- add LED control with PWM
[moodlight.git] / ledpwm.c
CommitLineData
17aea8ef 1/* $Id: ledpwm.c,v 1.1 2010/06/26 19:08:18 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 * Our hardware connections are as follows:
13 * Red -> PD6 / OC0A
14 * Green -> PD5 / OC0B
15 * Blue -> PD3 / OC2B
16 */
17void ledpwm_init(void)
18{
19 /* Set OC2B, OC0A and OC0B to output */
20 DDRD |= _BV(PD3) | _BV(PD5) | _BV(PD6);
21 /* Set compare output mode for OC2B in timer counter control register: */
22#if (PHASECORRECTPWM == 1)
23 /* select phase correct PWM mode (1). WGM2 bit is 0 so we don't need to touch TCCR2B. */
24 TCCR2A |= _BV(COM2B1) | _BV(WGM20);
25#else /* not PHASECORRECTPWM */
26 /* set output at BOTTOM (=0), clear it on compare match.
27 * select fast PWM mode 3. WGM2 bit is 0 so we don't need to touch TCCR2B. */
28 TCCR2A |= _BV(COM2B1) | _BV(WGM20) /*| _BV(WGM21)*/;
29#endif /* PHASECORRECTPWM */
30 /* select clock source: cpu clock without prescaler. */
31 TCCR2B |= _BV(CS20);
32 /* Default brightness: PWM 0 */
33 OCR2B = 0;
34 /* Set compare output mode for OC0A and OC0B in timer counter control register: */
35#if (PHASECORRECTPWM == 1)
36 /* select phase correct PWM mode (1). WGM2 bit is 0 so we don't need to touch TCCR0B. */
37 TCCR0A |= _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
38#else /* not PHASECORRECTPWM */
39 /* set output at BOTTOM (=0), clear it on compare match.
40 * select fast PWM mode 3. WGM2 bit is 0 so we don't need to touch TCCR0B. */
41 TCCR0A |= _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00) | _BV(WGM01);
42#endif /* PHASECORRECTPWM */
43 /* select clock source: i/o clock without prescaler. */
44 TCCR0B |= _BV(CS20);
45 /* Default brightness: PWM 0 */
46 OCR0A = 0;
47 OCR0B = 0;
48}
49
50/* In none-phase-correct PWM mode, This function does some mapping of
51 * the values:
52 * 0 really turns the LED off.
53 * 1 is an PWM value of 0, which still lets the LED glimmer.
54 * 2 to 254 are mapped to PWM 3 to 253 (always one less!)
55 * 255 is mapped to PWM 255.
56 * So there is no way to set PWM 254, but you cannot visually see the
57 * difference to 253 or 255 anyways...
58 * In phase-correct PWM mode there does not need to be a mapping, 0 means off.
59 */
60void ledpwm_setled(uint8_t led, uint8_t val)
61{
62#if (PHASECORRECTPWM == 1)
63 switch (led) {
64 case LEDPWM_REDLED: OCR0A = val; break;
65 case LEDPWM_GREENLED: OCR0B = val; break;
66 case LEDPWM_BLUELED: OCR2B = val; break;
67 };
68#else /* not PHASECORRECTPWM */
69 if (val == 0) {
70 switch (led) {
71 case LEDPWM_REDLED: DDRD &= (uint8_t)~_BV(PD6);
72 break;
73 case LEDPWM_GREENLED: DDRD &= (uint8_t)~_BV(PD5);
74 break;
75 case LEDPWM_BLUELED: DDRD &= (uint8_t)~_BV(PD3);
76 break;
77 };
78 } else {
79 val -= 1;
80 if (val == 254) {
81 val = 255;
82 }
83 switch (led) {
84 case LEDPWM_REDLED: DDRD |= _BV(PD6);
85 OCR0A = val;
86 break;
87 case LEDPWM_GREENLED: DDRD |= _BV(PD5);
88 OCR0B = val;
89 break;
90 case LEDPWM_BLUELED: DDRD |= _BV(PD3);
91 OCR2B = val;
92 break;
93 };
94 }
95#endif /* PHASECORRECTPWM */
96}
This page took 0.056799 seconds and 4 git commands to generate.