From 4b93ea55987c25fcce022403a505ca1749dc329c Mon Sep 17 00:00:00 2001 From: "Jan \"Yenya\" Kasprzak" Date: Tue, 28 Aug 2012 15:25:01 +0200 Subject: [PATCH] lights.c split into more modules --- Makefile | 11 +-- adc.c | 79 ++++++++++++++++ lights.c | 273 ------------------------------------------------------ lights.h | 45 +++++++++ logging.c | 53 +++++++++++ main.c | 36 +++++++ pattern.c | 54 +++++++++++ pwm.c | 72 ++++++++++++++ pwmled.c | 180 +++++++++++++++++++++++++++++++++++ tmr.c | 25 +++++ 10 files changed, 549 insertions(+), 279 deletions(-) create mode 100644 adc.c delete mode 100644 lights.c create mode 100644 lights.h create mode 100644 logging.c create mode 100644 main.c create mode 100644 pattern.c create mode 100644 pwm.c create mode 100644 pwmled.c create mode 100644 tmr.c diff --git a/Makefile b/Makefile index 99b9793..989bffb 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,15 @@ - PROGRAM=lights -SRC=lights.c +SRC=main.c logging.c adc.c pwm.c tmr.c pwmled.c OBJ=$(SRC:.c=.o) + MCU=attiny861a # AVRDUDE_MCU=$(MCU) AVRDUDE_MCU=attiny861 AVRDUDE_PROGRAMMER=usbasp -CFLAGS=-Os -mmcu=$(MCU) +CFLAGS=-Wall -Os -mmcu=$(MCU) -DUSE_LOGGING=1 -DF_CPU=1000000UL LDFLAGS= AVRDUDE_FLAGS= -p$(AVRDUDE_MCU) -c $(AVRDUDE_PROGRAMMER) @@ -38,7 +38,6 @@ dump_eeprom: objdump: $(PROGRAM).elf $(OBJDUMP) --disassemble $< - .PRECIOUS : $(OBJ) $(PROGRAM).elf %.hex: %.elf @@ -51,10 +50,10 @@ objdump: $(PROGRAM).elf %.elf: $(OBJ) $(CC) $(CFLAGS) $(OBJ) -o $@ $(LDFLAGS) -%.o: %.c +%.o: %.c lights.h Makefile $(CC) -c $(CFLAGS) $< -o $@ -%.s: %.c +%.s: %.c lights.h Makefile $(CC) -S -c $(CFLAGS) $< -o $@ %.o: %.S diff --git a/adc.c b/adc.c new file mode 100644 index 0000000..a37e958 --- /dev/null +++ b/adc.c @@ -0,0 +1,79 @@ +#include +#include + +#include "lights.h" + +static unsigned char adc_mux[] = { // pwmleds should be first + // 0: pwmled 0: 1.1V, ADC3 (PA4), single-ended + _BV(REFS1) | _BV(MUX1) | _BV(MUX0), + // 1: pwmled 1: 1.1V, ADC0,1 (PA0,1), gain 1 or 8 + _BV(REFS1) | _BV(MUX3) | _BV(MUX2), + // 2: pwmled 2: 1.1V, ADC2,1 (PA2,1), gain 1 or 8 + _BV(REFS1) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0), + // 3: ambient light: 1.1V, ADC4 (PA5), single-ended + _BV(REFS1) | _BV(MUX2), + // 4: batt voltage: 1.1V, ADC5 (PA6), single-ended + _BV(REFS1) | _BV(MUX2) | _BV(MUX0), +}; + +#define LAST_ADC (sizeof(adc_mux)/sizeof(char)) +volatile static unsigned char current_adc = LAST_ADC; + +static void start_next_adc() +{ + while (current_adc > 0) { + --current_adc; + + // test if current_adc should be measured + if (current_adc < N_PWMLEDS && pwmled_is_on(current_adc)) + goto found; + // TODO ambient light, battery sense, etc. + } + + // all ADCs have been handled + current_adc = LAST_ADC; + return; +found: + // ADCSRB |= _BV(GSEL); // gain 8 or 32 + ADMUX = adc_mux[current_adc]; // set up mux, start one-shot conversion + ADCSRA |= _BV(ADSC); +} + +void init_adc() +{ + ADCSRA = _BV(ADEN) // enable + | _BV(ADPS1) | _BV(ADPS0) // CLK/8 = 125 kHz + // | _BV(ADPS2) // CLK/16 = 62.5 kHz + ; + ADCSRB |= _BV(GSEL); // gain 8 or 32 + + // Disable digital input on all bits used by ADC + DIDR0 = _BV(ADC0D) | _BV(ADC1D) | _BV(ADC2D) | _BV(ADC3D) + | _BV(ADC4D) | _BV(ADC5D); + + ADCSRA |= _BV(ADSC); + + /* Do first conversion and drop the result */ + while ((ADCSRA & _BV(ADIF)) == 0) + ; + ADCSRA |= _BV(ADIF); // clear the IRQ flag + + ADCSRA |= _BV(ADIE); // enable IRQ +} + +ISR(ADC_vect) { // IRQ handler + uint16_t adcval = ADCW; + + if (current_adc < N_PWMLEDS) + pwmled_adc(current_adc, adcval); + // TODO ambient light, battery sense, etc. + + start_next_adc(); +} + +void timer_start_adcs() +{ + if (current_adc == LAST_ADC) // Don't start if in progress + start_next_adc(); +} + diff --git a/lights.c b/lights.c deleted file mode 100644 index d05fa1c..0000000 --- a/lights.c +++ /dev/null @@ -1,273 +0,0 @@ -#include -#include -#include -#include -#include - -volatile uint16_t adcval; -unsigned char led_is_on = 0; -volatile unsigned char adccount = 0; - -typedef struct { - unsigned char pwmval, expected; -} led_level_t; - -led_level_t led_modes[2] = { - { 0x50, 0x38 }, - { 0x38, 0x04 }, -}; - -unsigned char led_mode = 0; -unsigned char led_mode_changed = 0; - -static void inline led_on() -{ - DDRB |= _BV( PB5 ); - PORTA |= _BV( PA0 ); - led_is_on = 1; -} - -static void inline led_off() -{ - led_is_on = 0; - DDRB &= ~_BV( PB5 ); - PORTA &=~ _BV( PA0 ); -// ADCSRA &= ~(_BV(ADIE) | _BV(ADIF)); -} - -/* ------------ Logging/Debugging ----------- */ - -unsigned char debug_state EEMEM; - -static void inline debug_setstate(unsigned char val) -{ - eeprom_write_byte(&debug_state, val); -} - -#define LOG_BUFFER 64 -uint16_t log_buffer[LOG_BUFFER] EEMEM; -unsigned char log_buffer_count; -uint16_t log_buffer2[LOG_BUFFER]; -volatile unsigned char stop = 0; - -static void inline init_log() -{ - debug_setstate(1); - log_buffer_count = 0; -} - -static void log_word(uint16_t word) { - if (log_buffer_count >= LOG_BUFFER) - return; - - // eeprom_write_word(&log_buffer[log_buffer_count], word); - log_buffer2[log_buffer_count] = word; - log_buffer_count++; - - if (log_buffer_count == LOG_BUFFER) { - unsigned char i; - for (i=0; i < LOG_BUFFER; i++) { - eeprom_write_word(&log_buffer[i], - log_buffer2[i]); - } - debug_setstate(0x42); - } -} - -/* ------------ Timer ----------- */ - -volatile uint16_t jiffies = 0; - -static void inline init_tmr() -{ - TCCR0A = _BV(WGM00); - TCCR0B = _BV(CS02) | _BV(CS00); // 1 kHz - OCR0A = 12; // 100 Hz - TIMSK |= _BV(OCIE0A); - DDRA |= _BV( PA0 ); - - jiffies = 0; -} - -static void inline tmr_handler() -{ - unsigned char c = jiffies & 0x0F; - unsigned char c1 = jiffies & 0x7F; - - ++jiffies; - -#if 0 - if (c == 1) - led_on(); - - if (c == 9) - led_off(); -#endif - - if (c == 0x02 || c == 0x08) - led_on(); - - if (c == 0x05 || c == 0x0b) - led_off(); - -#if 1 - if (c1 == 0x10) { - led_mode = 0; - led_mode_changed = 1; - OCR1D = led_modes[led_mode].pwmval; - } else if (c1 == 0x70) { - led_mode = 1; - led_mode_changed = 1; - OCR1D = led_modes[led_mode].pwmval; - } -#endif - - ADCSRA |= _BV(ADSC); -#if 0 - if (led_is_on && adcval != 0xFFEE) { - adcval = 0xFFEE; - - ADCSRA |= _BV(ADIF) | _BV(ADIE) | _BV(ADSC); - } -#endif -} - -ISR(TIMER0_COMPA_vect) -{ - tmr_handler(); -} - -/* ------------ PWM ----------- */ - -static void inline init_pwm() -{ - /* Async clock */ - PLLCSR = _BV(LSM) | _BV(PLLE); - _delay_ms(1); - while (PLLCSR & _BV(PLOCK) == 0) - ; - PLLCSR |= _BV(PCKE); - - TCCR1C = _BV(COM1D0) | _BV(COM1D1) | _BV(PWM1D); - TCCR1A = _BV(COM1A0) | _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(PWM1A) | _BV(PWM1B); - // TCCR1B = 0x80| _BV(CS13) | _BV(CS11); - TCCR1B = _BV(7) // PWM1X: PWM inversion mode - | _BV(CS10) // no clock prescaling - ; - OCR1C = 0xFF; // TOP value - OCR1D = OCR1B = OCR1A = 0; - // OCR1D = 0; - DDRB |= _BV( PB5 ); - PORTB &= ~(_BV( PB5 ) | _BV( PB1 ) | _BV( PB3 )); - - // led_off(); - // TIMSK |= _BV(TOIE1); -} - -#if 0 -static void inline pwm_handler() -{ - // TIMSK &= ~_BV(TOIE1); - // OCR1D = pwmval; -} - -ISR(TIMER1_OVF_vect) -{ - pwm_handler(); -} -#endif - -/* ------------ A/D Converter ----------- */ - -static void inline init_adc() -{ - ADCSRA = _BV(ADEN) // enable - | _BV(ADPS1) | _BV(ADPS0) // CLK/8 = 125 kHz - // | _BV(ADPS2) // CLK/16 = 62.5 kHz - ; - ADMUX = _BV(REFS1) // 1.1V internal reference - | _BV(MUX4)|_BV(MUX3) // port ADC5-6, gain 1 - ; - // ADCSRB = _BV(REFS2); - ADCSRB |= _BV(GSEL); - // Disable digital input on all bits used by ADC - DIDR0 = _BV(ADC5D)|_BV(ADC6D) | _BV(AREFD); - ADCSRA |= _BV(ADIE); -} - -static void inline adc_handler() -{ - uint16_t new_pwm = led_modes[led_mode].pwmval; - uint16_t old_pwm = new_pwm; - uint16_t adc_exp = led_modes[led_mode].expected; - - adcval = ADCW; - adccount++; - - // log_word(((adcval & 0x3FC) << 6) | pwmval); - - if (!led_is_on) - return; - - // ADCSRA &= ~(_BV(ADIE) | _BV(ADIF)); - - if (led_mode_changed) { - led_mode_changed = 0; - goto set_pwm; - } - - log_word(((adcval & 0xFF) << 8) | old_pwm); - - if (2*adcval > 5*adc_exp) { // >2.5x expected, lower significantly - new_pwm = 2*old_pwm/3; - } else if (3*adcval > 4*adc_exp) { // >1.33x expected, lower a bit - new_pwm = old_pwm - 1; - } else if (4*adcval < 3*adc_exp) { // 0.75x expected, raise a bit - new_pwm = old_pwm + 1; - } - - if (new_pwm > 0x60) { // odpojeno? - new_pwm = 0x60; - } - if (new_pwm < 2) { // zkrat? - new_pwm = 2; - } - -set_pwm: - if (new_pwm != old_pwm) { - led_modes[led_mode].pwmval = new_pwm; - OCR1D = new_pwm; - } - // ADCSRA |= _BV(ADSC); -} - -ISR(ADC_vect) -{ - adc_handler(); -} - -int main(void) -{ - _delay_ms(1500); - init_log(); - - init_pwm(); - init_adc(); - init_tmr(); - - led_on(); - debug_setstate(3); - - sei(); - while (1) - ; // sleep_mode(); - -#if 0 - while (1) { - PORTA |= _BV( PA0 ); - _delay_ms(200); - PORTA &=~ _BV( PA0 ); - _delay_ms(200); - } -#endif -} diff --git a/lights.h b/lights.h new file mode 100644 index 0000000..d6e0cbd --- /dev/null +++ b/lights.h @@ -0,0 +1,45 @@ +#ifndef LIGHTS_H__ +#define LIGHTS_H__ 1 + +#define N_LEDS 5 +#define N_PWMLEDS 3 +#define N_PWMLED_MODES 4 + +/* logging.c */ +#ifdef USE_LOGGING +void log_set_state(unsigned char val); +void log_init(); +void log_flush(); +void log_byte(unsigned char byte); +void log_word(uint16_t word); +#else +void inline log_set_state(unsigned char val) { } +void inline log_init() { } +void inline log_flush() { } +void inline log_byte(unsigned char byte) { } +void inline log_word(uint16_t word) { } +#endif + +/* adc.c */ +void init_adc(); +void timer_start_adcs(); + +/* pwm.c */ +void init_pwm(); +void pwm_on(unsigned char n); +void pwm_off(unsigned char n); +void pwm_set(unsigned char n, unsigned char stride); + +/* tmr.c */ +extern volatile uint16_t jiffies; +void init_tmr(); + +/* pwmled.c */ +void pwmled_init(); +void pwmled_adc(unsigned char n, uint16_t adcval); +void pwmled_set_mode(unsigned char n, unsigned char mode); +unsigned char pwmled_is_on(unsigned char n); + + +#endif /* !LIGHTS_H__ */ + diff --git a/logging.c b/logging.c new file mode 100644 index 0000000..04f9515 --- /dev/null +++ b/logging.c @@ -0,0 +1,53 @@ +#ifdef USE_LOGGING + +#include +#include + +#include "lights.h" + +#define LOG_BUFFER 128 +static unsigned char log_state EEMEM; +static unsigned char log_buffer_ee[LOG_BUFFER] EEMEM; +static unsigned char log_buffer_count; +static unsigned char log_buffer[LOG_BUFFER]; + +void log_set_state(unsigned char val) +{ + eeprom_write_byte(&log_state, val); +} + +void log_init() +{ + log_set_state(1); + log_buffer_count = 0; +} + +void log_byte(unsigned char byte) { + if (log_buffer_count >= LOG_BUFFER) + return; + + // eeprom_write_word(&log_buffer[log_buffer_count], word); + log_buffer[log_buffer_count++] = byte; + + if (log_buffer_count == LOG_BUFFER) + log_flush(); +} + +void log_word(uint16_t word) { + log_byte(word & 0xFF); + log_byte(word >> 8); +} + +void log_flush() { + unsigned char i; + + log_buffer_count = LOG_BUFFER; + for (i=0; i < LOG_BUFFER; i++) { + eeprom_write_byte(&log_buffer_ee[i], + log_buffer[i]); + } + log_set_state(0x42); +} + +#endif + diff --git a/main.c b/main.c new file mode 100644 index 0000000..324b884 --- /dev/null +++ b/main.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +#include "lights.h" + +int main(void) +{ + _delay_ms(1500); + log_init(); + + init_pwm(); + init_adc(); + init_tmr(); + + pwmled_init(); + + log_set_state(3); + + sei(); +#if 1 + while (1) + ; // sleep_mode(); +#endif + +#if 0 + DDRB |= _BV(PB2); + while (1) { + PORTB |= _BV( PB2 ); + _delay_ms(200); + PORTB &=~ _BV( PB2 ); + _delay_ms(200); + } +#endif +} diff --git a/pattern.c b/pattern.c new file mode 100644 index 0000000..386f9df --- /dev/null +++ b/pattern.c @@ -0,0 +1,54 @@ +#include "lights.h" + +typedef struct { + unsigned char mode: 3; + unsigned char duration: 5; +} pattern_t; + +static unsigned char led_counters[N_LEDS]; +static pattern_t *led_patterns[N_LEDS]; + +#define PATTERN_END { 0, 0 } +pattern_t off_pattern[] = { + { 0, 5 }, + PATTERN_END +}; + +pattern_t blink_pattern[] = { + { 1, 5 }, + { 0, 5 }, + PATTERN_END +}; + +void pattern_init() +{ + unsigned char i; + + for (i = 0; i < N_LEDS; i++) { + led_counters[i] = 0; + led_patterns[i] = off_pattern; + } +} + +void patterns_next_tick() +{ + unsigned char i; + + for (i = 0; i < N_LEDS; i++) { + if (led_counters[i] == 0) { + led_patterns[i]++; + if (led_patterns[i]->duration == 0) { // END + led_patterns[i] = pattern_select(i); + } + led_counters[i] = led_patterns[i]->duration; + if (led_patterns[i]->mode == 0) { + led_off(i); + } else { + led_set_level(i, led_patterns[i]->mode - 1); + } + } + + led_counters[i]--; + } +} + diff --git a/pwm.c b/pwm.c new file mode 100644 index 0000000..af4e4fa --- /dev/null +++ b/pwm.c @@ -0,0 +1,72 @@ +#include +#include +#include + +#include "lights.h" + +void init_pwm() +{ + /* Async clock */ + PLLCSR = _BV(LSM) | _BV(PLLE); + + /* Synchronize to the phase lock */ + _delay_ms(1); + while ((PLLCSR & _BV(PLOCK)) == 0) + ; + PLLCSR |= _BV(PCKE); + + TCCR1C = _BV(COM1D0) | _BV(COM1D1) | _BV(PWM1D); + TCCR1A = _BV(COM1A0) | _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(PWM1A) | _BV(PWM1B); + TCCR1B = _BV(7) // PWM1X: PWM inversion mode + | _BV(CS10) // no clock prescaling + ; + OCR1C = 0xFF; // TOP value + + OCR1D = OCR1B = OCR1A = 0; // initial stride is 0 + + DDRB &= ~(_BV( PB1 ) | _BV( PB3 ) | _BV( PB5 )); // tristate it + PORTB &= ~(_BV( PB1 ) | _BV( PB3 ) | _BV( PB5 )); // set to zero +} + +void pwm_on(unsigned char n) +{ + switch (n) { + case 0: DDRB |= _BV(PB1); break; + case 1: DDRB |= _BV(PB3); break; + case 2: DDRB |= _BV(PB5); break; + } +} + +void pwm_off(unsigned char n) +{ + switch (n) { + case 0: DDRB &= ~_BV(PB1); break; + case 1: DDRB &= ~_BV(PB3); break; + case 2: DDRB &= ~_BV(PB5); break; + } +} + +void pwm_set(unsigned char n, unsigned char stride) +{ + switch (n) { + case 0: OCR1A = stride; break; + case 1: OCR1B = stride; break; + case 2: OCR1D = stride; break; + } +} + +#if 0 +static void inline pwm_handler() +{ + OCR1A = pwmval[0]; + OCR1B = pwmval[1]; + OCR1D = pwmval[2]; + TIMSK &= ~_BV(TOIE1); +} + +ISR(TIMER1_OVF_vect) +{ + pwm_handler(); +} +#endif + diff --git a/pwmled.c b/pwmled.c new file mode 100644 index 0000000..4861793 --- /dev/null +++ b/pwmled.c @@ -0,0 +1,180 @@ +#include + +#include "lights.h" + +static unsigned char pwm_vals[N_PWMLEDS*N_PWMLED_MODES]; +static unsigned char adc_vals[N_PWMLEDS*N_PWMLED_MODES] = { + /* pwmled0 */ + 0x04, 0x14, 0x24, 0x38, + /* pwmled1 */ + 0x04, 0x14, 0x24, 0x38, + /* pwmled2 */ + 0x04, 0x14, 0x24, 0x38, +}; + +static unsigned char pwmled_state[N_PWMLEDS]; +#define ST_DISABLED 0 +#define ST_PROBING 1 +#define ST_OFF 2 +#define ST_ON 3 + +static unsigned char pwmled_mode[N_PWMLEDS]; + +static unsigned char pwm_probes[N_PWMLEDS]; + +static void start_probing(unsigned char n) +{ + pwmled_state[n] = ST_PROBING; + pwm_set(n, 0); + pwm_on(n); + pwm_probes[n] = 0; +} + +void pwmled_init() +{ + unsigned char i; + + for (i = 0; i < N_PWMLEDS*N_PWMLED_MODES; i++) + pwm_vals[i] = 0; + + for (i = 0; i < N_PWMLEDS; i++) { + start_probing(i); + } +} + +unsigned char pwmled_is_on(unsigned char n) +{ + unsigned char st = pwmled_state[n]; + if (st == ST_PROBING || st == ST_ON) + return 1; + else + return 0; +} + +static void inline probing_adc(unsigned char n, uint16_t adcval) +{ + unsigned char need_bigger = 0, i; + unsigned char *pwm_p = &pwm_vals[n*N_PWMLED_MODES]; + unsigned char *adc_p = &adc_vals[n*N_PWMLED_MODES]; + unsigned char pwm = pwm_probes[n]; + +#if 0 + log_byte(n); + log_byte(0xF4); + log_word(adcval); +#endif + +#if 0 + if (pwm == 0 && adcval > 0) { // non-zero voltage with zero PWM? + pwmled_state[n] = ST_DISABLED; + log_byte(n); + log_byte(0xF0); + log_word(adcval); + return; + } +#endif + + for (i = 0; i < N_PWMLED_MODES; i++, pwm_p++, adc_p++) { + uint16_t adc = *adc_p; + if (adc >= adcval) { + *pwm_p = pwm; + need_bigger = 1; + } + } + +#if 0 + if ((n == 1 && pwm > 0x35) || adcval != 0) { + log_byte(n); + log_byte(0xF3); + log_byte(pwm); + log_word(adcval); + } +#endif + + if (!need_bigger) { // successfully probed + pwm_off(n); + // pwm_set(n, 0); + pwmled_state[n] = ST_OFF; + log_byte(n); + log_byte(0xF1); + + return; + } + + if (pwm >= 0x60) { // over the maximum! + pwmled_state[n] = ST_DISABLED; + log_byte(n); + log_byte(0xF2); + pwm_off(n); + // pwm_set(n, 0); + return; + } + + // try to increase + pwm++; + pwm_probes[n] = pwm; + pwm_set(n, pwm); +} + +// Feedback loop +static void inline on_adc(unsigned char n, uint16_t adcval) +{ +#if 0 + uint16_t new_pwm = led_modes[led_mode].pwmval; + uint16_t old_pwm = new_pwm; + uint16_t adc_exp = led_modes[led_mode].expected; + + log_word(((adcval & 0xFF) << 8) | old_pwm); + + if (2*adcval > 5*adc_exp) { // >2.5x expected, lower significantly + new_pwm = 2*old_pwm/3; + } else if (3*adcval > 4*adc_exp) { // >1.33x expected, lower a bit + new_pwm = old_pwm - 1; + } else if (4*adcval < 3*adc_exp) { // 0.75x expected, raise a bit + new_pwm = old_pwm + 1; + } + + if (new_pwm > 0x60) { // odpojeno? + new_pwm = 0x60; + } + if (new_pwm < 2) { // zkrat? + new_pwm = 2; + } + +set_pwm: + if (new_pwm != old_pwm) { + led_modes[led_mode].pwmval = new_pwm; + OCR1D = new_pwm; + } + // ADCSRA |= _BV(ADSC); +#endif +} + +void pwmled_adc(unsigned char n, uint16_t adcval) +{ + unsigned char i, probing; + switch (pwmled_state[n]) { + case ST_PROBING: + probing_adc(n, adcval); + + probing = 0; + for (i = 0; i < N_PWMLEDS; i++) + if (pwmled_state[i] == ST_PROBING) + probing = 1; + + if (!probing) { + for (i = 0; i < N_PWMLEDS; i++) + log_byte(pwmled_state[i]); + + for (i = 0; i < N_PWMLEDS*N_PWMLED_MODES; i++) + log_byte(pwm_vals[i]); + log_flush(); + } + + return; + case ST_ON: + on_adc(n, adcval); + return; + // WTF am I doing in this function then? + } +} diff --git a/tmr.c b/tmr.c new file mode 100644 index 0000000..b8fb502 --- /dev/null +++ b/tmr.c @@ -0,0 +1,25 @@ +#include +#include + +#include "lights.h" + +volatile uint16_t jiffies; + +void init_tmr() +{ + TCCR0A = _BV(WGM00); + TCCR0B = _BV(CS02) | _BV(CS00); // CLK/1024 = 1 kHz + OCR0A = 10; // 100 Hz + TIMSK |= _BV(OCIE0A); + + jiffies = 0; +} + +ISR(TIMER0_COMPA_vect) +{ + ++jiffies; + + // patterns_next_tick(); + timer_start_adcs(); +} + -- 2.39.3