diff options
| -rw-r--r-- | spaghetti-monster/fsm-adc.c | 45 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-adc.h | 8 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-events.c | 3 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-main.c | 21 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-main.h | 2 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-pcint.c | 21 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-pcint.h | 1 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-standby.c | 19 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-wdt.c | 22 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-wdt.h | 4 |
10 files changed, 108 insertions, 38 deletions
diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 6832e32..1fc5472 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -113,15 +113,44 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { #else #define ADC_CYCLES_PER_SECOND 8 #endif -// TODO: is this better done in main() or WDT()? + +// save the measurement result, set a flag to show something happened, +// and count how many times we've triggered since last counter reset ISR(ADC_vect) { - // For some reason, the ADC interrupt is getting called a *lot* - // more often than it should be, like it's auto-triggering after each - // measurement, but I don't know why, or how to turn that off... - // So, skip every call except when explicitly requested. + #if 0 // the fancy method is probably not even needed + // count up but wrap around from 255 to 128; not 255 to 0 + // TODO: find a way to do this faster if possible + uint8_t val = irq_adc; // cache volatile value + irq_adc = (val + 1) | (val & 0b10000000); + #else + irq_adc ++; + #endif + adc_value = ADC; // save this for later use +} + +void ADC_inner() { + // ignore the first measurement; the docs say it's junk + if (irq_adc < 2) { + ADC_start_measurement(); // start a second measurement + return; + } + + // the ADC triggers repeatedly when it's on, but we only want one value + // (so ignore everything after the first value, until it's manually reset) if (! adcint_enable) return; + + // if we're actually runnning, reset the status flags / counters + irq_adc = 0; adcint_enable = 0; + #ifdef TICK_DURING_STANDBY + // in sleep mode, turn off after just one measurement + // (having the ADC on raises standby power by about 250 uA) + // (and the usual standby level is only ~20 uA) + if (go_to_standby) ADC_off(); + #endif + + // what is being measured? 0/1 = battery voltage, 2/3 = temperature static uint8_t adc_step = 0; // LVP declarations @@ -155,7 +184,7 @@ ISR(ADC_vect) { #define ADC_STEPS 2 #endif - uint16_t measurement = ADC; // latest 10-bit ADC reading + uint16_t measurement = adc_value; // latest 10-bit ADC reading #ifdef USE_PSEUDO_RAND // real-world entropy makes this a true random, not pseudo @@ -376,10 +405,6 @@ ISR(ADC_vect) { #endif #endif - #ifdef TICK_DURING_STANDBY - // if we were asleep, go back to sleep - if (go_to_standby) ADC_off(); - #endif } #ifdef USE_BATTCHECK diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index 274fb4d..acb3da6 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -38,9 +38,15 @@ #define VOLTAGE_FUDGE_FACTOR 5 #endif #endif + +volatile uint8_t irq_adc = 0; // ADC interrupt happened? +uint16_t adc_value; // last ADC measurement +uint8_t adcint_enable = 0; // is the current ADC result needed? +void ADC_inner(); // do the actual ADC-related calculations + volatile uint8_t voltage = 0; -volatile uint8_t adcint_enable; // kludge, because adc auto-retrigger won't turn off void low_voltage(); + #ifdef USE_BATTCHECK void battcheck(); #ifdef BATTCHECK_VpT diff --git a/spaghetti-monster/fsm-events.c b/spaghetti-monster/fsm-events.c index 3e9a12d..e125e84 100644 --- a/spaghetti-monster/fsm-events.c +++ b/spaghetti-monster/fsm-events.c @@ -145,6 +145,9 @@ uint8_t nice_delay_ms(uint16_t ms) { _delay_loop_2(BOGOMIPS*98/100); #endif // ifdef USE_DYNAMIC_UNDERCLOCKING + // run pending system processes while we wait + handle_deferred_interrupts(); + if ((nice_delay_interrupt) || (old_state != current_state)) { return 0; // state changed; abort } diff --git a/spaghetti-monster/fsm-main.c b/spaghetti-monster/fsm-main.c index e537a9e..a898f41 100644 --- a/spaghetti-monster/fsm-main.c +++ b/spaghetti-monster/fsm-main.c @@ -160,6 +160,9 @@ int main() { standby_mode(); } + // catch up on interrupts + handle_deferred_interrupts(); + // give the recipe some time slices loop(); @@ -168,4 +171,22 @@ int main() { } } + +void handle_deferred_interrupts() { + /* + if (irq_pcint) { // button pressed or released + // nothing to do here + // (PCINT only matters during standby) + } + */ + if (irq_adc) { // ADC done measuring + ADC_inner(); + // irq_adc = 0; // takes care of itself + } + if (irq_wdt) { // the clock ticked + WDT_inner(); + // irq_wdt = 0; // takes care of itself + } +} + #endif diff --git a/spaghetti-monster/fsm-main.h b/spaghetti-monster/fsm-main.h index cc469d7..55ae2ff 100644 --- a/spaghetti-monster/fsm-main.h +++ b/spaghetti-monster/fsm-main.h @@ -21,5 +21,7 @@ #define FSM_MAIN_H int main(); +// needs to run frequently to execute the logic for WDT and ADC and stuff +void handle_deferred_interrupts(); #endif diff --git a/spaghetti-monster/fsm-pcint.c b/spaghetti-monster/fsm-pcint.c index 4928980..a4a496a 100644 --- a/spaghetti-monster/fsm-pcint.c +++ b/spaghetti-monster/fsm-pcint.c @@ -24,19 +24,9 @@ #include <util/delay_basic.h> uint8_t button_is_pressed() { - // remember the past 32 measurements - static uint32_t readings = 0; - // take at least one new measurement, - // and wait for measurements to settle to all zeroes or all ones - do { - // shift past readings and add current value - readings = (readings << 1) | ((SWITCH_PORT & (1<<SWITCH_PIN)) == 0); - // wait a moment - _delay_loop_2(BOGOMIPS/16); // up to 2ms to stabilize - } - while ((readings != 0) && (readings != 0xFFFFFFFF)); - button_last_state = readings; - return readings; + uint8_t value = ((SWITCH_PORT & (1<<SWITCH_PIN)) == 0); + button_last_state = value; + return value; } inline void PCINT_on() { @@ -75,7 +65,10 @@ inline void PCINT_off() { //void button_change_interrupt() { #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634) -EMPTY_INTERRUPT(PCINT0_vect); +//EMPTY_INTERRUPT(PCINT0_vect); +ISR(PCINT0_vect) { + irq_pcint = 1; +} #else #error Unrecognized MCU type #endif diff --git a/spaghetti-monster/fsm-pcint.h b/spaghetti-monster/fsm-pcint.h index ec3ae4b..a7f3733 100644 --- a/spaghetti-monster/fsm-pcint.h +++ b/spaghetti-monster/fsm-pcint.h @@ -20,6 +20,7 @@ #ifndef FSM_PCINT_H #define FSM_PCINT_H +volatile uint8_t irq_pcint = 0; // pin change interrupt happened? //static volatile uint8_t button_was_pressed; #define BP_SAMPLES 32 volatile uint8_t button_last_state; diff --git a/spaghetti-monster/fsm-standby.c b/spaghetti-monster/fsm-standby.c index 44b047a..4124d92 100644 --- a/spaghetti-monster/fsm-standby.c +++ b/spaghetti-monster/fsm-standby.c @@ -42,13 +42,15 @@ void sleep_until_eswitch_pressed() // make sure switch isn't currently pressed while (button_is_pressed()) {} empty_event_sequence(); // cancel pending input on suspend - //PCINT_since_WDT = 0; // ensure PCINT won't ignore itself PCINT_on(); // wake on e-switch event #ifdef TICK_DURING_STANDBY + // detect which type of event caused a wake-up + irq_adc = 0; + irq_wdt = 0; + irq_pcint = 0; while (go_to_standby) { - f_wdt = 0; // detect if WDT was what caused a wake-up #else go_to_standby = 0; #endif @@ -65,10 +67,19 @@ void sleep_until_eswitch_pressed() sleep_disable(); #ifdef TICK_DURING_STANDBY - // determine what woke us up... WDT or PCINT - if (! f_wdt) { // PCINT went off; wake up + // determine what woke us up... + if (irq_pcint) { // button pressed; wake up go_to_standby = 0; } + if (irq_adc) { // ADC done measuring + adcint_enable = 1; + ADC_inner(); + //ADC_off(); // takes care of itself + //irq_adc = 0; // takes care of itself + } + if (irq_wdt) { // generate a sleep tick + WDT_inner(); + } } #endif diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c index 6e61e87..3cb7d86 100644 --- a/spaghetti-monster/fsm-wdt.c +++ b/spaghetti-monster/fsm-wdt.c @@ -82,11 +82,23 @@ inline void WDT_off() // clock tick -- this runs every 16ms (62.5 fps) ISR(WDT_vect) { + irq_wdt = 1; // WDT event happened +} + +void WDT_inner() { + irq_wdt = 0; // WDT event handled; reset flag + static uint8_t adc_trigger = 0; - #ifdef TICK_DURING_STANDBY - f_wdt = 1; // WDT event happened + // detect and emit button change events (even during standby) + uint8_t was_pressed = button_last_state; + uint8_t pressed = button_is_pressed(); + if (was_pressed != pressed) { + go_to_standby = 0; + PCINT_inner(pressed); + } + #ifdef TICK_DURING_STANDBY static uint16_t sleep_counter = 0; // handle standby mode specially if (go_to_standby) { @@ -107,11 +119,6 @@ ISR(WDT_vect) { else { sleep_counter = 0; } #endif - // detect and emit button change events - uint8_t was_pressed = button_last_state; - uint8_t pressed = button_is_pressed(); - if (was_pressed != pressed) PCINT_inner(pressed); - // cache this here to reduce ROM size, because it's volatile uint16_t ticks_since_last = ticks_since_last_event; @@ -178,6 +185,7 @@ ISR(WDT_vect) { if (go_to_standby) ADC_on(); #endif ADC_start_measurement(); + irq_adc = 0; adcint_enable = 1; } #endif diff --git a/spaghetti-monster/fsm-wdt.h b/spaghetti-monster/fsm-wdt.h index 78fe791..d127551 100644 --- a/spaghetti-monster/fsm-wdt.h +++ b/spaghetti-monster/fsm-wdt.h @@ -25,9 +25,9 @@ void WDT_on(); inline void WDT_off(); -#ifdef TICK_DURING_STANDBY -volatile uint8_t f_wdt = 0; +volatile uint8_t irq_wdt = 0; // WDT interrupt happened? +#ifdef TICK_DURING_STANDBY #if defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS) // measure battery charge while asleep #define USE_SLEEP_LVP |
