aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSelene ToyKeeper2019-11-14 19:47:49 -0700
committerSelene ToyKeeper2019-11-14 19:47:49 -0700
commit5362c032fdca4b20af49db0409a03524a396b815 (patch)
tree1d437085b5b3472279167aee905385e39a4a1fe1
parentmerged from fsm branch to get safety ramp-down and version check functions, a... (diff)
parentmerged irq-refactor branch, which fixes some small but long-standing issues: (diff)
downloadanduril-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 '')
-rw-r--r--hwdef-Emisar_D4Sv2.h124
-rw-r--r--spaghetti-monster/anduril/anduril.c10
-rw-r--r--spaghetti-monster/anduril/cfg-blf-lantern.h3
-rw-r--r--spaghetti-monster/anduril/cfg-blf-q8.h5
-rw-r--r--spaghetti-monster/anduril/cfg-emisar-d1sv2.h5
-rw-r--r--spaghetti-monster/anduril/cfg-emisar-d4s.h1
-rw-r--r--spaghetti-monster/anduril/cfg-emisar-d4sv2-219.h10
-rw-r--r--spaghetti-monster/anduril/cfg-emisar-d4sv2.h67
-rw-r--r--spaghetti-monster/anduril/cfg-emisar-d4v2.h3
-rw-r--r--spaghetti-monster/anduril/cfg-mateminco-mf01s.h6
-rw-r--r--spaghetti-monster/anduril/version.h4
-rw-r--r--spaghetti-monster/darkhorse/darkhorse.c1
-rw-r--r--spaghetti-monster/fsm-adc.c468
-rw-r--r--spaghetti-monster/fsm-adc.h16
-rw-r--r--spaghetti-monster/fsm-events.c17
-rw-r--r--spaghetti-monster/fsm-main.c22
-rw-r--r--spaghetti-monster/fsm-main.h2
-rw-r--r--spaghetti-monster/fsm-pcint.c21
-rw-r--r--spaghetti-monster/fsm-pcint.h1
-rw-r--r--spaghetti-monster/fsm-standby.c19
-rw-r--r--spaghetti-monster/fsm-wdt.c22
-rw-r--r--spaghetti-monster/fsm-wdt.h4
-rw-r--r--spaghetti-monster/meteor/meteor.c1
-rw-r--r--tk-delay.h2
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
diff --git a/tk-delay.h b/tk-delay.h
index 7b00ac0..29cf463 100644
--- a/tk-delay.h
+++ b/tk-delay.h
@@ -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