diff options
| author | Selene ToyKeeper | 2019-11-14 19:47:49 -0700 |
|---|---|---|
| committer | Selene ToyKeeper | 2019-11-14 19:47:49 -0700 |
| commit | 5362c032fdca4b20af49db0409a03524a396b815 (patch) | |
| tree | 1d437085b5b3472279167aee905385e39a4a1fe1 | |
| parent | merged from fsm branch to get safety ramp-down and version check functions, a... (diff) | |
| parent | merged irq-refactor branch, which fixes some small but long-standing issues: (diff) | |
| download | anduril-5362c032fdca4b20af49db0409a03524a396b815.tar.gz anduril-5362c032fdca4b20af49db0409a03524a396b815.tar.bz2 anduril-5362c032fdca4b20af49db0409a03524a396b815.zip | |
merged fsm updates / irq-refactor branch, to get more stable voltage readings
(and otherwise get recent bugfixes)
Diffstat (limited to '')
24 files changed, 566 insertions, 268 deletions
diff --git a/hwdef-Emisar_D4Sv2.h b/hwdef-Emisar_D4Sv2.h new file mode 100644 index 0000000..da3a0ca --- /dev/null +++ b/hwdef-Emisar_D4Sv2.h @@ -0,0 +1,124 @@ +#ifndef HWDEF_EMISAR_D4SV2_H +#define HWDEF_EMISAR_D4SV2_H + +/* Emisar D4Sv2 driver layout (attiny1634) + * (same layout as D4v2, except it's a FET+3+1 instead of FET+1) + * + * Pin / Name / Function + * 1 PA6 FET PWM (PWM1B) + * 2 PA5 red aux LED (PWM0B) + * 3 PA4 green aux LED + * 4 PA3 blue aux LED + * 5 PA2 e-switch + * 6 PA1 (none) + * 7 PA0 (none) + * 8 GND GND + * 9 VCC VCC + * 10 PC5 (none) + * 11 PC4 (none) + * 12 PC3 RESET + * 13 PC2 (none) + * 14 PC1 SCK + * 15 PC0 3x7135 PWM (PWM0A) + * 16 PB3 1x7135 PWM (PWM1A) + * 17 PB2 MISO + * 18 PB1 MOSI + * 19 PB0 (none) + * 20 PA7 (none) + * ADC12 thermal sensor + */ + +#ifdef ATTINY +#undef ATTINY +#endif +#define ATTINY 1634 +#include <avr/io.h> + +#define SWITCH_PIN PA2 // pin 5 +#define SWITCH_PCINT PCINT2 // pin 5 pin change interrupt +#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] +#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] +#define SWITCH_PORT PINA // PINA or PINB or PINC + +#define PWM_CHANNELS 3 + +#define PWM1_PIN PB3 // pin 16, 1x7135 PWM +#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 + +#define PWM2_PIN PC0 // pin 15, 3x7135 PWM +#define PWM2_LVL OCR0A // OCR0A is the output compare register for PC0 + +#define PWM3_PIN PA6 // pin 1, FET PWM +#define PWM3_LVL OCR1B // OCR1B is the output compare register for PB1 + + +#define ADC_PRSCL 0x06 // clk/64 + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 4 // add 0.20V (measured 0.22V) +#endif + +#define TEMP_CHANNEL 0b00001111 + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + +// with so many pins, doing this all with #ifdefs gets awkward... +// ... so just hardcode it in each hwdef file instead +inline void hwdef_setup() { + // enable output ports + // FET, aux R/G/B + DDRA = (1 << PWM3_PIN) + | (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + ; + // 1x7135 + DDRB = (1 << PWM1_PIN); + // 3x7135 + DDRC = (1 << PWM2_PIN); + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // WGM1[3:0]: 0,0,0,1: PWM, Phase Correct, 8-bit (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) + TCCR1A = (0<<WGM11) | (1<<WGM10) // 8-bit (TOP=0xFF) (DS table 12-5) + | (1<<COM1A1) | (0<<COM1A0) // PWM 1A in normal direction (DS table 12-4) + | (1<<COM1B1) | (0<<COM1B0) // PWM 1B in normal direction (DS table 12-4) + ; + TCCR1B = (0<<CS12) | (0<<CS11) | (1<<CS10) // clk/1 (no prescaling) (DS table 12-6) + | (0<<WGM13) | (0<<WGM12) // phase-correct PWM (DS table 12-5) + ; + + // WGM0[2:0]: 0,0,1: PWM, Phase Correct (DS table 11-8) + // CS0[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 11-9) + // COM0A[1:0]: 1,0: PWM OC0A in the normal direction (DS table 11-4) + // COM0B[1:0]: 0,0: OC0B disabled (DS table 11-7) + // TCCR0A: COM0A1, COM0A0, COM0B1, COM0B0, -, -, WGM01, WGM00 + TCCR0A = (0<<WGM01) | (1<<WGM00) // PWM, Phase Correct, TOP=0xFF (DS table 11-5) + | (1<<COM1A1) | (0<<COM1A0) // PWM 0A in normal direction (DS table 11-4) + | (0<<COM1B1) | (0<<COM1B0) // PWM 0B disabled (DS table 11-7) + ; + // TCCR0B: FOC0A, FOC0B, -, -, WGM02, CS02, CS01, CS00 + TCCR0B = (0<<CS02) | (0<<CS01) | (1<<CS00) // clk/1 (no prescaling) (DS table 11-9) + | (0<<WGM02) // PWM, Phase Correct, TOP=0xFF (DS table 11-8) + ; + + // set up e-switch + //PORTA = (1 << SWITCH_PIN); // TODO: configure PORTA / PORTB / PORTC? + PUEA = (1 << SWITCH_PIN); // pull-up for e-switch + SWITCH_PCMSK = (1 << SWITCH_PCINT); // enable pin change interrupt +} + +#define LAYOUT_DEFINED + +#endif diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 359681f..e006292 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -2403,7 +2403,7 @@ void rgb_led_voltage_readout(uint8_t bright) { void factory_reset() { // display a warning for a few seconds before doing the actual reset, // so the user has time to abort if they want - #define SPLODEY_TIME 3000 + #define SPLODEY_TIME 2500 #define SPLODEY_STEPS 64 #define SPLODEY_TIME_PER_STEP (SPLODEY_TIME/SPLODEY_STEPS) uint8_t bright; @@ -2411,9 +2411,9 @@ void factory_reset() { // wind up to an explosion for (bright=0; bright<SPLODEY_STEPS; bright++) { set_level(bright); - delay_4ms(SPLODEY_TIME_PER_STEP/2/4); + nice_delay_ms(SPLODEY_TIME_PER_STEP/2); set_level(bright>>1); - delay_4ms(SPLODEY_TIME_PER_STEP/2/4); + nice_delay_ms(SPLODEY_TIME_PER_STEP/2); if (! button_is_pressed()) { reset = 0; break; @@ -2434,14 +2434,14 @@ void factory_reset() { bright = MAX_LEVEL; for (; bright > 0; bright--) { set_level(bright); - delay_4ms(SPLODEY_TIME_PER_STEP/6/4); + nice_delay_ms(SPLODEY_TIME_PER_STEP/8); } } // explosion cancelled, fade away else { for (; bright > 0; bright--) { set_level(bright); - delay_4ms(SPLODEY_TIME_PER_STEP/3/4); + nice_delay_ms(SPLODEY_TIME_PER_STEP/3); } } } diff --git a/spaghetti-monster/anduril/cfg-blf-lantern.h b/spaghetti-monster/anduril/cfg-blf-lantern.h index 9467397..bf183eb 100644 --- a/spaghetti-monster/anduril/cfg-blf-lantern.h +++ b/spaghetti-monster/anduril/cfg-blf-lantern.h @@ -51,6 +51,9 @@ #define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL #define RAMP_DISCRETE_STEPS 5 +#define MUGGLE_FLOOR 15 // about 20 lm +#define MUGGLE_CEILING 115 // about 350 lm + // the sensor (attiny85) is nowhere near the emitters // so thermal regulation can't work #ifdef USE_THERMAL_REGULATION diff --git a/spaghetti-monster/anduril/cfg-blf-q8.h b/spaghetti-monster/anduril/cfg-blf-q8.h index 970fedb..166b10e 100644 --- a/spaghetti-monster/anduril/cfg-blf-q8.h +++ b/spaghetti-monster/anduril/cfg-blf-q8.h @@ -13,6 +13,11 @@ // lockout: blinking (3) #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2) +// doesn't quite fit +#ifdef USE_MUGGLE_MODE +#undef USE_MUGGLE_MODE +#endif + // copied from Emisar D4 ramp // ../../bin/level_calc.py 1 65 7135 1 0.8 150 // ... mixed with this: diff --git a/spaghetti-monster/anduril/cfg-emisar-d1sv2.h b/spaghetti-monster/anduril/cfg-emisar-d1sv2.h index 33b240d..19610dc 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1sv2.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1sv2.h @@ -59,3 +59,8 @@ #define PARTY_STROBE_ONTIME 2 #define THERM_CAL_OFFSET 5 + +// attiny1634 has enough space to smooth out voltage readings +// (prevent the button from blinking during use) +#define USE_VOLTAGE_LOWPASS + diff --git a/spaghetti-monster/anduril/cfg-emisar-d4s.h b/spaghetti-monster/anduril/cfg-emisar-d4s.h index 230ac7c..6fe95a6 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4s.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4s.h @@ -46,3 +46,4 @@ #define THERMAL_WARNING_SECONDS 3 #define THERMAL_UPDATE_SPEED 2 #define THERM_PREDICTION_STRENGTH 4 + diff --git a/spaghetti-monster/anduril/cfg-emisar-d4sv2-219.h b/spaghetti-monster/anduril/cfg-emisar-d4sv2-219.h new file mode 100644 index 0000000..9898246 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-emisar-d4sv2-219.h @@ -0,0 +1,10 @@ +// Emisar D4Sv2-219 config options for Anduril +#include "cfg-emisar-d4sv2.h" +// ATTINY: 1634 + +#undef PWM1_LEVELS +#undef PWM2_LEVELS +#undef PWM3_LEVELS +#define PWM1_LEVELS 1,1,2,2,3,3,4,5,5,6,7,8,9,10,11,12,13,17,18,19,20,21,22,24,26,28,30,33,35,38,41,44,47,50,54,57,61,65,69,74,79,84,89,94,100,106,113,119,126,134,142,150,158,167,176,186,196,207,218,230,242,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,16,21,25,30,35,41,46,52,58,64,71,77,84,92,99,107,115,124,133,142,151,161,172,182,193,205,217,229,242,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,4,6,7,9,10,12,13,15,17,18,20,22,24,26,28,30,33,35,37,40,43,45,48,50,53,56,59,62,65,69,72,76,80,83,87,91,95,99,104,108,113,117,123,127,132,138,143,148,154,160,166,172,178,185,192 diff --git a/spaghetti-monster/anduril/cfg-emisar-d4sv2.h b/spaghetti-monster/anduril/cfg-emisar-d4sv2.h new file mode 100644 index 0000000..c47e774 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-emisar-d4sv2.h @@ -0,0 +1,67 @@ +// Emisar D4S V2 config options for Anduril +#include "hwdef-Emisar_D4Sv2.h" +// ATTINY: 1634 + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS +// the aux LEDs are front-facing, so turn them off while main LEDs are on +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif +// enable blinking aux LEDs +#define TICK_DURING_STANDBY +#define STANDBY_TICK_SPEED 3 // every 0.128 s +//#define STANDBY_TICK_SPEED 4 // every 0.256 s +//#define STANDBY_TICK_SPEED 5 // every 0.512 s + + +// 1x7135 + 3x7135 + FET +// ../../../bin/level_calc.py seventh 3 150 7135 1 2.3 130 7135 11 5 400.1 FET 2 10 4000 +// (and some manual edits to make the clock speed changes smoother) +#define PWM1_LEVELS 1,1,2,2,3,3,4,5,5,6,7,8,9,10,11,12,13,17,18,19,20,21,22,24,26,28,30,33,35,38,41,44,47,50,54,57,61,65,69,74,79,84,89,94,100,106,113,119,126,134,142,150,158,167,176,186,196,207,218,230,242,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,16,21,25,30,35,41,46,52,58,64,71,77,84,92,99,107,115,124,133,142,151,161,172,182,193,205,217,229,242,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,5,6,8,10,12,14,16,18,20,23,25,27,30,32,35,38,41,44,47,50,53,57,60,64,67,71,75,79,83,87,92,96,101,106,111,116,121,127,132,138,144,150,156,163,169,176,183,190,197,205,213,221,229,237,246,255 +#define MAX_1x7135 62 +#define MAX_Nx7135 93 +#define HALFSPEED_LEVEL 18 +#define QUARTERSPEED_LEVEL 8 + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 130 +// 20, 38, 56, 75, [93], 111, 130 +#define RAMP_DISCRETE_FLOOR 20 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 + +#define DEFAULT_LEVEL MAX_Nx7135 +#define STROBE_BRIGHTNESS MAX_LEVEL + +#define MUGGLE_FLOOR RAMP_DISCRETE_FLOOR +#define MUGGLE_CEILING MAX_Nx7135 + +// stop panicking at ~50% power or ~2000 lm +#define THERM_FASTER_LEVEL 130 + +// no need to be extra-careful on this light +#ifdef THERM_HARD_TURBO_DROP +#undef THERM_HARD_TURBO_DROP +#endif + +// respond to thermal changes faster +#define THERMAL_WARNING_SECONDS 3 +#define THERMAL_UPDATE_SPEED 2 +#define THERM_PREDICTION_STRENGTH 4 + +// easier access to thermal config mode, for Emisar +#define USE_TENCLICK_THERMAL_CONFIG + +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + +// seems relevant on attiny1634 +#define THERM_CAL_OFFSET 5 + +// attiny1634 has enough space to smooth out voltage readings +#define USE_VOLTAGE_LOWPASS + diff --git a/spaghetti-monster/anduril/cfg-emisar-d4v2.h b/spaghetti-monster/anduril/cfg-emisar-d4v2.h index b83c65c..0db1062 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4v2.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4v2.h @@ -49,3 +49,6 @@ #define USE_TENCLICK_THERMAL_CONFIG #define THERM_CAL_OFFSET 5 + +// attiny1634 has enough space to smooth out voltage readings +#define USE_VOLTAGE_LOWPASS diff --git a/spaghetti-monster/anduril/cfg-mateminco-mf01s.h b/spaghetti-monster/anduril/cfg-mateminco-mf01s.h index 0585b38..2af1305 100644 --- a/spaghetti-monster/anduril/cfg-mateminco-mf01s.h +++ b/spaghetti-monster/anduril/cfg-mateminco-mf01s.h @@ -14,6 +14,12 @@ #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) +// doesn't quite fit +#ifdef USE_MUGGLE_MODE +#undef USE_MUGGLE_MODE +#endif + + // don't blink during ramp, it's irrelevant and annoying on this light #define BLINK_AT_RAMP_CEILING #undef BLINK_AT_RAMP_MIDDLE diff --git a/spaghetti-monster/anduril/version.h b/spaghetti-monster/anduril/version.h new file mode 100644 index 0000000..8cf3c90 --- /dev/null +++ b/spaghetti-monster/anduril/version.h @@ -0,0 +1,4 @@ +// this file is replaced automatically by the build script +// set your own date here if you're not using the build script +// otherwise, default to first human contact with the moon +#define VERSION_NUMBER "19690720" diff --git a/spaghetti-monster/darkhorse/darkhorse.c b/spaghetti-monster/darkhorse/darkhorse.c index e613f55..4058c2f 100644 --- a/spaghetti-monster/darkhorse/darkhorse.c +++ b/spaghetti-monster/darkhorse/darkhorse.c @@ -21,7 +21,6 @@ #define USE_LVP #define USE_THERMAL_REGULATION #define DEFAULT_THERM_CEIL 45 -#define USE_DELAY_4MS #define USE_RAMPING #define RAMP_LENGTH 150 #define USE_BATTCHECK diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index a5507a9..30f8460 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -30,6 +30,7 @@ inline void set_admux_therm() { #else #error Unrecognized MCU type #endif + adc_channel = 1; } inline void set_admux_voltage() { @@ -52,6 +53,7 @@ inline void set_admux_voltage() { #else #error Unrecognized MCU type #endif + adc_channel = 0; } inline void ADC_start_measurement() { @@ -113,36 +115,158 @@ 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()? + +#ifdef USE_THERMAL_REGULATION +#define ADC_STEPS 2 +#else +#define ADC_STEPS 1 +#endif + +// happens every time the ADC sampler finishes a measurement 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. + #ifdef USE_PSEUDO_RAND + // real-world entropy makes this a true random, not pseudo + pseudo_rand_seed += ADCL; + #endif + + if (irq_adc_stable) { // skip first result; it's junk + adc_values[adc_channel] = ADC; // save this for later use + irq_adc = 1; // a value was saved, so trigger deferred logic + } + irq_adc_stable = 1; + + // start another measurement + // (is explicit because it otherwise doesn't seem to happen during standby mode) + ADC_start_measurement(); +} + +void ADC_inner() { + irq_adc = 0; // event handled + + // 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; + + // disable after one iteration 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 = battery voltage, 1 = temperature static uint8_t adc_step = 0; - // LVP declarations #ifdef USE_LVP - #ifdef USE_LVP_AVG - #define NUM_VOLTAGE_VALUES 4 - static int16_t voltage_values[NUM_VOLTAGE_VALUES]; + if (0 == adc_step) { // voltage + ADC_voltage_handler(); + } + #endif + + #ifdef USE_THERMAL_REGULATION + else if (1 == adc_step) { // temperature + ADC_temperature_handler(); + } + #endif + + #if defined(TICK_DURING_STANDBY) && defined(USE_SLEEP_LVP) + // only measure battery voltage while asleep + if (go_to_standby) adc_step = 0; + else + #endif + + adc_step = (adc_step + 1) & (ADC_STEPS-1); + + // set the correct type of measurement for next time + #ifdef USE_THERMAL_REGULATION + #ifdef USE_LVP + if (0 == adc_step) set_admux_voltage(); + else set_admux_therm(); + #else + //set_admux_therm(); + #error "USE_THERMAL_REGULATION set without USE_LVP" + #endif + #else + #ifdef USE_LVP + set_admux_voltage(); + #endif #endif + + irq_adc_stable = 0; // first result is unstable +} + + +#ifdef USE_LVP +static inline void ADC_voltage_handler() { static uint8_t lvp_timer = 0; static uint8_t lvp_lowpass = 0; #define LVP_TIMER_START (VOLTAGE_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) // N seconds between LVP warnings #define LVP_LOWPASS_STRENGTH ADC_CYCLES_PER_SECOND // lowpass for one second + + uint16_t measurement = adc_values[0]; // latest 10-bit ADC reading + + #ifdef USE_VOLTAGE_LOWPASS + static uint16_t prev_measurement = 0; + + // prime on first execution, or while asleep + if (go_to_standby || (! prev_measurement)) prev_measurement = measurement; + + // only allow raw value to go up or down by 1 per iteration + if (measurement > prev_measurement) measurement = prev_measurement + 1; + else if (measurement < prev_measurement) measurement = prev_measurement - 1; + + // remember for later + prev_measurement = measurement; + #endif // no USE_VOLTAGE_LOWPASS + + #ifdef USE_VOLTAGE_DIVIDER + voltage = calc_voltage_divider(measurement); + #else + // calculate actual voltage: volts * 10 + // ADC = 1.1 * 1024 / volts + // volts = 1.1 * 1024 / ADC + //voltage = (uint16_t)(1.1*1024*10)/measurement + VOLTAGE_FUDGE_FACTOR; + voltage = ((uint16_t)(2*1.1*1024*10)/measurement + VOLTAGE_FUDGE_FACTOR) >> 1; #endif + // if low, callback EV_voltage_low / EV_voltage_critical + // (but only if it has been more than N ticks since last call) + if (lvp_timer) { + lvp_timer --; + } else { // it has been long enough since the last warning + if (voltage < VOLTAGE_LOW) { + if (lvp_lowpass < LVP_LOWPASS_STRENGTH) { + lvp_lowpass ++; + } else { + // try to send out a warning + //uint8_t err = emit(EV_voltage_low, 0); + //uint8_t err = emit_now(EV_voltage_low, 0); + emit(EV_voltage_low, 0); + //if (!err) { + // on successful warning, reset counters + lvp_timer = LVP_TIMER_START; + lvp_lowpass = 0; + //} + } + } else { + // voltage not low? reset count + lvp_lowpass = 0; + } + } +} +#endif + + +#ifdef USE_THERMAL_REGULATION +static inline void ADC_temperature_handler() { // thermal declarations - #ifdef USE_THERMAL_REGULATION #ifndef THERMAL_UPDATE_SPEED #define THERMAL_UPDATE_SPEED 2 #endif #define NUM_THERMAL_VALUES_HISTORY 8 - #define ADC_STEPS 4 static uint8_t history_step = 0; // don't update history as often static int16_t temperature_history[NUM_THERMAL_VALUES_HISTORY]; static uint8_t temperature_timer = 0; @@ -151,236 +275,132 @@ ISR(ADC_vect) { #define TEMPERATURE_TIMER_START ((THERMAL_WARNING_SECONDS-2)*ADC_CYCLES_PER_SECOND) // N seconds between thermal regulation events #define OVERHEAT_LOWPASS_STRENGTH (ADC_CYCLES_PER_SECOND*2) // lowpass for 2 seconds #define UNDERHEAT_LOWPASS_STRENGTH (ADC_CYCLES_PER_SECOND*2) // lowpass for 2 seconds - #else - #define ADC_STEPS 2 - #endif - - uint16_t measurement = ADC; // latest 10-bit ADC reading - - #ifdef USE_PSEUDO_RAND - // real-world entropy makes this a true random, not pseudo - pseudo_rand_seed += measurement; - #endif - - #if defined(TICK_DURING_STANDBY) && defined(USE_SLEEP_LVP) - // only measure battery voltage while asleep - if (go_to_standby) adc_step = 1; - else - #endif - adc_step = (adc_step + 1) & (ADC_STEPS-1); - - #ifdef USE_LVP - // voltage - if (adc_step == 1) { - #ifdef USE_LVP_AVG - // prime on first execution - if (voltage == 0) { - for(uint8_t i=0; i<NUM_VOLTAGE_VALUES; i++) - voltage_values[i] = measurement; - voltage = 42; // the answer to life, the universe, and the voltage of a full li-ion cell - } else { - uint16_t total = 0; - uint8_t i; - for(i=0; i<NUM_VOLTAGE_VALUES-1; i++) { - voltage_values[i] = voltage_values[i+1]; - total += voltage_values[i]; - } - voltage_values[i] = measurement; - total += measurement; - total = total >> 2; - - #ifdef USE_VOLTAGE_DIVIDER - voltage = calc_voltage_divider(total); - #else - voltage = (uint16_t)(1.1*1024*10)/total + VOLTAGE_FUDGE_FACTOR; - #endif - } - #else // no USE_LVP_AVG - #ifdef USE_VOLTAGE_DIVIDER - voltage = calc_voltage_divider(measurement); - #else - // calculate actual voltage: volts * 10 - // ADC = 1.1 * 1024 / volts - // volts = 1.1 * 1024 / ADC - //voltage = (uint16_t)(1.1*1024*10)/measurement + VOLTAGE_FUDGE_FACTOR; - voltage = ((uint16_t)(2*1.1*1024*10)/measurement + VOLTAGE_FUDGE_FACTOR) >> 1; - #endif - #endif - // if low, callback EV_voltage_low / EV_voltage_critical - // (but only if it has been more than N ticks since last call) - if (lvp_timer) { - lvp_timer --; - } else { // it has been long enough since the last warning - if (voltage < VOLTAGE_LOW) { - if (lvp_lowpass < LVP_LOWPASS_STRENGTH) { - lvp_lowpass ++; - } else { - // try to send out a warning - //uint8_t err = emit(EV_voltage_low, 0); - //uint8_t err = emit_now(EV_voltage_low, 0); - emit(EV_voltage_low, 0); - //if (!err) { - // on successful warning, reset counters - lvp_timer = LVP_TIMER_START; - lvp_lowpass = 0; - //} - } - } else { - // voltage not low? reset count - lvp_lowpass = 0; - } + uint16_t measurement = adc_values[1]; // latest 10-bit ADC reading + + // Convert ADC units to Celsius (ish) + int16_t temp = measurement - 275 + THERM_CAL_OFFSET + (int16_t)therm_cal_offset; + + // prime on first execution + if (reset_thermal_history) { + reset_thermal_history = 0; + temperature = temp; + for(uint8_t i=0; i<NUM_THERMAL_VALUES_HISTORY; i++) + temperature_history[i] = temp; + } else { // update our current temperature estimate + // crude lowpass filter + // (limit rate of change to 1 degree per measurement) + if (temp > temperature) { + temperature ++; + } else if (temp < temperature) { + temperature --; } } - #endif // ifdef USE_LVP + // guess what the temperature will be in a few seconds + int16_t pt; + { + int16_t diff; + int16_t t = temperature; - #ifdef USE_THERMAL_REGULATION - // temperature - else if (adc_step == 3) { - // Convert ADC units to Celsius (ish) - int16_t temp = measurement - 275 + THERM_CAL_OFFSET + (int16_t)therm_cal_offset; - - // prime on first execution - if (reset_thermal_history) { - reset_thermal_history = 0; - temperature = temp; - for(uint8_t i=0; i<NUM_THERMAL_VALUES_HISTORY; i++) - temperature_history[i] = temp; - } else { // update our current temperature estimate - // crude lowpass filter - // (limit rate of change to 1 degree per measurement) - if (temp > temperature) { - temperature ++; - } else if (temp < temperature) { - temperature --; + // algorithm tweaking; not really intended to be modified + // how far ahead should we predict? + #ifndef THERM_PREDICTION_STRENGTH + #define THERM_PREDICTION_STRENGTH 4 + #endif + // how proportional should the adjustments be? (not used yet) + #ifndef THERM_RESPONSE_MAGNITUDE + #define THERM_RESPONSE_MAGNITUDE 128 + #endif + // acceptable temperature window size in C + #define THERM_WINDOW_SIZE 5 + // highest temperature allowed + #define THERM_CEIL ((int16_t)therm_ceil) + // bottom of target temperature window + #define THERM_FLOOR (THERM_CEIL - THERM_WINDOW_SIZE) + + // if it's time to rotate the thermal history, do it + history_step ++; + #if (THERMAL_UPDATE_SPEED == 4) // new value every 4s + #define THERM_HISTORY_STEP_MAX 15 + #elif (THERMAL_UPDATE_SPEED == 2) // new value every 2s + #define THERM_HISTORY_STEP_MAX 7 + #elif (THERMAL_UPDATE_SPEED == 1) // new value every 1s + #define THERM_HISTORY_STEP_MAX 3 + #elif (THERMAL_UPDATE_SPEED == 0) // new value every 0.5s + #define THERM_HISTORY_STEP_MAX 1 + #endif + if (0 == (history_step & THERM_HISTORY_STEP_MAX)) { + // rotate measurements and add a new one + for (uint8_t i=0; i<NUM_THERMAL_VALUES_HISTORY-1; i++) { + temperature_history[i] = temperature_history[i+1]; } + temperature_history[NUM_THERMAL_VALUES_HISTORY-1] = t; } - // guess what the temperature will be in a few seconds - int16_t pt; - { - int16_t diff; - int16_t t = temperature; - - // algorithm tweaking; not really intended to be modified - // how far ahead should we predict? - #ifndef THERM_PREDICTION_STRENGTH - #define THERM_PREDICTION_STRENGTH 4 - #endif - // how proportional should the adjustments be? (not used yet) - #ifndef THERM_RESPONSE_MAGNITUDE - #define THERM_RESPONSE_MAGNITUDE 128 - #endif - // acceptable temperature window size in C - #define THERM_WINDOW_SIZE 5 - // highest temperature allowed - #define THERM_CEIL ((int16_t)therm_ceil) - // bottom of target temperature window - #define THERM_FLOOR (THERM_CEIL - THERM_WINDOW_SIZE) - - // if it's time to rotate the thermal history, do it - history_step ++; - #if (THERMAL_UPDATE_SPEED == 4) // new value every 4s - #define THERM_HISTORY_STEP_MAX 15 - #elif (THERMAL_UPDATE_SPEED == 2) // new value every 2s - #define THERM_HISTORY_STEP_MAX 7 - #elif (THERMAL_UPDATE_SPEED == 1) // new value every 1s - #define THERM_HISTORY_STEP_MAX 3 - #elif (THERMAL_UPDATE_SPEED == 0) // new value every 0.5s - #define THERM_HISTORY_STEP_MAX 1 - #endif - if (0 == (history_step & THERM_HISTORY_STEP_MAX)) { - // rotate measurements and add a new one - for (uint8_t i=0; i<NUM_THERMAL_VALUES_HISTORY-1; i++) { - temperature_history[i] = temperature_history[i+1]; - } - temperature_history[NUM_THERMAL_VALUES_HISTORY-1] = t; - } - - // guess what the temp will be several seconds in the future - // diff = rate of temperature change - //diff = temperature_history[NUM_THERMAL_VALUES_HISTORY-1] - temperature_history[0]; - diff = t - temperature_history[0]; - // slight bias toward zero; ignore very small changes (noise) - for (uint8_t z=0; z<3; z++) { - if (diff < 0) diff ++; - if (diff > 0) diff --; - } - // projected_temperature = current temp extended forward by amplified rate of change - //projected_temperature = temperature_history[NUM_THERMAL_VALUES_HISTORY-1] + (diff<<THERM_PREDICTION_STRENGTH); - pt = projected_temperature = t + (diff<<THERM_PREDICTION_STRENGTH); + // guess what the temp will be several seconds in the future + // diff = rate of temperature change + //diff = temperature_history[NUM_THERMAL_VALUES_HISTORY-1] - temperature_history[0]; + diff = t - temperature_history[0]; + // slight bias toward zero; ignore very small changes (noise) + for (uint8_t z=0; z<3; z++) { + if (diff < 0) diff ++; + if (diff > 0) diff --; } + // projected_temperature = current temp extended forward by amplified rate of change + //projected_temperature = temperature_history[NUM_THERMAL_VALUES_HISTORY-1] + (diff<<THERM_PREDICTION_STRENGTH); + pt = projected_temperature = t + (diff<<THERM_PREDICTION_STRENGTH); + } - // cancel counters if appropriate - if (pt > THERM_FLOOR) { - underheat_lowpass = 0; // we're probably not too cold - } - if (pt < THERM_CEIL) { - overheat_lowpass = 0; // we're probably not too hot - } + // cancel counters if appropriate + if (pt > THERM_FLOOR) { + underheat_lowpass = 0; // we're probably not too cold + } + if (pt < THERM_CEIL) { + overheat_lowpass = 0; // we're probably not too hot + } - if (temperature_timer) { - temperature_timer --; - } else { // it has been long enough since the last warning - - // Too hot? - if (pt > THERM_CEIL) { - if (overheat_lowpass < OVERHEAT_LOWPASS_STRENGTH) { - overheat_lowpass ++; - } else { - // reset counters - overheat_lowpass = 0; - temperature_timer = TEMPERATURE_TIMER_START; - // how far above the ceiling? - //int16_t howmuch = (pt - THERM_CEIL) * THERM_RESPONSE_MAGNITUDE / 128; - int16_t howmuch = pt - THERM_CEIL; - // try to send out a warning - emit(EV_temperature_high, howmuch); - } + if (temperature_timer) { + temperature_timer --; + } else { // it has been long enough since the last warning + + // Too hot? + if (pt > THERM_CEIL) { + if (overheat_lowpass < OVERHEAT_LOWPASS_STRENGTH) { + overheat_lowpass ++; + } else { + // reset counters + overheat_lowpass = 0; + temperature_timer = TEMPERATURE_TIMER_START; + // how far above the ceiling? + //int16_t howmuch = (pt - THERM_CEIL) * THERM_RESPONSE_MAGNITUDE / 128; + int16_t howmuch = pt - THERM_CEIL; + // try to send out a warning + emit(EV_temperature_high, howmuch); } + } - // Too cold? - else if (pt < THERM_FLOOR) { - if (underheat_lowpass < UNDERHEAT_LOWPASS_STRENGTH) { - underheat_lowpass ++; - } else { - // reset counters - underheat_lowpass = 0; - temperature_timer = TEMPERATURE_TIMER_START; - // how far below the floor? - //int16_t howmuch = (THERM_FLOOR - pt) * THERM_RESPONSE_MAGNITUDE / 128; - int16_t howmuch = THERM_FLOOR - pt; - // try to send out a warning (unless voltage is low) - // (LVP and underheat warnings fight each other) - if (voltage > VOLTAGE_LOW) - emit(EV_temperature_low, howmuch); - } + // Too cold? + else if (pt < THERM_FLOOR) { + if (underheat_lowpass < UNDERHEAT_LOWPASS_STRENGTH) { + underheat_lowpass ++; + } else { + // reset counters + underheat_lowpass = 0; + temperature_timer = TEMPERATURE_TIMER_START; + // how far below the floor? + //int16_t howmuch = (THERM_FLOOR - pt) * THERM_RESPONSE_MAGNITUDE / 128; + int16_t howmuch = THERM_FLOOR - pt; + // try to send out a warning (unless voltage is low) + // (LVP and underheat warnings fight each other) + if (voltage > VOLTAGE_LOW) + emit(EV_temperature_low, howmuch); } } } - #endif // ifdef USE_THERMAL_REGULATION - - - // set the correct type of measurement for next time - #ifdef USE_THERMAL_REGULATION - #ifdef USE_LVP - if (adc_step < 2) set_admux_voltage(); - else set_admux_therm(); - #else - set_admux_therm(); - #endif - #else - #ifdef USE_LVP - set_admux_voltage(); - #endif - #endif - - #ifdef TICK_DURING_STANDBY - // if we were asleep, go back to sleep - if (go_to_standby) ADC_off(); - #endif } +#endif + #ifdef USE_BATTCHECK #ifdef BATTCHECK_4bars diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index 274fb4d..6e39750 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -38,9 +38,18 @@ #define VOLTAGE_FUDGE_FACTOR 5 #endif #endif + +volatile uint8_t irq_adc = 0; // ADC interrupt happened? +volatile uint8_t irq_adc_stable = 0; // have we passed the 1st junk value yet? +uint8_t adc_channel = 0; // 0=voltage, 1=temperature +uint16_t adc_values[2]; // last ADC measurements (0=voltage, 1=temperature) +uint8_t adcint_enable = 0; // is the current ADC result needed? +void ADC_inner(); // do the actual ADC-related calculations + +static inline void ADC_voltage_handler(); 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 @@ -50,7 +59,7 @@ void battcheck(); #define USE_BLINK_DIGIT #endif #endif -#endif +#endif // ifdef USE_LVP #ifdef USE_THERMAL_REGULATION @@ -79,7 +88,8 @@ int8_t therm_cal_offset = 0; //void low_temperature(); //void high_temperature(); volatile uint8_t reset_thermal_history = 1; -#endif +static inline void ADC_temperature_handler(); +#endif // ifdef USE_THERMAL_REGULATION inline void ADC_on(); diff --git a/spaghetti-monster/fsm-events.c b/spaghetti-monster/fsm-events.c index f35607d..a1b013a 100644 --- a/spaghetti-monster/fsm-events.c +++ b/spaghetti-monster/fsm-events.c @@ -20,6 +20,8 @@ #ifndef FSM_EVENTS_C #define FSM_EVENTS_C +#include <util/delay_basic.h> + void empty_event_sequence() { current_event = EV_none; @@ -108,7 +110,7 @@ uint8_t nice_delay_ms(uint16_t ms) { /* // delay_zero() implementation if (ms == 0) { CLKPR = 1<<CLKPCE; CLKPR = 0; // full speed - _delay_loop_2(BOGOMIPS*98/100/3); + _delay_loop_2(BOGOMIPS*95/100/3); return 1; } */ @@ -118,15 +120,15 @@ uint8_t nice_delay_ms(uint16_t ms) { uint8_t level = actual_level; // volatile, avoid repeat access if (level < QUARTERSPEED_LEVEL) { clock_prescale_set(clock_div_4); - _delay_loop_2(BOGOMIPS*98/100/4); + _delay_loop_2(BOGOMIPS*95/100/4); } //else if (level < HALFSPEED_LEVEL) { // clock_prescale_set(clock_div_2); - // _delay_loop_2(BOGOMIPS*98/100/2); + // _delay_loop_2(BOGOMIPS*95/100/2); //} else { clock_prescale_set(clock_div_1); - _delay_loop_2(BOGOMIPS*98/100); + _delay_loop_2(BOGOMIPS*95/100); } // restore regular clock speed clock_prescale_set(clock_div_1); @@ -134,15 +136,18 @@ uint8_t nice_delay_ms(uint16_t ms) { // underclock MCU to save power clock_prescale_set(clock_div_4); // wait - _delay_loop_2(BOGOMIPS*98/100/4); + _delay_loop_2(BOGOMIPS*95/100/4); // restore regular clock speed clock_prescale_set(clock_div_1); #endif // ifdef USE_RAMPING #else // wait - _delay_loop_2(BOGOMIPS*98/100); + _delay_loop_2(BOGOMIPS*95/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..c9ab69b 100644 --- a/spaghetti-monster/fsm-main.c +++ b/spaghetti-monster/fsm-main.c @@ -123,7 +123,6 @@ int main() { #else delay_4ms(1); #endif - empty_event_sequence(); // fallback for handling a few things #ifndef DONT_USE_DEFAULT_STATE @@ -160,6 +159,9 @@ int main() { standby_mode(); } + // catch up on interrupts + handle_deferred_interrupts(); + // give the recipe some time slices loop(); @@ -168,4 +170,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..beab1a2 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_stable = 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 diff --git a/spaghetti-monster/meteor/meteor.c b/spaghetti-monster/meteor/meteor.c index 5e925e2..7d854a1 100644 --- a/spaghetti-monster/meteor/meteor.c +++ b/spaghetti-monster/meteor/meteor.c @@ -22,7 +22,6 @@ #define USE_LVP #define USE_THERMAL_REGULATION #define DEFAULT_THERM_CEIL 45 -#define USE_DELAY_4MS #define USE_RAMPING #define RAMP_LENGTH 150 #define USE_BATTCHECK @@ -48,12 +48,14 @@ void _delay_zero() { } #endif #ifdef USE_DELAY_4MS +#ifndef delay_4ms #define delay_4ms _delay_4ms void _delay_4ms(uint8_t n) // because it saves a bit of ROM space to do it this way { while(n-- > 0) _delay_loop_2(BOGOMIPS*4); } #endif +#endif #ifdef USE_DELAY_S #define delay_s _delay_s void _delay_s() // because it saves a bit of ROM space to do it this way |
