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).
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
13 * Our hardware connections are as follows:
19 uint8_t ledpwm_re = 0xff, ledpwm_gr = 0xff, ledpwm_bl = 0xff;
20 uint8_t ledpwm_bri = 128;
22 void ledpwm_init(void)
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. */
37 /* Default brightness: PWM 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. */
50 /* Default brightness: PWM 0 */
55 /* In none-phase-correct PWM mode, This function does some mapping of
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.
65 void ledpwm_setled(uint8_t led, uint8_t val)
67 #if (PHASECORRECTPWM == 1)
69 case LEDPWM_REDLED: OCR0A = val; break;
70 case LEDPWM_GREENLED: OCR0B = val; break;
71 case LEDPWM_BLUELED: OCR2B = val; break;
73 #else /* not PHASECORRECTPWM */
76 case LEDPWM_REDLED: DDRD &= (uint8_t)~_BV(6);
78 case LEDPWM_GREENLED: DDRD &= (uint8_t)~_BV(5);
80 case LEDPWM_BLUELED: DDRD &= (uint8_t)~_BV(3);
89 case LEDPWM_REDLED: DDRD |= _BV(6);
92 case LEDPWM_GREENLED: DDRD |= _BV(5);
95 case LEDPWM_BLUELED: DDRD |= _BV(3);
100 #endif /* PHASECORRECTPWM */
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));