diff options
| author | Sarah Wilson <sarah@swilson.id.au> | 2025-01-10 20:09:05 +1100 |
|---|---|---|
| committer | Sarah Wilson <sarah@swilson.id.au> | 2025-01-10 20:09:05 +1100 |
| commit | d915fd32a7becdf0f0492960fa5b241ee407aee9 (patch) | |
| tree | ef136c9eb89883801f71aaa087f1c4b606213af2 /main.c | |
Diffstat (limited to 'main.c')
| -rw-r--r-- | main.c | 182 |
1 files changed, 182 insertions, 0 deletions
@@ -0,0 +1,182 @@ +#include <stdint.h> + +#include <avr/interrupt.h> +#include <avr/io.h> +#include <avr/sleep.h> + +#define max(a, b) \ + ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a > _b ? _a : _b; \ + }) + +#define min(a, b) \ + ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a < _b ? _a : _b; \ + }) + +// return a + (t/128)*(b-a) +static uint8_t lerp(uint8_t a, uint8_t b, uint8_t t) +{ + return a + (uint8_t)(((int16_t)(b - a) * t) >> 7); +} + +static void eeprom_write(uint16_t addr, uint8_t data) +{ + while (EECR & _BV(EEPE)) + ; + EEAR = addr; + EECR = 0; + EEDR = data; + EECR |= _BV(EEMPE); + EECR |= _BV(EEPE); +} + +static uint8_t eeprom_read(uint16_t addr) +{ + while (EECR & _BV(EEPE)) + ; + EEAR = addr; + EECR = _BV(EERE); + return EEDR; +} + +enum { + MODE_SOLID = 0, + MODE_PULSE, + MODE_ALTERNATE, + MODE_FAST_PULSE, + MODE_FAST_ALTERNATE, + MODE_VFAST_PULSE, + MODE_VFAST_ALTERNATE, + NUM_MODE, +}; + +uint16_t tickcount; +static void tick(void); + +ISR(TIM0_COMPA_vect) +{ + ++tickcount; + tick(); +} + +static uint8_t mode; +ISR(PCINT0_vect) +{ + static uint16_t down; + + if ((PINB & _BV(PB0)) == 0) { + down = tickcount; + } else { + if (tickcount - down > 100) { + eeprom_write(0, mode); + } else { + if (++mode == NUM_MODE) { + mode = MODE_SOLID; + } + } + } +} + +static uint8_t brightness; +ISR(ADC_vect) +{ + brightness = ADCH; +} + +static uint8_t oa_duty, ob_duty; +ISR(TIM1_OVF_vect) +{ + OCR1A = min(oa_duty, 127); + OCR1B = max(255 - ob_duty, 128); +} + +void tick(void) +{ + ADCSRA |= _BV(ADSC); + + switch (mode) { + case MODE_SOLID: + oa_duty = ob_duty = brightness >> 1; + break; + case MODE_PULSE: + case MODE_ALTERNATE: + case MODE_FAST_PULSE: + case MODE_FAST_ALTERNATE: + case MODE_VFAST_PULSE: + case MODE_VFAST_ALTERNATE: { + static uint8_t dir; + static uint8_t t; + + oa_duty = lerp(0, brightness >> 1, dir ? t : 128 - t); + ob_duty = (mode & 1) ? oa_duty : ((brightness >> 1) - oa_duty); + t += mode > MODE_FAST_ALTERNATE ? 4 : + mode > MODE_ALTERNATE ? 2 : + 1; + if (t >= 128) { + t = 0; + dir = !dir; + } + } break; + } +} + +static void pwm_init(void) +{ + TCCR1 = _BV(PWM1A) | _BV(COM1A1); + GTCCR |= _BV(PWM1B) | _BV(COM1B1) | _BV(COM1B0); + + TCCR1 |= _BV(CS12); + + OCR1A = 0; + OCR1B = 255; + + DDRB |= _BV(PB1) | _BV(PB4); + + TIMSK |= _BV(TOIE1); +} + +static void adc_init(void) +{ + ADMUX = _BV(ADLAR) | _BV(MUX0) | _BV(MUX1); + DIDR0 = _BV(ADC3D); + ADCSRA = _BV(ADEN) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1); +} + +static void tick_init(void) +{ + GTCCR = _BV(TSM) | _BV(PSR0); + TCCR0A = _BV(WGM01); + TCCR0B = _BV(CS01) | _BV(CS00); + OCR0A = 122; // 1M/64 = 15kHz / 122 = 128 hz tick + TIMSK |= _BV(OCIE0A); + GTCCR &= _BV(TSM); +} + +int main(void) +{ + mode = eeprom_read(0); + if (mode >= NUM_MODE) { + mode = 0; + } + + tick_init(); + pwm_init(); + adc_init(); + + DDRB &= ~_BV(PB0); + PORTB |= _BV(PB0); + GIMSK = _BV(PCIE); + PCMSK = _BV(PCINT0); + + sei(); + + for (;;) + sleep_mode(); + + return (0); +} |
