4307b86a |
1 | /* $Id: ledpwm.c,v 1.4 2010/07/25 20:40:44 simimeie Exp $ |
17aea8ef |
2 | * Functions for led brightness control via PWM (pulse width modulation). |
3 | */ |
4 | |
5 | #include <avr/io.h> |
4307b86a |
6 | #include <avr/interrupt.h> |
17aea8ef |
7 | #include "ledpwm.h" |
8 | |
17aea8ef |
9 | /* |
4307b86a |
10 | * Our hardware connections on the first prototype are as follows: |
11 | * Red -> PD6 (OC0A) |
12 | * Green -> PD5 (OC0B) |
13 | * Blue -> PD3 (OC2B) CHANGED umgeloetet durch Julian jetzt PD7 |
14 | * In the next hardware revision this will be: |
15 | * Red -> PC3 |
16 | * Green -> PC2 |
17 | * Blue -> PC1 |
17aea8ef |
18 | */ |
ddf1553f |
19 | |
4307b86a |
20 | #define LEDPORT PORTD |
21 | #define LEDDDR DDRD |
22 | #define LEDPINR 6 |
23 | #define LEDPING 5 |
24 | #define LEDPINB 7 |
25 | |
ddf1553f |
26 | uint8_t ledpwm_re = 0xff, ledpwm_gr = 0xff, ledpwm_bl = 0xff; |
27 | uint8_t ledpwm_bri = 128; |
4307b86a |
28 | /* Internal */ |
29 | volatile uint16_t ledpwm_val[3] = { 0x8000, 0x8000, 0x8000 }; |
30 | volatile uint16_t ledpwm_curoreg = 0; |
ddf1553f |
31 | |
4307b86a |
32 | /* To do a 16-bit write, the high byte must be written before the low byte. |
33 | * For a 16-bit read, the low byte must be read before the high byte */ |
34 | static void ledpwm_programnextstep(void) { |
35 | uint16_t nextval = 0xffff; |
36 | uint8_t i; |
37 | for (i = 0; i < 3; i++) { |
38 | if ((ledpwm_val[i] > ledpwm_curoreg) && (ledpwm_val[i] <= nextval)) { |
39 | nextval = ledpwm_val[i]; |
40 | } |
41 | } |
42 | OCR1AH = nextval >> 8; |
43 | OCR1AL = nextval & 0xff; |
44 | ledpwm_curoreg = nextval; |
17aea8ef |
45 | } |
46 | |
4307b86a |
47 | /* This gets called from timers.c which holds the 'main' (interrupt) |
48 | * handler for the timer1 overflow. */ |
49 | void ledpwm_TIMER1OVF_hook(void) { |
50 | /* Turn on all LEDs */ |
51 | if (ledpwm_val[LEDPWM_REDLED] > 0) { |
52 | LEDPORT |= _BV(LEDPINR); |
53 | } |
54 | if (ledpwm_val[LEDPWM_GREENLED] > 0) { |
55 | LEDPORT |= _BV(LEDPING); |
56 | } |
57 | if (ledpwm_val[LEDPWM_BLUELED] > 0) { |
58 | LEDPORT |= _BV(LEDPINB); |
59 | } |
60 | ledpwm_curoreg = 0; |
61 | ledpwm_programnextstep(); |
62 | } |
63 | |
64 | /* Called on compare match */ |
65 | ISR(TIMER1_COMPA_vect) |
17aea8ef |
66 | { |
4307b86a |
67 | if (ledpwm_val[LEDPWM_REDLED] <= ledpwm_curoreg) { |
68 | LEDPORT &= (uint8_t)~_BV(LEDPINR); |
69 | } |
70 | if (ledpwm_val[LEDPWM_GREENLED] <= ledpwm_curoreg) { |
71 | LEDPORT &= (uint8_t)~_BV(LEDPING); |
72 | } |
73 | if (ledpwm_val[LEDPWM_BLUELED] <= ledpwm_curoreg) { |
74 | LEDPORT &= (uint8_t)~_BV(LEDPINB); |
17aea8ef |
75 | } |
4307b86a |
76 | ledpwm_programnextstep(); |
77 | } |
78 | |
79 | void ledpwm_init(void) { |
80 | /* Set our Port Pins to output */ |
81 | LEDDDR |= _BV(LEDPINR) | _BV(LEDPING) | _BV(LEDPINB); |
82 | /* DO NOT initialize TIMER1 frequency and overflow interrupt. |
83 | * timers.c already does that. */ |
84 | /* Enable TIMER1 output compare interrupt A */ |
85 | TIMSK1 |= _BV(OCIE1A); |
86 | ledpwm_programnextstep(); |
87 | } |
88 | |
89 | void ledpwm_setled(uint8_t led, uint16_t val) { |
90 | if (led > 2) { return; /* ignore invalid values */ } |
91 | ledpwm_val[led] = val; |
92 | ledpwm_programnextstep(); |
17aea8ef |
93 | } |
de0e300b |
94 | |
95 | void ledpwm_set(uint8_t red, uint8_t green, uint8_t blue, uint8_t br) { |
4307b86a |
96 | ledpwm_val[LEDPWM_REDLED] = red * br; |
97 | ledpwm_val[LEDPWM_GREENLED] = green * br; |
98 | ledpwm_val[LEDPWM_BLUELED] = blue * br; |
99 | ledpwm_programnextstep(); |
de0e300b |
100 | } |