diff options
-rw-r--r-- | pwm.c | 100 | ||||
-rw-r--r-- | pwm.h | 9 |
2 files changed, 55 insertions, 54 deletions
@@ -7,21 +7,32 @@ #include <avr/interrupt.h> #include <stdbool.h> #include <stdlib.h> +#include <string.h> #include "speaker.h" #include "pwm.h" -/* max count for blinks */ -static uint8_t blink[6]; -static uint8_t comphit = 0; -static uint8_t state = 0; -/* PORTB and PORTB values */ -static uint8_t val[2]; -static uint8_t init[2]; +static uint8_t count = 0; +static uint8_t toggle[PWM_MAX_BRIGHTNESS][2]; +/* led bitfield, indicating which ones are leds */ +static const uint8_t bits[2] = {(1 << PB6) | (1 << PB7), + (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5)}; -static void ledOff () { - PORTB = PORTB & ~((1 << PB6) | (1 << PB7)); - PORTD = PORTD & ~((1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5)); +static void allLedsOff () { + PORTB &= ~bits[0]; + PORTD &= ~bits[1]; +} + +ISR(TIMER0_COMPA_vect) { + /* the 16th+ state is always ignored/force-off */ + if (count >= PWM_MAX_BRIGHTNESS-1) { + allLedsOff (); + } else { + PORTB ^= toggle[count][0]; + PORTD ^= toggle[count][1]; + } + /* 16 steps */ + count = (count+1) & (PWM_MAX_BRIGHTNESS-1); } static uint8_t ledToArray (const uint8_t i) { @@ -39,49 +50,27 @@ static uint8_t ledToShift (const uint8_t i) { return shifts[i]; } -/* All LEDs are off for state % 2 == 0 (off state) or state >= 7 (end of blink - * sequence), setting blink[i] = state*2 causes LED i to blink state times - */ -ISR(TIMER0_COMPA_vect) { - ++comphit; - /* divide by 13 to get ~10 Hz timer */ - if (comphit >= 13) { - comphit = 0; - ++state; - if (state == 12) { - state = 0; - } - val[0] = init[0]; - val[1] = init[1]; - if (state >= 10 || state % 2 == 0) { - /* end of blink/off state */ - } else { - for (uint8_t i = 0; i < PWM_LED_COUNT; i++) { - if (state < blink[i]) { - val[ledToArray (i)] |= (1 << ledToShift(i)); - } - } - } - } - - if (comphit % 2 == 0) { - ledOff (); +#if 0 +static void ledOff (const uint8_t i) { + assert (i < PWM_LED_COUNT); + if (ledToArray (i) == 0) { + PORTB = PORTB & ~(1 << ledToShift (i)); } else { - PORTB |= val[0]; - PORTD |= val[1]; + PORTD = PORTD & ~(1 << ledToShift (i)); } } +#endif void pwmInit () { /* set led1,led2 to output */ DDRB |= (1 << PB6) | (1 << PB7); /* set led3,led4,led5,led6 to output */ DDRD |= (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5); + memset (toggle, 0, sizeof (toggle)); } void pwmStart () { - comphit = 0; - state = 0; + count = 0; /* reset timer value */ TCNT0 = 0; /* set ctc timer0 (part 1) */ @@ -90,24 +79,35 @@ void pwmStart () { TIMSK0 = (1 << OCIE0A); /* compare value */ OCR0A = 255; - /* io clock with prescaler 256; ctc (part 2) */ - TCCR0B = (1 << CS02) | (0 << CS01) | (0 << CS00); + /* io clock with prescaler 64; ctc (part 2) */ + TCCR0B = (0 << CS02) | (1 << CS01) | (1 << CS00); } void pwmStop () { /* zero clock source */ TCCR0B = 0; - ledOff (); + allLedsOff (); } -void pwmSetBlink (const uint8_t i, const uint8_t value) { +/* Set LED brightness + * + * We could switch off interrupts here. Instead use pwmStart/Stop. + */ +void pwmSet (const uint8_t i, const uint8_t value) { assert (i < PWM_LED_COUNT); - if (value == PWM_BLINK_ON) { - /* permanently switch on LED */ - init[ledToArray (i)] |= (1 << ledToShift (i)); + const uint8_t array = ledToArray (i); + const uint8_t bit = 1 << ledToShift (i); + /* disable all toggles */ + for (uint8_t j = 0; j < PWM_MAX_BRIGHTNESS; j++) { + toggle[j][array] &= ~bit; + } + uint8_t toggleat; + if (value < PWM_MAX_BRIGHTNESS) { + toggleat = PWM_MAX_BRIGHTNESS-value; } else { - init[ledToArray (i)] &= ~(1 << ledToShift (i)); - blink[i] = value*2; + /* max brightness */ + toggleat = 0; } + toggle[toggleat][array] |= bit; } @@ -5,13 +5,14 @@ void pwmInit (); void pwmStart (); void pwmStop (); -void pwmSetBlink (const uint8_t, const uint8_t); +void pwmSet (const uint8_t, const uint8_t); -/* LED on (no blink) */ -#define PWM_BLINK_ON UINT8_MAX +/* LED on (max brightness) */ +#define PWM_ON UINT8_MAX /* LED off */ -#define PWM_BLINK_OFF 0 +#define PWM_OFF 0 #define PWM_LED_COUNT 6 +#define PWM_MAX_BRIGHTNESS 8 #endif /* PWM_H */ |