aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSelene ToyKeeper2019-11-24 16:21:40 -0700
committerSelene ToyKeeper2019-11-24 16:21:40 -0700
commit30510a7948815f3092b8a2eff3321ad85ed5c480 (patch)
tree4a1b68628c779bf4092a64ae027917529d03e158
parentmerged changes from fsm branch, including version check and stuck-button safety (diff)
parentadded -fwhole-program gcc flag, suggested by Agro. Signficantly reduces ROM ... (diff)
downloadanduril-30510a7948815f3092b8a2eff3321ad85ed5c480.tar.gz
anduril-30510a7948815f3092b8a2eff3321ad85ed5c480.tar.bz2
anduril-30510a7948815f3092b8a2eff3321ad85ed5c480.zip
merged from upstream fsm branch to get a whole bunch of kernel-level improvements
-rwxr-xr-xbin/build.sh2
-rw-r--r--spaghetti-monster/anduril/anduril.c58
-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-d4s.h1
-rw-r--r--spaghetti-monster/anduril/cfg-emisar-d4sv2.h4
-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/darkhorse/darkhorse.c1
-rw-r--r--spaghetti-monster/fsm-adc.c478
-rw-r--r--spaghetti-monster/fsm-adc.h16
-rw-r--r--spaghetti-monster/fsm-events.c17
-rw-r--r--spaghetti-monster/fsm-main.c38
-rw-r--r--spaghetti-monster/fsm-main.h2
-rw-r--r--spaghetti-monster/fsm-pcint.c24
-rw-r--r--spaghetti-monster/fsm-pcint.h1
-rw-r--r--spaghetti-monster/fsm-standby.c25
-rw-r--r--spaghetti-monster/fsm-wdt.c73
-rw-r--r--spaghetti-monster/fsm-wdt.h4
-rw-r--r--spaghetti-monster/meteor/meteor.c1
-rw-r--r--tk-delay.h2
21 files changed, 446 insertions, 318 deletions
diff --git a/bin/build.sh b/bin/build.sh
index fbb24ea..3992c38 100755
--- a/bin/build.sh
+++ b/bin/build.sh
@@ -14,7 +14,7 @@ export PROGRAM=$1 ; shift
export MCU=attiny$ATTINY
export CC=avr-gcc
export OBJCOPY=avr-objcopy
-export CFLAGS="-Wall -g -Os -mmcu=$MCU -c -std=gnu99 -fgnu89-inline -DATTINY=$ATTINY -I.. -I../.. -I../../.. -fshort-enums"
+export CFLAGS="-Wall -g -Os -mmcu=$MCU -c -std=gnu99 -fgnu89-inline -fwhole-program -DATTINY=$ATTINY -I.. -I../.. -I../../.. -fshort-enums"
export OFLAGS="-Wall -g -Os -mmcu=$MCU"
export LDFLAGS="-fgnu89-inline"
export OBJCOPYFLAGS='--set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex'
diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c
index 9f87dff..4a61da3 100644
--- a/spaghetti-monster/anduril/anduril.c
+++ b/spaghetti-monster/anduril/anduril.c
@@ -90,6 +90,8 @@
// so don't enable them at the same time as any of the above strobes)
//#define USE_POLICE_STROBE_MODE
//#define USE_SOS_MODE
+//#define USE_SOS_MODE_IN_FF_GROUP // put SOS in the "boring strobes" mode
+//#define USE_SOS_MODE_IN_BLINKY_GROUP // put SOS in the blinkies mode group
/***** specific settings for known driver types *****/
#include "tk.h"
@@ -146,7 +148,7 @@
#define USE_STROBE_STATE
#endif
-#if defined(USE_POLICE_STROBE_MODE) || defined(USE_SOS_MODE)
+#if defined(USE_POLICE_STROBE_MODE) || defined(USE_SOS_MODE_IN_FF_GROUP)
#define USE_BORING_STROBE_STATE
#endif
@@ -282,6 +284,10 @@ uint8_t goodnight_state(Event event, uint16_t arg);
uint8_t beacon_state(Event event, uint16_t arg);
uint8_t beacon_config_state(Event event, uint16_t arg);
#endif
+#ifdef USE_SOS_MODE_IN_BLINKY_GROUP
+// automatic SOS emergency signal
+uint8_t sos_state(Event event, uint16_t arg);
+#endif
// soft lockout
#define MOON_DURING_LOCKOUT_MODE
// if enabled, 2nd lockout click goes to the other ramp's floor level
@@ -1507,8 +1513,29 @@ inline void police_strobe_iter() {
}
}
#endif
+#endif // #ifdef USE_BORING_STROBE_STATE
#ifdef USE_SOS_MODE
+#ifdef USE_SOS_MODE_IN_BLINKY_GROUP
+uint8_t sos_state(Event event, uint16_t arg) {
+ // 1 click: off
+ if (event == EV_1click) {
+ set_state(off_state, 0);
+ return MISCHIEF_MANAGED;
+ }
+ // 2 clicks: next mode
+ else if (event == EV_2clicks) {
+ #ifdef USE_THERMAL_REGULATION
+ set_state(tempcheck_state, 0);
+ #else
+ set_state(battcheck_state, 0);
+ #endif
+ return MISCHIEF_MANAGED;
+ }
+ return EVENT_NOT_HANDLED;
+}
+#endif
+
void sos_blink(uint8_t num, uint8_t dah) {
#define DIT_LENGTH 200
for (; num > 0; num--) {
@@ -1527,14 +1554,13 @@ void sos_blink(uint8_t num, uint8_t dah) {
inline void sos_mode_iter() {
// one iteration of main loop()
- nice_delay_ms(1000);
+ //nice_delay_ms(1000);
sos_blink(3, 0); // S
sos_blink(3, 1); // O
sos_blink(3, 0); // S
- nice_delay_ms(1000);
+ nice_delay_ms(2000);
}
#endif // #ifdef USE_SOS_MODE
-#endif // #ifdef USE_BORING_STROBE_STATE
#ifdef USE_BATTCHECK
@@ -1585,9 +1611,11 @@ uint8_t beacon_state(Event event, uint16_t arg) {
}
// TODO: use sleep ticks to measure time between pulses,
// to save power
- // 2 clicks: tempcheck mode
+ // 2 clicks: next mode
else if (event == EV_2clicks) {
- #ifdef USE_THERMAL_REGULATION
+ #ifdef USE_SOS_MODE_IN_BLINKY_GROUP
+ set_state(sos_state, 0);
+ #elif defined(USE_THERMAL_REGULATION)
set_state(tempcheck_state, 0);
#else
set_state(battcheck_state, 0);
@@ -2381,7 +2409,7 @@ void rgb_led_update(uint8_t mode, uint8_t arg) {
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;
@@ -2389,9 +2417,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;
@@ -2412,14 +2440,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);
}
}
}
@@ -2671,7 +2699,7 @@ void loop() {
break;
#endif
- #ifdef USE_SOS_MODE
+ #ifdef USE_SOS_MODE_IN_FF_GROUP
default: // SOS
sos_mode_iter();
break;
@@ -2692,6 +2720,12 @@ void loop() {
}
#endif
+ #ifdef USE_SOS_MODE_IN_BLINKY_GROUP
+ else if (state == sos_state) {
+ sos_mode_iter();
+ }
+ #endif
+
#ifdef USE_THERMAL_REGULATION
// TODO: blink out therm_ceil during thermal_config_state?
else if (state == tempcheck_state) {
diff --git a/spaghetti-monster/anduril/cfg-blf-lantern.h b/spaghetti-monster/anduril/cfg-blf-lantern.h
index bf183eb..bdcd893 100644
--- a/spaghetti-monster/anduril/cfg-blf-lantern.h
+++ b/spaghetti-monster/anduril/cfg-blf-lantern.h
@@ -54,6 +54,9 @@
#define MUGGLE_FLOOR 15 // about 20 lm
#define MUGGLE_CEILING 115 // about 350 lm
+#define USE_SOS_MODE
+#define USE_SOS_MODE_IN_BLINKY_GROUP
+
// 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..31c22ff 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-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.h b/spaghetti-monster/anduril/cfg-emisar-d4sv2.h
index acc9101..c47e774 100644
--- a/spaghetti-monster/anduril/cfg-emisar-d4sv2.h
+++ b/spaghetti-monster/anduril/cfg-emisar-d4sv2.h
@@ -61,3 +61,7 @@
// 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 d0d2cf6..3da877e 100644
--- a/spaghetti-monster/anduril/cfg-emisar-d4v2.h
+++ b/spaghetti-monster/anduril/cfg-emisar-d4v2.h
@@ -53,3 +53,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..22b497b 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/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 6832e32..4ee2018 100644
--- a/spaghetti-monster/fsm-adc.c
+++ b/spaghetti-monster/fsm-adc.c
@@ -21,7 +21,7 @@
#define FSM_ADC_C
-inline void set_admux_therm() {
+static inline void set_admux_therm() {
#if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634)
ADMUX = ADMUX_THERM;
#elif (ATTINY == 841)
@@ -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() {
@@ -106,43 +108,165 @@ static inline uint8_t calc_voltage_divider(uint16_t value) {
}
#endif
-// Each full cycle runs 7.8X per second with just voltage enabled,
-// or 3.9X per second with voltage and temperature.
+// Each full cycle runs 15.6X per second with just voltage enabled,
+// or 7.8X per second with voltage and temperature.
#if defined(USE_LVP) && defined(USE_THERMAL_REGULATION)
-#define ADC_CYCLES_PER_SECOND 4
-#else
#define ADC_CYCLES_PER_SECOND 8
+#else
+#define ADC_CYCLES_PER_SECOND 16
+#endif
+
+#ifdef USE_THERMAL_REGULATION
+#define ADC_STEPS 2
+#else
+#define ADC_STEPS 1
#endif
-// TODO: is this better done in main() or WDT()?
+
+// 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 ((2*ADC_CYCLES_PER_SECOND)-1)
+ #elif (THERMAL_UPDATE_SPEED == 2) // new value every 2s
+ #define THERM_HISTORY_STEP_MAX (ADC_CYCLES_PER_SECOND-1)
+ #elif (THERMAL_UPDATE_SPEED == 1) // new value every 1s
+ #define THERM_HISTORY_STEP_MAX ((ADC_CYCLES_PER_SECOND/2)-1)
+ #elif (THERMAL_UPDATE_SPEED == 0) // new value every 0.5s
+ #define THERM_HISTORY_STEP_MAX ((ADC_CYCLES_PER_SECOND/4)-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
- 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 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..4ad1e16 100644
--- a/spaghetti-monster/fsm-main.c
+++ b/spaghetti-monster/fsm-main.c
@@ -37,7 +37,7 @@ ISR(TIMER1_COMPA_vect) {
#endif
#if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85)
-inline void hw_setup() {
+static inline void hw_setup() {
// configure PWM channels
#if PWM_CHANNELS >= 1
DDRB |= (1 << PWM1_PIN);
@@ -69,7 +69,7 @@ inline void hw_setup() {
PCMSK = (1 << SWITCH_PIN); // pin change interrupt uses this pin
}
#elif (ATTINY == 1634)
-inline void hw_setup() {
+static inline void hw_setup() {
// this gets tricky with so many pins...
// ... so punt it to the hwdef file
hwdef_setup();
@@ -79,22 +79,24 @@ inline void hw_setup() {
#endif
-#ifdef USE_REBOOT
-void prevent_reboot_loop() {
+//#ifdef USE_REBOOT
+static inline void prevent_reboot_loop() {
// prevent WDT from rebooting MCU again
MCUSR &= ~(1<<WDRF); // reset status flag
wdt_disable();
}
-#endif
+//#endif
int main() {
// Don't allow interrupts while booting
cli();
- #ifdef USE_REBOOT
+ //#ifdef USE_REBOOT
+ // prevents cycling after a crash,
+ // whether intentional (like factory reset) or not (bugs)
prevent_reboot_loop();
- #endif
+ //#endif
hw_setup();
@@ -123,7 +125,6 @@ int main() {
#else
delay_4ms(1);
#endif
- empty_event_sequence();
// fallback for handling a few things
#ifndef DONT_USE_DEFAULT_STATE
@@ -160,6 +161,9 @@ int main() {
standby_mode();
}
+ // catch up on interrupts
+ handle_deferred_interrupts();
+
// give the recipe some time slices
loop();
@@ -168,4 +172,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..1ba1c15 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
@@ -104,8 +97,7 @@ void PCINT_inner(uint8_t pressed) {
pushed = push_event(B_RELEASE);
}
- // check if sequence matches any defined sequences
- // if so, send event to current state callback
+ // send event to the current state callback
if (pushed) {
button_last_state = pressed;
emit_current_event(0);
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..9398f52 100644
--- a/spaghetti-monster/fsm-standby.c
+++ b/spaghetti-monster/fsm-standby.c
@@ -42,16 +42,19 @@ 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
+
// configure sleep mode
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
@@ -65,10 +68,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
@@ -78,7 +90,10 @@ void sleep_until_eswitch_pressed()
#endif
// go back to normal running mode
- //PCINT_on(); // should be on already
+ // PCINT not needed any more, and can cause problems if on
+ // (occasional reboots on wakeup-by-button-press)
+ PCINT_off();
+ // restore normal awake-mode interrupts
ADC_on();
WDT_on();
}
diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c
index 6e61e87..0c49a75 100644
--- a/spaghetti-monster/fsm-wdt.c
+++ b/spaghetti-monster/fsm-wdt.c
@@ -82,46 +82,52 @@ 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
+ // cache this here to reduce ROM size, because it's volatile
+ uint16_t ticks_since_last = ticks_since_last_event;
+ // increment, but loop from max back to half
+ ticks_since_last = (ticks_since_last + 1) \
+ | (ticks_since_last & 0x8000);
+ // copy back to the original
+ ticks_since_last_event = ticks_since_last;
+
+ // 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);
+ }
+ // cache again, in case the value changed
+ ticks_since_last = ticks_since_last_event;
- static uint16_t sleep_counter = 0;
+ #ifdef TICK_DURING_STANDBY
// handle standby mode specially
if (go_to_standby) {
// emit a halfsleep tick, and process it
- emit(EV_sleep_tick, sleep_counter);
- // wrap around from 65535 to 32768, not 0
- sleep_counter = (sleep_counter + 1) | (sleep_counter & 0x8000);
+ emit(EV_sleep_tick, ticks_since_last);
process_emissions();
- #if defined(USE_SLEEP_LVP)
+ #ifndef USE_SLEEP_LVP
+ return; // no sleep LVP needed if nothing drains power while off
+ #else
// stop here, usually... but proceed often enough for sleep LVP to work
- if (0 != (sleep_counter & 0x7f)) return;
+ if (0 != (ticks_since_last & 0x7f)) return;
+
adc_trigger = 255; // make sure a measurement will happen
- #else
- return; // no sleep LVP needed if nothing drains power while off
+ ADC_on(); // enable ADC voltage measurement functions temporarily
#endif
}
- else { sleep_counter = 0; }
+ else { // button handling should only happen while awake
#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;
-
- // increment, but loop from max back to half
- //if (ticks_since_last < 0xff) ticks_since_last ++;
- ticks_since_last = (ticks_since_last + 1) \
- | (ticks_since_last & 0x8000);
- // copy back to the original
- ticks_since_last_event = ticks_since_last;
-
// if time since last event exceeds timeout,
// append timeout to current event sequence, then
// send event to current state callback
@@ -141,9 +147,9 @@ ISR(WDT_vect) {
emit_current_event(ticks_since_last);
}
// has button been down long enough to become a "hold"?
+ // (first frame of a "hold" event)
else {
if (ticks_since_last >= HOLD_TIMEOUT) {
- //ticks_since_last_event = 0;
current_event |= B_HOLD;
emit_current_event(0);
}
@@ -156,28 +162,27 @@ ISR(WDT_vect) {
// no timeout required when releasing a long-press
// TODO? move this logic to PCINT() and simplify things here?
if (current_event & B_HOLD) {
- //emit_current_event(0); // should have been emitted by PCINT
+ //emit_current_event(0); // should have been emitted by PCINT_inner()
empty_event_sequence();
}
// end and clear event after release timeout
else if (ticks_since_last >= RELEASE_TIMEOUT) {
current_event |= B_TIMEOUT;
- //ticks_since_last_event = 0;
emit_current_event(0);
empty_event_sequence();
}
}
+ #ifdef TICK_DURING_STANDBY
+ }
+ #endif
+
#if defined(USE_LVP) || defined(USE_THERMAL_REGULATION)
// start a new ADC measurement every 4 ticks
adc_trigger ++;
if (0 == (adc_trigger & 3)) {
- #if defined(TICK_DURING_STANDBY) && defined(USE_SLEEP_LVP)
- // we shouldn't be here unless it woke up for a LVP check...
- // so enable ADC voltage measurement functions temporarily
- 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
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.