b9ef73cb8dcc15e83c03ad71da83034a2d703ba6
[moodlight.git] / ledpwm.c
1 /* $Id: ledpwm.c,v 1.3 2010/07/10 07:34:51 simimeie Exp $
2  * Functions for led brightness control via PWM (pulse width modulation).
3  */
4
5 #include <avr/io.h>
6 #include "ledpwm.h"
7
8 /* Select between Phase correct PWM and Fast PWM mode.
9  * setting this to 1 selects phase correct mode, everything else is Fast PWM. */
10 #define PHASECORRECTPWM 1
11
12 /*
13  * Our hardware connections are as follows:
14  *  Red -> PD6 / OC0A
15  *  Green -> PD5 / OC0B
16  *  Blue -> PD3 / OC2B
17  */
18
19 uint8_t ledpwm_re = 0xff, ledpwm_gr = 0xff, ledpwm_bl = 0xff;
20 uint8_t ledpwm_bri = 128;
21
22 void ledpwm_init(void)
23 {
24   /* Set OC2B, OC0A and OC0B to output */
25   DDRD |= _BV(3) | _BV(5) | _BV(6);
26   /* Set compare output mode for OC2B in timer counter control register: */
27 #if (PHASECORRECTPWM == 1)
28   /* select phase correct PWM mode (1). WGM2 bit is 0 so we don't need to touch TCCR2B. */
29   TCCR2A |= _BV(COM2B1) | _BV(WGM20);
30 #else  /* not PHASECORRECTPWM */
31   /* set output at BOTTOM (=0), clear it on compare match.
32    * select fast PWM mode 3. WGM2 bit is 0 so we don't need to touch TCCR2B. */
33   TCCR2A |= _BV(COM2B1) | _BV(WGM20) /*| _BV(WGM21)*/;
34 #endif /* PHASECORRECTPWM */
35   /* select clock source: cpu clock without prescaler. */
36   TCCR2B |= _BV(CS20);
37   /* Default brightness: PWM 0 */
38   OCR2B = 0;
39   /* Set compare output mode for OC0A and OC0B in timer counter control register: */
40 #if (PHASECORRECTPWM == 1)
41   /* select phase correct PWM mode (1). WGM2 bit is 0 so we don't need to touch TCCR0B. */
42   TCCR0A |= _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
43 #else  /* not PHASECORRECTPWM */
44   /* set output at BOTTOM (=0), clear it on compare match.
45    * select fast PWM mode 3. WGM2 bit is 0 so we don't need to touch TCCR0B. */
46   TCCR0A |= _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00) | _BV(WGM01);
47 #endif /* PHASECORRECTPWM */
48   /* select clock source: i/o clock without prescaler. */
49   TCCR0B |= _BV(CS20);
50   /* Default brightness: PWM 0 */
51   OCR0A = 0;
52   OCR0B = 0;
53 }
54
55 /* In none-phase-correct PWM mode, This function does some mapping of
56  * the values:
57  * 0 really turns the LED off.
58  * 1 is an PWM value of 0, which still lets the LED glimmer.
59  * 2 to 254 are mapped to PWM 3 to 253 (always one less!)
60  * 255 is mapped to PWM 255.
61  * So there is no way to set PWM 254, but you cannot visually see the
62  * difference to 253 or 255 anyways...
63  * In phase-correct PWM mode there does not need to be a mapping, 0 means off.
64  */
65 void ledpwm_setled(uint8_t led, uint8_t val)
66 {
67 #if (PHASECORRECTPWM == 1)
68   switch (led) {
69   case LEDPWM_REDLED:   OCR0A = val; break;
70   case LEDPWM_GREENLED: OCR0B = val; break;
71   case LEDPWM_BLUELED:  OCR2B = val; break;
72   };
73 #else /* not PHASECORRECTPWM */
74   if (val == 0) {
75     switch (led) {
76     case LEDPWM_REDLED:   DDRD &= (uint8_t)~_BV(6);
77                           break;
78     case LEDPWM_GREENLED: DDRD &= (uint8_t)~_BV(5);
79                           break;
80     case LEDPWM_BLUELED:  DDRD &= (uint8_t)~_BV(3);
81                           break;
82     };
83   } else {
84     val -= 1;
85     if (val == 254) {
86       val = 255;
87     }
88     switch (led) {
89     case LEDPWM_REDLED:   DDRD |= _BV(6);
90                           OCR0A = val;
91                           break;
92     case LEDPWM_GREENLED: DDRD |= _BV(5);
93                           OCR0B = val;
94                           break;
95     case LEDPWM_BLUELED:  DDRD |= _BV(3);
96                           OCR2B = val;
97                           break;
98     };
99   }
100 #endif /* PHASECORRECTPWM */
101 }
102
103 void ledpwm_set(uint8_t red, uint8_t green, uint8_t blue, uint8_t br) {
104   ledpwm_setled(LEDPWM_REDLED,  (((uint16_t)red   * br) / 255));
105   ledpwm_setled(LEDPWM_GREENLED,(((uint16_t)green * br) / 255));
106   ledpwm_setled(LEDPWM_BLUELED, (((uint16_t)blue  * br) / 255));
107 }
This page took 0.049952 seconds and 3 git commands to generate.