summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..5c8bc76
--- /dev/null
+++ b/main.c
@@ -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);
+}