diff options
| author | Selene ToyKeeper | 2020-03-16 03:57:19 -0600 |
|---|---|---|
| committer | Selene ToyKeeper | 2020-03-16 03:57:19 -0600 |
| commit | 15fe735df7edf31ac388c2ffd65020216e1a70aa (patch) | |
| tree | 8f8b1668ccb555dc4825ccbd9f4ac0487401b5cf /spaghetti-monster | |
| parent | added FETless KR4 build target, calibrated other KR4 therm faster level better (diff) | |
| parent | merged adc-rework branch, which rewrote all ADC code (voltage, temperature, a... (diff) | |
| download | anduril-15fe735df7edf31ac388c2ffd65020216e1a70aa.tar.gz anduril-15fe735df7edf31ac388c2ffd65020216e1a70aa.tar.bz2 anduril-15fe735df7edf31ac388c2ffd65020216e1a70aa.zip | |
merged fsm branch (to get adc-rework branch with new thermal regulation)
Diffstat (limited to 'spaghetti-monster')
23 files changed, 358 insertions, 401 deletions
diff --git a/spaghetti-monster/anduril/anduril-manual.txt b/spaghetti-monster/anduril/anduril-manual.txt index 3f17f41..97e6589 100644 --- a/spaghetti-monster/anduril/anduril-manual.txt +++ b/spaghetti-monster/anduril/anduril-manual.txt @@ -147,7 +147,7 @@ In more detail, this is what each blinky / utility mode does: can reach before it will start doing thermal regulation to keep itself from overheating. Click once per degree C above 30. For example, to set the limit to 50 C, click 20 times. The default - is 45 C. + is 45 C, and the highest value it will allow is 70 C. Strobe / Mood Modes diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 9348262..cb48b45 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -22,7 +22,7 @@ // Anduril config file name (set it here or define it at the gcc command line) //#define CONFIGFILE cfg-blf-q8.h -#define USE_LVP // FIXME: won't build when this option is turned off +#define USE_LVP // parameters for this defined below or per-driver #define USE_THERMAL_REGULATION @@ -278,6 +278,7 @@ void sos_blink(uint8_t num, uint8_t dah); uint8_t battcheck_state(Event event, uint16_t arg); #endif #ifdef USE_THERMAL_REGULATION +#define USE_BLINK_NUM uint8_t tempcheck_state(Event event, uint16_t arg); uint8_t thermal_config_state(Event event, uint16_t arg); #endif @@ -511,6 +512,7 @@ volatile uint8_t beacon_seconds = 2; #endif #ifdef USE_VERSION_CHECK +#define USE_BLINK_DIGIT #include "version.h" const PROGMEM uint8_t version_number[] = VERSION_NUMBER; uint8_t version_check_state(Event event, uint16_t arg); @@ -973,59 +975,34 @@ uint8_t steady_state(Event event, uint16_t arg) { if (arg == TICKS_PER_SECOND) ramp_direction = 1; #endif #ifdef USE_SET_LEVEL_GRADUALLY - // make thermal adjustment speed scale with magnitude - // also, adjust slower when going up - if ((arg & 1) && - ((actual_level < THERM_FASTER_LEVEL) || - (actual_level < gradual_target))) { - return MISCHIEF_MANAGED; // adjust slower when not a high mode - } - #ifdef THERM_HARD_TURBO_DROP - else if ((! (actual_level < THERM_FASTER_LEVEL)) - && (actual_level > gradual_target)) { - gradual_tick(); - } - else { - #endif - // [int(62*4 / (x**0.8)) for x in (1,2,4,8,16,32,64,128)] - //uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5}; - // [int(62*4 / (x**0.9)) for x in (1,2,4,8,16,32,64,128)] - //uint8_t intervals[] = {248, 132, 71, 38, 20, 10, 5, 3}; - // [int(62*4 / (x**0.95)) for x in (1,2,4,8,16,32,64,128)] - uint8_t intervals[] = {248, 128, 66, 34, 17, 9, 4, 2}; - uint8_t diff; - static uint8_t ticks_since_adjust = 0; - if (gradual_target > actual_level) { - // rise at half speed (skip half the frames) - if (arg & 2) return MISCHIEF_MANAGED; - diff = gradual_target - actual_level; - } else { - diff = actual_level - gradual_target; - } - ticks_since_adjust ++; - // if there's any adjustment to be made, make it + int16_t diff = gradual_target - actual_level; + static uint16_t ticks_since_adjust = 0; + ticks_since_adjust++; if (diff) { - uint8_t magnitude = 0; - #ifndef THERM_HARD_TURBO_DROP - // if we're on a really high mode, drop faster - if ((actual_level >= THERM_FASTER_LEVEL) - && (actual_level > gradual_target)) { magnitude ++; } - #endif + uint16_t ticks_per_adjust = 256; + if (diff < 0) { + //diff = -diff; + if (actual_level > THERM_FASTER_LEVEL) { + #ifdef THERM_HARD_TURBO_DROP + ticks_per_adjust >>= 2; + #endif + ticks_per_adjust >>= 2; + } + } else { + // rise at half speed + ticks_per_adjust <<= 1; + } while (diff) { - magnitude ++; - diff >>= 1; + ticks_per_adjust >>= 1; + //diff >>= 1; + diff /= 2; // because shifting produces weird behavior } - uint8_t ticks_per_adjust = intervals[magnitude]; if (ticks_since_adjust > ticks_per_adjust) { gradual_tick(); ticks_since_adjust = 0; } - //if (!(arg % ticks_per_adjust)) gradual_tick(); } - #ifdef THERM_HARD_TURBO_DROP - } - #endif #endif // ifdef USE_SET_LEVEL_GRADUALLY return MISCHIEF_MANAGED; } @@ -1078,6 +1055,18 @@ uint8_t steady_state(Event event, uint16_t arg) { } return MISCHIEF_MANAGED; } + #ifdef USE_SET_LEVEL_GRADUALLY + // temperature is within target window + // (so stop trying to adjust output) + else if (event == EV_temperature_okay) { + // if we're still adjusting output... stop after the current step + if (gradual_target > actual_level) + gradual_target = actual_level + 1; + else if (gradual_target < actual_level) + gradual_target = actual_level - 1; + return MISCHIEF_MANAGED; + } + #endif // ifdef USE_SET_LEVEL_GRADUALLY #endif // ifdef USE_THERMAL_REGULATION return EVENT_NOT_HANDLED; } @@ -1618,11 +1607,13 @@ uint8_t tempcheck_state(Event event, uint16_t arg) { set_state(off_state, 0); return MISCHIEF_MANAGED; } + #ifdef USE_BATTCHECK // 2 clicks: battcheck mode else if (event == EV_2clicks) { set_state(battcheck_state, 0); return MISCHIEF_MANAGED; } + #endif // 4 clicks: thermal config mode else if (event == EV_4clicks) { push_state(thermal_config_state, 0); @@ -1648,7 +1639,7 @@ uint8_t beacon_state(Event event, uint16_t arg) { set_state(sos_state, 0); #elif defined(USE_THERMAL_REGULATION) set_state(tempcheck_state, 0); - #else + #elif defined(USE_BATTCHECK) set_state(battcheck_state, 0); #endif return MISCHIEF_MANAGED; @@ -2040,6 +2031,7 @@ uint8_t muggle_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif + #ifdef USE_LVP // low voltage is handled specially in muggle mode else if(event == EV_voltage_low) { uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); @@ -2050,6 +2042,7 @@ uint8_t muggle_state(Event event, uint16_t arg) { } return MISCHIEF_MANAGED; } + #endif return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/anduril/cfg-emisar-d18.h b/spaghetti-monster/anduril/cfg-emisar-d18.h index 16fbacd..155a747 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d18.h +++ b/spaghetti-monster/anduril/cfg-emisar-d18.h @@ -42,5 +42,3 @@ // stop panicking at about ~40% power or ~5000 lm #define THERM_FASTER_LEVEL 125 -// optional, makes initial turbo step-down faster so first peak isn't as hot -//#define THERM_HARD_TURBO_DROP diff --git a/spaghetti-monster/anduril/cfg-emisar-d4.h b/spaghetti-monster/anduril/cfg-emisar-d4.h index c86a534..501b9c7 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4.h @@ -24,8 +24,4 @@ // stop panicking at ~30% power or ~1200 lm #define THERM_FASTER_LEVEL 105 -// respond to thermal changes faster -#define THERMAL_WARNING_SECONDS 3 -#define THERMAL_UPDATE_SPEED 1 -#define THERM_PREDICTION_STRENGTH 4 diff --git a/spaghetti-monster/anduril/cfg-emisar-d4s.h b/spaghetti-monster/anduril/cfg-emisar-d4s.h index 6fe95a6..88465da 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4s.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4s.h @@ -42,8 +42,3 @@ #ifdef THERM_HARD_TURBO_DROP #undef THERM_HARD_TURBO_DROP #endif - -#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 c47e774..c578c4a 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4sv2.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4sv2.h @@ -42,16 +42,6 @@ // 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 @@ -61,7 +51,3 @@ // 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 3da877e..241ca7e 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4v2.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4v2.h @@ -37,22 +37,10 @@ #define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL #define RAMP_DISCRETE_STEPS 7 -// optional, makes initial turbo step-down faster so first peak isn't as hot -// the D4 runs very very hot, so be extra careful -//#define THERM_HARD_TURBO_DROP - // stop panicking at ~30% power or ~1200 lm #define THERM_FASTER_LEVEL 105 -// respond to thermal changes faster -#define THERMAL_WARNING_SECONDS 3 -#define THERMAL_UPDATE_SPEED 1 -#define THERM_PREDICTION_STRENGTH 4 -//#define THERM_RESPONSE_MAGNITUDE 128 // easier access to thermal config mode, for Emisar #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-ff-pl47.h b/spaghetti-monster/anduril/cfg-ff-pl47.h index 7a81c25..e6907c1 100644 --- a/spaghetti-monster/anduril/cfg-ff-pl47.h +++ b/spaghetti-monster/anduril/cfg-ff-pl47.h @@ -61,11 +61,6 @@ // regulate down faster when the FET is active, slower otherwise #define THERM_FASTER_LEVEL 135 // throttle back faster when high -// play it safe, don't try to regulate above the recommended safe level -#ifdef THERM_HARD_TURBO_DROP -#undef THERM_HARD_TURBO_DROP -#endif - // don't do this #undef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_CEILING diff --git a/spaghetti-monster/anduril/cfg-ff-pl47g2.h b/spaghetti-monster/anduril/cfg-ff-pl47g2.h index d5dd79d..cab008c 100644 --- a/spaghetti-monster/anduril/cfg-ff-pl47g2.h +++ b/spaghetti-monster/anduril/cfg-ff-pl47g2.h @@ -49,11 +49,6 @@ // regulate down faster when the FET is active, slower otherwise #define THERM_FASTER_LEVEL 135 // throttle back faster when high -// hard drop doesn't seem to be needed on this light -#ifdef THERM_HARD_TURBO_DROP -#undef THERM_HARD_TURBO_DROP -#endif - // don't do this #undef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_CEILING diff --git a/spaghetti-monster/anduril/cfg-ff-rot66.h b/spaghetti-monster/anduril/cfg-ff-rot66.h index 2a90343..a87b66d 100644 --- a/spaghetti-monster/anduril/cfg-ff-rot66.h +++ b/spaghetti-monster/anduril/cfg-ff-rot66.h @@ -38,9 +38,6 @@ // regulate down faster when the FET is active, slower otherwise #define THERM_FASTER_LEVEL 130 // throttle back faster when high -// play it safe, don't try to regulate above the recommended safe level -//#define THERM_HARD_TURBO_DROP - // don't do this #undef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_CEILING diff --git a/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h b/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h index bbf751b..28c77c2 100644 --- a/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h +++ b/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h @@ -48,8 +48,3 @@ #define USE_TENCLICK_THERMAL_CONFIG // by request #define THERM_FASTER_LEVEL 130 // throttle back faster when high -//#define THERM_HARD_TURBO_DROP // this light is massively overpowered -#define THERMAL_WARNING_SECONDS 1 // FIXME: increase by 2 after merging newer code -//#define THERMAL_UPDATE_SPEED 1 -//#define THERM_PREDICTION_STRENGTH 4 - diff --git a/spaghetti-monster/anduril/cfg-sofirn-sp36.h b/spaghetti-monster/anduril/cfg-sofirn-sp36.h index 494a263..d808e2a 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-sp36.h +++ b/spaghetti-monster/anduril/cfg-sofirn-sp36.h @@ -28,10 +28,3 @@ #undef THERM_FASTER_LEVEL #endif #define THERM_FASTER_LEVEL 130 - -// be extra-careful at high levels -// (or not... this host seems to heat up pretty slowly) -//#ifndef THERM_HARD_TURBO_DROP -//#define THERM_HARD_TURBO_DROP -//#endif - diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 2d8d01f..7880238 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -22,38 +22,48 @@ static inline void set_admux_therm() { - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634) + #if (ATTINY == 1634) ADMUX = ADMUX_THERM; - #elif (ATTINY == 841) + #elif (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) + ADMUX = ADMUX_THERM | (1 << ADLAR); + #elif (ATTINY == 841) // FIXME: not tested ADMUXA = ADMUXA_THERM; ADMUXB = ADMUXB_THERM; #else #error Unrecognized MCU type #endif adc_channel = 1; + adc_sample_count = 0; // first result is unstable + ADC_start_measurement(); } inline void set_admux_voltage() { - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634) - #ifdef USE_VOLTAGE_DIVIDER - // 1.1V / pin7 - ADMUX = ADMUX_VOLTAGE_DIVIDER; - #else - // VCC / 1.1V reference - ADMUX = ADMUX_VCC; + #if (ATTINY == 1634) + #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7 + ADMUX = ADMUX_VOLTAGE_DIVIDER; + #else // VCC / 1.1V reference + ADMUX = ADMUX_VCC; #endif - #elif (ATTINY == 841) - #ifdef USE_VOLTAGE_DIVIDER - ADMUXA = ADMUXA_VOLTAGE_DIVIDER; - ADMUXB = ADMUXB_VOLTAGE_DIVIDER; - #else - ADMUXA = ADMUXA_VCC; - ADMUXB = ADMUXB_VCC; + #elif (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) + #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7 + ADMUX = ADMUX_VOLTAGE_DIVIDER | (1 << ADLAR); + #else // VCC / 1.1V reference + ADMUX = ADMUX_VCC | (1 << ADLAR); + #endif + #elif (ATTINY == 841) // FIXME: not tested + #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7 + ADMUXA = ADMUXA_VOLTAGE_DIVIDER; + ADMUXB = ADMUXB_VOLTAGE_DIVIDER; + #else // VCC / 1.1V reference + ADMUXA = ADMUXA_VCC; + ADMUXB = ADMUXB_VCC; #endif #else #error Unrecognized MCU type #endif adc_channel = 0; + adc_sample_count = 0; // first result is unstable + ADC_start_measurement(); } inline void ADC_start_measurement() { @@ -70,24 +80,25 @@ inline void ADC_on() #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634) set_admux_voltage(); #ifdef USE_VOLTAGE_DIVIDER - // disable digital input on divider pin to reduce power consumption - VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); + // disable digital input on divider pin to reduce power consumption + VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); #else - // disable digital input on VCC pin to reduce power consumption - //VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); // FIXME: unsure how to handle for VCC pin + // disable digital input on VCC pin to reduce power consumption + //VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); // FIXME: unsure how to handle for VCC pin #endif #if (ATTINY == 1634) - ACSRA |= (1 << ACD); // turn off analog comparator to save power + //ACSRA |= (1 << ACD); // turn off analog comparator to save power + ADCSRB |= (1 << ADLAR); // left-adjust flag is here instead of ADMUX #endif - // enable, start, prescale - ADCSRA = (1 << ADEN) | (1 << ADSC) | ADC_PRSCL; + // enable, start, auto-retrigger, prescale + ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL; // end tiny25/45/85 - #elif (ATTINY == 841) + #elif (ATTINY == 841) // FIXME: not tested, missing left-adjust ADCSRB = 0; // Right adjusted, auto trigger bits cleared. //ADCSRA = (1 << ADEN ) | 0b011; // ADC on, prescaler division factor 8. set_admux_voltage(); - // enable, start, prescale - ADCSRA = (1 << ADEN) | (1 << ADSC) | ADC_PRSCL; + // enable, start, auto-retrigger, prescale + ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL; //ADCSRA |= (1 << ADSC); // start measuring #else #error Unrecognized MCU type @@ -101,110 +112,124 @@ inline void ADC_off() { #ifdef USE_VOLTAGE_DIVIDER static inline uint8_t calc_voltage_divider(uint16_t value) { // use 9.7 fixed-point to get sufficient precision - uint16_t adc_per_volt = ((ADC_44<<5) - (ADC_22<<5)) / (44-22); - // incoming value is 8.2 fixed-point, so shift it 2 bits less - uint8_t result = ((value<<5) / adc_per_volt) + VOLTAGE_FUDGE_FACTOR; + uint16_t adc_per_volt = ((ADC_44<<7) - (ADC_22<<7)) / (44-22); + // shift incoming value into a matching position + uint8_t result = ((value>>1) / adc_per_volt) + VOLTAGE_FUDGE_FACTOR; return result; } #endif -// Each full cycle runs 15.6X per second with just voltage enabled, -// or 7.8X per second with voltage and temperature. +// Each full cycle runs ~2X per second with just voltage enabled, +// or ~1X per second with voltage and temperature. #if defined(USE_LVP) && defined(USE_THERMAL_REGULATION) -#define ADC_CYCLES_PER_SECOND 8 +#define ADC_CYCLES_PER_SECOND 1 #else -#define ADC_CYCLES_PER_SECOND 16 -#endif - -#ifdef USE_THERMAL_REGULATION -#define ADC_STEPS 2 -#else -#define ADC_STEPS 1 +#define ADC_CYCLES_PER_SECOND 2 #endif // happens every time the ADC sampler finishes a measurement ISR(ADC_vect) { - #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 + if (adc_sample_count) { + + uint16_t m; // latest measurement + uint16_t s; // smoothed measurement + uint8_t channel = adc_channel; + + // update the latest value + m = ADC; + adc_raw[channel] = m; + + // lowpass the value + //s = adc_smooth[channel]; // easier to read + uint16_t *v = adc_smooth + channel; // compiles smaller + s = *v; + if (m > s) { s++; } + if (m < s) { s--; } + //adc_smooth[channel] = s; + *v = s; + + // track what woke us up, and enable deferred logic + irq_adc = 1; + } - irq_adc_stable = 1; - // start another measurement - // (is explicit because it otherwise doesn't seem to happen during standby mode) - ADC_start_measurement(); + // the next measurement isn't the first + adc_sample_count = 1; + // rollover doesn't really matter + //adc_sample_count ++; + } -void ADC_inner() { +void adc_deferred() { 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; + #ifdef USE_PSEUDO_RAND + // real-world entropy makes this a true random, not pseudo + // Why here instead of the ISR? Because it makes the time-critical ISR + // code a few cycles faster and we don't need crypto-grade randomness. + pseudo_rand_seed += (ADCL >> 6) + (ADCH << 2); + #endif + + // the ADC triggers repeatedly when it's on, but we only need to run the + // voltage and temperature regulation stuff once in a while...so disable + // this after each activation, until it's manually enabled again + if (! adc_deferred_enable) return; // disable after one iteration - adcint_enable = 0; + adc_deferred_enable = 0; - #ifdef TICK_DURING_STANDBY + // what is being measured? 0 = battery voltage, 1 = temperature + uint8_t adc_step; + + #if defined(USE_LVP) && defined(USE_THERMAL_REGULATION) + // do whichever one is currently active + adc_step = adc_channel; + #else + // unless there's no temperature sensor... then just do voltage + adc_step = 0; + #endif + + #if defined(TICK_DURING_STANDBY) && defined(USE_SLEEP_LVP) // 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(); + if (go_to_standby) { + ADC_off(); + // also, only check the battery while asleep, not the temperature + adc_channel = 0; + } #endif - // what is being measured? 0 = battery voltage, 1 = temperature - static uint8_t adc_step = 0; + if (0) {} // placeholder for easier syntax #ifdef USE_LVP - if (0 == adc_step) { // voltage + else if (0 == adc_step) { // voltage ADC_voltage_handler(); + #ifdef USE_THERMAL_REGULATION + // set the correct type of measurement for next time + if (! go_to_standby) set_admux_therm(); + #endif } #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 the correct type of measurement for next time set_admux_voltage(); #endif + } #endif - - irq_adc_stable = 0; // first result is unstable } #ifdef USE_LVP static inline void ADC_voltage_handler() { + // rate-limit low-voltage warnings to a max of 1 per N seconds 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 #ifdef NO_LVP_WHILE_BUTTON_PRESSED // don't run if button is currently being held @@ -212,21 +237,24 @@ static inline void ADC_voltage_handler() { if (button_last_state) return; #endif - uint16_t measurement = adc_values[0]; // latest 10-bit ADC reading + uint16_t measurement; - #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 + // latest ADC value + if (go_to_standby || (adc_smooth[0] < 255)) { + measurement = adc_raw[0]; + adc_smooth[0] = measurement; // no lowpass while asleep + } + else measurement = adc_smooth[0]; + + // values stair-step between intervals of 64, with random variations + // of 1 or 2 in either direction, so if we chop off the last 6 bits + // it'll flap between N and N-1... but if we add half an interval, + // the values should be really stable after right-alignment + // (instead of 99.98, 100.00, and 100.02, it'll hit values like + // 100.48, 100.50, and 100.52... which are stable when truncated) + //measurement += 32; + //measurement = (measurement + 16) >> 5; + measurement = (measurement + 16) & 0xffe0; // 1111 1111 1110 0000 #ifdef USE_VOLTAGE_DIVIDER voltage = calc_voltage_divider(measurement); @@ -234,32 +262,19 @@ static inline void ADC_voltage_handler() { // 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; + voltage = ((uint16_t)(2*1.1*1024*10)/(measurement>>6) + 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) + // (but only if it has been more than N seconds 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; + // send out a warning + emit(EV_voltage_low, 0); + // reset rate-limit counter + lvp_timer = LVP_TIMER_START; } } } @@ -267,146 +282,141 @@ static inline void ADC_voltage_handler() { #ifdef USE_THERMAL_REGULATION +// generally happens once per second while awake static inline void ADC_temperature_handler() { - // thermal declarations - #ifndef THERMAL_UPDATE_SPEED - #define THERMAL_UPDATE_SPEED 2 + // coarse adjustment + #ifndef THERM_LOOKAHEAD + #define THERM_LOOKAHEAD 4 // can be tweaked per build target #endif - #define NUM_THERMAL_VALUES_HISTORY 8 - 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; - static uint8_t overheat_lowpass = 0; - static uint8_t underheat_lowpass = 0; - #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 - - // TODO: left-shift this so the lowpass can get higher resolution - // TODO: increase the sampling rate, to keep the lowpass from lagging - uint16_t measurement = adc_values[1]; // latest 10-bit ADC reading + // reduce frequency of minor warnings + #ifndef THERM_NEXT_WARNING_THRESHOLD + #define THERM_NEXT_WARNING_THRESHOLD 24 + #endif + // fine-grained adjustment + // 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 2 + + // TODO: make this configurable per build target? + // (shorter time for hosts with a lower power-to-mass ratio) + // (because then it'll have smaller responses) + #define NUM_TEMP_HISTORY_STEPS 8 // don't change; it'll break stuff + static uint8_t history_step = 0; + static uint16_t temperature_history[NUM_TEMP_HISTORY_STEPS]; + static int8_t warning_threshold = 0; + + if (reset_thermal_history) { // wipe out old data + // don't keep resetting + reset_thermal_history = 0; - // Convert ADC units to Celsius (ish) - int16_t temp = measurement - 275 + THERM_CAL_OFFSET + (int16_t)therm_cal_offset; + // ignore average, use latest sample + uint16_t foo = adc_raw[1]; + adc_smooth[1] = foo; - // 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 --; - } + // forget any past measurements + for(uint8_t i=0; i<NUM_TEMP_HISTORY_STEPS; i++) + temperature_history[i] = (foo + 16) >> 5; } - // guess what the temperature will be in a few seconds - int16_t pt; - { - int16_t diff; - int16_t t = temperature; + // latest 16-bit ADC reading + uint16_t measurement = adc_smooth[1]; - // 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 (4*ADC_CYCLES_PER_SECOND) - #elif (THERMAL_UPDATE_SPEED == 2) // new value every 2s - #define THERM_HISTORY_STEP_MAX (2*ADC_CYCLES_PER_SECOND) - #elif (THERMAL_UPDATE_SPEED == 1) // new value every 1s - #define THERM_HISTORY_STEP_MAX (ADC_CYCLES_PER_SECOND) - #elif (THERMAL_UPDATE_SPEED == 0) // new value every 0.5s - #define THERM_HISTORY_STEP_MAX (ADC_CYCLES_PER_SECOND/2) - #endif - if (THERM_HISTORY_STEP_MAX == history_step) { - history_step = 0; - // 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; - } + // values stair-step between intervals of 64, with random variations + // of 1 or 2 in either direction, so if we chop off the last 6 bits + // it'll flap between N and N-1... but if we add half an interval, + // the values should be really stable after right-alignment + // (instead of 99.98, 100.00, and 100.02, it'll hit values like + // 100.48, 100.50, and 100.52... which are stable when truncated) + //measurement += 32; + measurement = (measurement + 16) >> 5; + //measurement = (measurement + 16) & 0xffe0; // 1111 1111 1110 0000 - // 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 --; + // let the UI see the current temperature in C + // Convert ADC units to Celsius (ish) + temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)therm_cal_offset - 275; + + // how much has the temperature changed between now and a few seconds ago? + int16_t diff; + diff = measurement - temperature_history[history_step]; + + // update / rotate the temperature history + temperature_history[history_step] = measurement; + history_step = (history_step + 1) & (NUM_TEMP_HISTORY_STEPS-1); + + // PI[D]: guess what the temperature will be in a few seconds + uint16_t pt; // predicted temperature + pt = measurement + (diff * THERM_LOOKAHEAD); + + // convert temperature limit from C to raw 16-bit ADC units + // C = (ADC>>6) - 275 + THERM_CAL_OFFSET + therm_cal_offset; + // ... so ... + // (C + 275 - THERM_CAL_OFFSET - therm_cal_offset) << 6 = ADC; + uint16_t ceil = (therm_ceil + 275 - therm_cal_offset - THERM_CAL_OFFSET) << 1; + int16_t offset = pt - ceil; + + // bias small errors toward zero, while leaving large errors mostly unaffected + // (a diff of 1 C is 2 ADC units, * 4 for therm lookahead, so it becomes 8) + // (but a diff of 1 C should only send a warning of magnitude 1) + // (this also makes it only respond to small errors at the time the error + // happened, not after the temperature has stabilized) + for(uint8_t foo=0; foo<5; foo++) { + if (offset > 0) { + offset --; + } else if (offset < 0) { + offset ++; } - // 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 } - 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 it's too hot and still getting warmer...) + if ((offset > 0) && (diff > 0)) { + // accumulated error isn't big enough yet to send a warning + if (warning_threshold > 0) { + warning_threshold -= offset; + } else { // error is big enough; send a warning + warning_threshold = THERM_NEXT_WARNING_THRESHOLD - offset; + + // how far above the ceiling? + //int16_t howmuch = offset * THERM_RESPONSE_MAGNITUDE / 128; + int16_t howmuch = offset; + // send 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? + // (if it's too cold and still getting colder...) + // the temperature is this far below the floor: + #define BELOW (offset + (THERM_WINDOW_SIZE<<1)) + else if ((BELOW < 0) && (diff < 0)) { + // accumulated error isn't big enough yet to send a warning + if (warning_threshold < 0) { + warning_threshold -= BELOW; + } else { // error is big enough; send a warning + warning_threshold = (-THERM_NEXT_WARNING_THRESHOLD) - BELOW; + + // how far below the floor? + // int16_t howmuch = ((-BELOW) >> 1) * THERM_RESPONSE_MAGNITUDE / 128; + int16_t howmuch = (-BELOW) >> 1; + // send a notification (unless voltage is low) + // (LVP and underheat warnings fight each other) + if (voltage > (VOLTAGE_LOW + 1)) + emit(EV_temperature_low, howmuch); } } + #undef BELOW + + // Goldilocks? + // (temperature is within target window, or at least heading toward it) + else { + // send a notification (unless voltage is low) + // (LVP and temp-okay events fight each other) + if (voltage > VOLTAGE_LOW) + emit(EV_temperature_okay, 0); + } } #endif diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index 6e39750..241dee4 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -40,15 +40,21 @@ #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_sample_count = 0; // skip the first sample; it's junk 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 +uint16_t adc_raw[2]; // last ADC measurements (0=voltage, 1=temperature) +uint16_t adc_smooth[2]; // lowpassed ADC measurements (0=voltage, 1=temperature) +// ADC code is split into two parts: +// - ISR: runs immediately at each interrupt, does the bare minimum because time is critical here +// - deferred: the bulk of the logic runs later when time isn't so critical +uint8_t adc_deferred_enable = 0; // stop waiting and run the deferred code +void adc_deferred(); // do the actual ADC-related calculations static inline void ADC_voltage_handler(); volatile uint8_t voltage = 0; +#ifdef USE_LVP void low_voltage(); +#endif #ifdef USE_BATTCHECK void battcheck(); @@ -63,10 +69,6 @@ void battcheck(); #ifdef USE_THERMAL_REGULATION -// default 5 seconds between thermal regulation events -#ifndef THERMAL_WARNING_SECONDS -#define THERMAL_WARNING_SECONDS 5 -#endif // try to keep temperature below 45 C #ifndef DEFAULT_THERM_CEIL #define DEFAULT_THERM_CEIL 45 @@ -79,14 +81,10 @@ void battcheck(); #ifndef THERM_CAL_OFFSET #define THERM_CAL_OFFSET 0 #endif -// temperature now, in C (ish) * 2 (14.1 fixed-point) +// temperature now, in C (ish) volatile int16_t temperature; -// temperature in a few seconds, in C (ish) * 2 (14.1 fixed-point) -volatile int16_t projected_temperature; // Fight the future! uint8_t therm_ceil = DEFAULT_THERM_CEIL; int8_t therm_cal_offset = 0; -//void low_temperature(); -//void high_temperature(); volatile uint8_t reset_thermal_history = 1; static inline void ADC_temperature_handler(); #endif // ifdef USE_THERMAL_REGULATION diff --git a/spaghetti-monster/fsm-events.h b/spaghetti-monster/fsm-events.h index 39ad3aa..6760fdd 100644 --- a/spaghetti-monster/fsm-events.h +++ b/spaghetti-monster/fsm-events.h @@ -85,6 +85,7 @@ static volatile uint16_t ticks_since_last_event = 0; #ifdef USE_THERMAL_REGULATION #define EV_temperature_high (B_SYSTEM|0b00000101) #define EV_temperature_low (B_SYSTEM|0b00000110) +#define EV_temperature_okay (B_SYSTEM|0b00000111) #endif // Button press events diff --git a/spaghetti-monster/fsm-main.c b/spaghetti-monster/fsm-main.c index 4ad1e16..790cc68 100644 --- a/spaghetti-monster/fsm-main.c +++ b/spaghetti-monster/fsm-main.c @@ -181,7 +181,7 @@ void handle_deferred_interrupts() { } */ if (irq_adc) { // ADC done measuring - ADC_inner(); + adc_deferred(); // irq_adc = 0; // takes care of itself } if (irq_wdt) { // the clock ticked diff --git a/spaghetti-monster/fsm-misc.c b/spaghetti-monster/fsm-misc.c index 8da7b5b..152f047 100644 --- a/spaghetti-monster/fsm-misc.c +++ b/spaghetti-monster/fsm-misc.c @@ -46,19 +46,41 @@ uint8_t blink_digit(uint8_t num) { //StatePtr old_state = current_state; // "zero" digit gets a single short blink - uint8_t ontime = BLINK_SPEED * 2 / 10; + uint8_t ontime = BLINK_SPEED * 2 / 12; if (!num) { ontime = 8; num ++; } for (; num>0; num--) { set_level(BLINK_BRIGHTNESS); nice_delay_ms(ontime); set_level(0); - nice_delay_ms(BLINK_SPEED * 3 / 10); + nice_delay_ms(BLINK_SPEED * 3 / 12); } - return nice_delay_ms(BLINK_SPEED * 5 / 10); + return nice_delay_ms(BLINK_SPEED * 8 / 12); } #endif +#ifdef USE_BLINK_BIG_NUM +uint8_t blink_big_num(uint16_t num) { + uint16_t digits[] = { 10000, 1000, 100, 10, 1 }; + uint8_t started = 0; + for (uint8_t digit=0; digit<sizeof(digits)/sizeof(uint16_t); digit++) { + uint16_t scale = digits[digit]; + if (num >= scale) { + started = 1; + } + if (started) { + uint8_t digit = 0; + while (num >= scale) { + num -= scale; + digit ++; + } + if (! blink_digit(digit)) return 0; + } + } + + return nice_delay_ms(1000); +} +#endif #ifdef USE_BLINK_NUM uint8_t blink_num(uint8_t num) { //StatePtr old_state = current_state; diff --git a/spaghetti-monster/fsm-standby.c b/spaghetti-monster/fsm-standby.c index 9398f52..b002b91 100644 --- a/spaghetti-monster/fsm-standby.c +++ b/spaghetti-monster/fsm-standby.c @@ -73,8 +73,8 @@ void sleep_until_eswitch_pressed() go_to_standby = 0; } if (irq_adc) { // ADC done measuring - adcint_enable = 1; - ADC_inner(); + adc_deferred_enable = 1; + adc_deferred(); //ADC_off(); // takes care of itself //irq_adc = 0; // takes care of itself } diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c index 0c49a75..94266c1 100644 --- a/spaghetti-monster/fsm-wdt.c +++ b/spaghetti-monster/fsm-wdt.c @@ -111,7 +111,7 @@ void WDT_inner() { #ifdef TICK_DURING_STANDBY // handle standby mode specially if (go_to_standby) { - // emit a halfsleep tick, and process it + // emit a sleep tick, and process it emit(EV_sleep_tick, ticks_since_last); process_emissions(); @@ -119,9 +119,9 @@ void WDT_inner() { 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 != (ticks_since_last & 0x7f)) return; + if (0 != (ticks_since_last & 0x3f)) return; - adc_trigger = 255; // make sure a measurement will happen + adc_trigger = 0; // make sure a measurement will happen ADC_on(); // enable ADC voltage measurement functions temporarily #endif } @@ -178,13 +178,13 @@ void WDT_inner() { #endif #if defined(USE_LVP) || defined(USE_THERMAL_REGULATION) - // start a new ADC measurement every 4 ticks - adc_trigger ++; - if (0 == (adc_trigger & 3)) { + // enable the deferred ADC handler once in a while + if (! adc_trigger) { ADC_start_measurement(); - irq_adc_stable = 0; - adcint_enable = 1; + adc_deferred_enable = 1; } + // timing for the ADC handler is every 32 ticks (~2Hz) + adc_trigger = (adc_trigger + 1) & 31; #endif } diff --git a/spaghetti-monster/ramping-ui/ramping-ui.c b/spaghetti-monster/ramping-ui/ramping-ui.c index 18f488d..5eb7d8f 100644 --- a/spaghetti-monster/ramping-ui/ramping-ui.c +++ b/spaghetti-monster/ramping-ui/ramping-ui.c @@ -22,7 +22,6 @@ #define USE_THERMAL_REGULATION #define DEFAULT_THERM_CEIL 32 #define USE_DELAY_MS -#define USE_DELAY_4MS #define USE_DELAY_ZERO #define USE_RAMPING #define USE_BATTCHECK @@ -353,7 +352,7 @@ void loop() { battcheck(); } else if (current_state == tempcheck_state) { - blink_num(projected_temperature>>2); + blink_num(temperature); nice_delay_ms(1000); } #endif diff --git a/spaghetti-monster/rampingios/rampingiosv3.c b/spaghetti-monster/rampingios/rampingiosv3.c index d72e971..7f03e77 100644 --- a/spaghetti-monster/rampingios/rampingiosv3.c +++ b/spaghetti-monster/rampingios/rampingiosv3.c @@ -123,6 +123,7 @@ uint8_t ramp_config_state(Event event, uint16_t arg); uint8_t battcheck_state(Event event, uint16_t arg); #endif #ifdef USE_THERMAL_REGULATION +#define USE_BLINK_NUM uint8_t tempcheck_state(Event event, uint16_t arg); uint8_t thermal_config_state(Event event, uint16_t arg); #endif @@ -930,14 +931,15 @@ void thermal_config_save() { // calibrate room temperature val = config_state_values[0]; if (val) { - int8_t rawtemp = (temperature >> 1) - therm_cal_offset; + int8_t rawtemp = temperature - therm_cal_offset; therm_cal_offset = val - rawtemp; + reset_thermal_history = 1; // invalidate all recent temperature data } val = config_state_values[1]; if (val) { // set maximum heat limit - therm_ceil = 30 + val; + therm_ceil = 30 + val - 1; } if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL; } @@ -966,9 +968,9 @@ uint8_t beacon_config_state(Event event, uint16_t arg) { inline void beacon_mode_iter() { // one iteration of main loop() set_level(memorized_level); - nice_delay_ms(500); + nice_delay_ms(100); set_level(0); - nice_delay_ms(((beacon_seconds) * 1000) - 500); + nice_delay_ms(((beacon_seconds) * 1000) - 100); } #endif // #ifdef USE_BEACON_MODE @@ -1235,7 +1237,7 @@ void loop() { #ifdef USE_THERMAL_REGULATION // TODO: blink out therm_ceil during thermal_config_state? else if (state == tempcheck_state) { - blink_num(temperature>>1); + blink_num(temperature); nice_delay_ms(1000); } #endif diff --git a/spaghetti-monster/spaghetti-monster.txt b/spaghetti-monster/spaghetti-monster.txt index 9e051f1..434e1bc 100644 --- a/spaghetti-monster/spaghetti-monster.txt +++ b/spaghetti-monster/spaghetti-monster.txt @@ -124,14 +124,13 @@ Event types: between events. - EV_temperature_high: Sent whenever the MCU's projected temperature - is higher than therm_ceil. Minimum of THERMAL_WARNING_SECONDS - between events. The 'arg' indicates how far the temperature - exceeds the limit. + is higher than therm_ceil. Minimum of one second between events. + The 'arg' indicates how far the temperature exceeds the limit. - EV_temperature_low: Sent whenever the MCU's projected temperature is lower than (therm_ceil - THERMAL_WINDOW_SIZE). Minimum of - THERMAL_WARNING_SECONDS between events. The 'arg' indicates how - far the temperature exceeds the limit. + one second between events. The 'arg' indicates how far the + temperature exceeds the limit. Button presses: @@ -297,9 +296,6 @@ Useful #defines: - DEFAULT_THERM_CEIL: Set the temperature limit to use by default when the user hasn't configured anything. - - THERMAL_WARNING_SECONDS: How long to wait between temperature - events. - - USE_RAMPING: Enable smooth ramping helpers. - RAMP_LENGTH: Pick a pre-defined ramp by length. Defined sizes diff --git a/spaghetti-monster/werner/werner.c b/spaghetti-monster/werner/werner.c index 7c47cd7..4159fc6 100644 --- a/spaghetti-monster/werner/werner.c +++ b/spaghetti-monster/werner/werner.c @@ -467,14 +467,15 @@ void thermal_config_save() { // calibrate room temperature val = config_state_values[0]; if (val) { - int8_t rawtemp = (temperature >> 1) - therm_cal_offset; + int8_t rawtemp = temperature - therm_cal_offset; therm_cal_offset = val - rawtemp; + reset_thermal_history = 1; // invalidate all recent temperature data } val = config_state_values[1]; if (val) { // set maximum heat limit - therm_ceil = 30 + val; + therm_ceil = 30 + val - 1; } if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL; } @@ -589,7 +590,7 @@ uint8_t nearest_level(int16_t target) { for(uint8_t i=0; i<ramp_discrete_steps; i++) { this_level = ramp_discrete_floor + (i * (uint16_t)ramp_range / (ramp_discrete_steps-1)); - int8_t diff = target - this_level; + int16_t diff = target - this_level; if (diff < 0) diff = -diff; if (diff <= (ramp_discrete_step_size>>1)) return this_level; @@ -684,9 +685,6 @@ void loop() { StatePtr state = current_state; - #ifdef USE_DYNAMIC_UNDERCLOCKING - auto_clock_speed(); - #endif if (0) {} #ifdef USE_BATTCHECK @@ -697,7 +695,7 @@ void loop() { #ifdef USE_THERMAL_REGULATION // TODO: blink out therm_ceil during thermal_config_state else if (state == tempcheck_state) { - blink_num(temperature>>1); + blink_num(temperature); nice_delay_ms(1000); } #endif |
