From 9c0d1832464e4ee7ee8c4c63092ac4337347483b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 29 Jan 2020 05:08:14 -0700 Subject: rewrote ADC code to use a continuous lowpass system on all measurements, to eliminate noise and maybe increase precision (thermal code still needs to be rewritten though) --- spaghetti-monster/fsm-adc.c | 296 ++++++++++++++++++++++++---------------- spaghetti-monster/fsm-adc.h | 12 +- spaghetti-monster/fsm-main.c | 2 +- spaghetti-monster/fsm-standby.c | 8 +- spaghetti-monster/fsm-wdt.c | 6 +- 5 files changed, 194 insertions(+), 130 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 3763a3e..0a80461 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 - DIDR0 |= (1 << VOLTAGE_ADC_DIDR); + // disable digital input on divider pin to reduce power consumption + DIDR0 |= (1 << VOLTAGE_ADC_DIDR); #else - // disable digital input on VCC pin to reduce power consumption - //DIDR0 |= (1 << ADC_DIDR); // FIXME: unsure how to handle for VCC pin + // disable digital input on VCC pin to reduce power consumption + //DIDR0 |= (1 << ADC_DIDR); // FIXME: unsure how to handle for VCC pin #endif #if (ATTINY == 1634) 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 @@ -102,8 +113,8 @@ inline void ADC_off() { 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<<7) - (ADC_22<<7)) / (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; + // incoming value is left-adjusted, so shift it into a matching position + uint8_t result = ((value>>1) / adc_per_volt) + VOLTAGE_FUDGE_FACTOR; return result; } #endif @@ -124,78 +135,115 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { // 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 + // skip the first measurement; it's junk + //if (adc_sample_count) { + // slow down even more than ADC_PRSCL + // (result is about 600 Hz or a maximum of ~9 ADC units per second) + // (8 MHz / 128 prescale / 13.5 ticks per measurement / 8 = ~578 Hz) + // (~578 Hz / 64X resolution = ~9 original-resolution units per second) + if (1 == (adc_sample_count & 7)) { + + 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; + + } + + // the next measurement isn't the first + //adc_sample_count = 1; + adc_sample_count ++; + + /* + if (adc_sample_count) { // 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; + adc_sample_count = 1; // start another measurement // (is explicit because it otherwise doesn't seem to happen during standby mode) ADC_start_measurement(); + */ } -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; + + // what is being measured? 0 = battery voltage, 1 = temperature + uint8_t adc_step; - #ifdef TICK_DURING_STANDBY + #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 } @@ -206,21 +254,14 @@ static inline void ADC_voltage_handler() { #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; + uint16_t measurement = adc_smooth[0]; // latest 16-bit ADC value - // 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 + // jump-start the lowpass seed at boot + // (otherwise it takes a while to rise from zero) + if (measurement < 255) { + measurement = adc_raw[0]; + adc_smooth[0] = measurement; + } #ifdef USE_VOLTAGE_DIVIDER voltage = calc_voltage_divider(measurement); @@ -229,7 +270,7 @@ static inline void ADC_voltage_handler() { // 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 @@ -268,7 +309,7 @@ static inline void ADC_temperature_handler() { #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 uint16_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; @@ -276,34 +317,61 @@ static inline void ADC_temperature_handler() { #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 + // latest 16-bit ADC reading (left-adjusted, lowpassed) + uint16_t measurement; - // 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) { + // don't keep resetting reset_thermal_history = 0; - temperature = temp; + + // ignore lowpass, use latest sample + measurement = adc_raw[1]; + + // reset lowpass to latest sample + adc_smooth[1] = measurement; + + // forget any past measurements for(uint8_t i=0; i temperature) { - temperature ++; - } else if (temp < temperature) { - temperature --; + temperature_history[i] = measurement; + } + else { + measurement = adc_smooth[1]; // average of recent samples + } + + { // rotate the temperature history + // if it's time to rotate the thermal history, do it + // FIXME? allow more than 255 frames per step + // (that's only about 8 seconds maximum) + 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 + // FIXME: rotate the index instead of moving the values + if (THERM_HISTORY_STEP_MAX == history_step) { + history_step = 0; + // rotate measurements and add a new one + for (uint8_t i=0; i>6) - 275 + THERM_CAL_OFFSET + (int16_t)therm_cal_offset; + // guess what the temperature will be in a few seconds int16_t pt; { int16_t diff; - int16_t t = temperature; + uint16_t t = measurement; // algorithm tweaking; not really intended to be modified // how far ahead should we predict? @@ -315,44 +383,28 @@ static inline void ADC_temperature_handler() { #define THERM_RESPONSE_MAGNITUDE 128 #endif // acceptable temperature window size in C - #define THERM_WINDOW_SIZE 5 + #define THERM_WINDOW_SIZE (3<<6) // highest temperature allowed - #define THERM_CEIL ((int16_t)therm_ceil) + #define THERM_CEIL (((int16_t)therm_ceil)<<6) // 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 0) diff --; } + */ // projected_temperature = current temp extended forward by amplified rate of change //projected_temperature = temperature_history[NUM_THERMAL_VALUES_HISTORY-1] + (diff<>1) / adc_per_volt) + VOLTAGE_FUDGE_FACTOR; return result; } @@ -134,40 +134,41 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { #endif // happens every time the ADC sampler finishes a measurement +// collects an average of 64 samples, which increases effective number of +// bits from 10 to about 16 (ish, probably more like 14 really) +// (64 was chosen because it's the largest sample size which allows the +// sum to still fit into a 16-bit integer, and for speed and size reasons, +// we want to avoid doing 32-bit math) ISR(ADC_vect) { - // slow down even more than ADC_PRSCL - // (result is about 600 Hz or a maximum of ~9 ADC units per second) - // (8 MHz / 128 prescale / 13.5 ticks per measurement / 8 = ~578 Hz) - // (~578 Hz / 64X resolution = ~9 original-resolution units per second) - if (1 == (adc_sample_count & 7)) { + static uint16_t adc_sum; - uint16_t m; // latest measurement - uint16_t s; // smoothed measurement - uint8_t channel = adc_channel; + // keep this moving along + adc_sample_count ++; + // reset on first sample + // also, ignore first value since it's probably junk + if (1 == adc_sample_count) { + adc_sum = 0; + return; + } + // 64 samples collected, save the result + else if (66 == adc_sample_count) { + adc_smooth[adc_channel] = adc_sum; + } + // add the latest measurement to the pile + else { + uint16_t m = ADC; + // add to the running total + adc_sum += m; // 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; - + adc_raw[adc_channel] = m; } + // don't worry about the running total overflowing after sample 64... + // it doesn't matter - // the next measurement isn't the first - //adc_sample_count = 1; - adc_sample_count ++; - + // track what woke us up, and enable deferred logic + irq_adc = 1; } void adc_deferred() { @@ -177,7 +178,7 @@ void adc_deferred() { // 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); + pseudo_rand_seed += ADCL; #endif // the ADC triggers repeatedly when it's on, but we only need to run the @@ -241,22 +242,11 @@ static inline void ADC_voltage_handler() { #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_smooth[0]; // latest 16-bit ADC value - - // jump-start the lowpass seed at boot - // (otherwise it takes a while to rise from zero) - if (measurement < 255) { - measurement = adc_raw[0]; - adc_smooth[0] = measurement; - } + uint16_t measurement; - // 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; + // latest ADC value + if (go_to_standby) measurement = adc_raw[0] << 6; + else measurement = adc_smooth[0]; #ifdef USE_VOLTAGE_DIVIDER voltage = calc_voltage_divider(measurement); @@ -264,7 +254,6 @@ 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>>6) + VOLTAGE_FUDGE_FACTOR) >> 1; #endif @@ -308,34 +297,24 @@ static inline void ADC_temperature_handler() { #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 - // latest 16-bit ADC reading (left-adjusted, lowpassed) + // latest 16-bit ADC reading uint16_t measurement; if (! reset_thermal_history) { - measurement = adc_smooth[1]; // average of recent samples + // average of recent samples + measurement = adc_smooth[1]; } else { // wipe out old data // don't keep resetting reset_thermal_history = 0; - // ignore lowpass, use latest sample - measurement = adc_raw[1]; - - // reset lowpass to latest sample - adc_smooth[1] = measurement; + // ignore average, use latest sample + measurement = adc_raw[1] << 6; // forget any past measurements for(uint8_t i=0; i>= 1; + adc_sample_count = 33; } // add the latest measurement to the pile else { @@ -164,8 +171,6 @@ ISR(ADC_vect) { // update the latest value adc_raw[adc_channel] = m; } - // don't worry about the running total overflowing after sample 64... - // it doesn't matter // track what woke us up, and enable deferred logic irq_adc = 1; -- cgit v1.2.3 From d275f50525ed9a0950c743faa317c7aa4fe9420b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 30 Jan 2020 23:10:25 -0700 Subject: saving state of ADC / WDT refactoring before doing more changes... what changed so far: - removed LVP lowpass and thermal regulation lowpass logic; it's probably redundant now - slowed ADC deferred logic timing to 4X per second instead of 16X, because there doesn't seem to be much reason to do it any faster - reduced thermal event rate-limit to just 1 second, for more responsive regulation - added "EV_temperature_okay" signal, to help stop adjustments at an appropriate time instead of going to far - sped up sleep LVP to one measurement every 8 seconds instead of 16, to help the aux LEDs respond to voltage changes faster (effect on standby time is negligible) - make sure the WDT doesn't set the ADC channel or counter... except in standby mode --- spaghetti-monster/anduril/anduril.c | 10 ++++ spaghetti-monster/fsm-adc.c | 107 +++++++++++++----------------------- spaghetti-monster/fsm-adc.h | 4 +- spaghetti-monster/fsm-events.h | 1 + spaghetti-monster/fsm-wdt.c | 13 +++-- 5 files changed, 59 insertions(+), 76 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 380e2f9..2b11486 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -1062,6 +1062,16 @@ 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 + gradual_target = actual_level; + //set_level_gradually(actual_level); + return MISCHIEF_MANAGED; + } + #endif // ifdef USE_SET_LEVEL_GRADUALLY #endif // ifdef USE_THERMAL_REGULATION return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index f10114f..6fae262 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -119,18 +119,12 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { } #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 ~4X per second with just voltage enabled, +// or ~2X 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 2 #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 4 #endif // happens every time the ADC sampler finishes a measurement @@ -242,10 +236,9 @@ void adc_deferred() { #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 uint16_t measurement; @@ -263,23 +256,15 @@ static inline void ADC_voltage_handler() { #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 - emit(EV_voltage_low, 0); - // 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; } } } @@ -296,11 +281,7 @@ static inline void ADC_temperature_handler() { static uint8_t history_step = 0; // don't update history as often static uint16_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 + #define TEMPERATURE_TIMER_START (THERMAL_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) // N seconds between thermal regulation events // latest 16-bit ADC reading uint16_t measurement; @@ -373,28 +354,17 @@ static inline void ADC_temperature_handler() { // 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) - // FIXME: this is way too small for left-adjusted values /* + // FIXME: this is way too small for 16-bit values 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_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) { @@ -403,39 +373,38 @@ static inline void ADC_temperature_handler() { // 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); - } + // reset counters + 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) >> 6; + // 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); - } + // reset counters + 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) >> 6; + // send a notification (unless voltage is low) + // (LVP and underheat warnings fight each other) + if (voltage > VOLTAGE_LOW) + emit(EV_temperature_low, howmuch); + } + + // Goldilocks? (temperature is within target window) + else { + // reset counters + temperature_timer = TEMPERATURE_TIMER_START; + // send a notification (unless voltage is low) + // (LVP and temp-okay events fight each other) + if (voltage > VOLTAGE_LOW) + emit(EV_temperature_okay, 0); } - // TODO: add EV_temperature_okay signal } } #endif diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index f4c1332..6283b2c 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -67,9 +67,9 @@ void battcheck(); #ifdef USE_THERMAL_REGULATION -// default 5 seconds between thermal regulation events +// default 1 seconds between thermal regulation events #ifndef THERMAL_WARNING_SECONDS -#define THERMAL_WARNING_SECONDS 5 +#define THERMAL_WARNING_SECONDS 1 #endif // try to keep temperature below 45 C #ifndef DEFAULT_THERM_CEIL 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-wdt.c b/spaghetti-monster/fsm-wdt.c index e9dca3a..459010f 100644 --- a/spaghetti-monster/fsm-wdt.c +++ b/spaghetti-monster/fsm-wdt.c @@ -119,7 +119,7 @@ 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_on(); // enable ADC voltage measurement functions temporarily @@ -178,12 +178,15 @@ void WDT_inner() { #endif #if defined(USE_LVP) || defined(USE_THERMAL_REGULATION) - // start a new ADC measurement every 4 ticks + // start a new ADC measurement every 16 ticks adc_trigger ++; - if (0 == (adc_trigger & 3)) { - // in case we're in standby mode and auto-retrigger is turned off + if (0 == (adc_trigger & 15)) { + // in case we're in standby mode and the ADC is turned off + if (go_to_standby) { + //set_admux_voltage(); + ADC_on(); + } ADC_start_measurement(); - adc_sample_count = 0; // allow regulation logic to run adc_deferred_enable = 1; } -- cgit v1.2.3 From f6f553bc5dbef8ef4a00b5e19838d775eff9ab41 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 3 Feb 2020 02:52:53 -0700 Subject: mention the maximum allowed temperature in the manual --- spaghetti-monster/anduril/anduril-manual.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spaghetti-monster') 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 -- cgit v1.2.3 From 32cc8a10f500456a0288eff38d41e8b820ee2a7d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 5 Feb 2020 02:35:10 -0700 Subject: replaced Anduril's gradual adjustment speed code with a smaller simpler version --- spaghetti-monster/anduril/anduril.c | 60 +++++++++++-------------------------- 1 file changed, 17 insertions(+), 43 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 2b11486..69dd118 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -957,59 +957,33 @@ 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 ++; + ticks_per_adjust >>= 1; diff >>= 1; } - 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; } -- cgit v1.2.3 From 7e994a1a76d7a61e3cdd921b3275169d9a725b6a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 5 Feb 2020 02:36:24 -0700 Subject: first pass at a smaller simpler thermal regulation algorithm... ... doesn't work well, but I'm saving it so I can experiment with other methods and maybe revert back later. --- spaghetti-monster/fsm-adc.c | 127 ++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 75 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 6fae262..d1efff3 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -273,15 +273,24 @@ static inline void ADC_voltage_handler() { #ifdef USE_THERMAL_REGULATION 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 5 // 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 uint16_t temperature_history[NUM_THERMAL_VALUES_HISTORY]; + // 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 3 + + #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 uint8_t temperature_timer = 0; - #define TEMPERATURE_TIMER_START (THERMAL_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) // N seconds between thermal regulation events + // N seconds between thermal regulation events + #define TEMPERATURE_TIMER_START (THERMAL_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) // latest 16-bit ADC reading uint16_t measurement; @@ -297,105 +306,73 @@ static inline void ADC_temperature_handler() { measurement = adc_raw[1] << 6; // forget any past measurements - for(uint8_t i=0; i>6) - 275 + THERM_CAL_OFFSET + (int16_t)therm_cal_offset; - // guess what the temperature will be in a few seconds - int16_t pt; - { - int16_t diff; - uint16_t t = measurement; + // 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 + int16_t pt; // predicted temperature + pt = measurement + (diff * THERM_LOOKAHEAD); + + // P[I]D: average of recent measurements + uint16_t avg = 0; + for(uint8_t i=0; i>3); + + uint16_t ceil = therm_ceil << 6; + //uint16_t floor = ceil - (THERM_WINDOW_SIZE << 6); + int16_t offset_pt, offset_avg; + offset_pt = pt - ceil; + offset_avg = avg - ceil; + int16_t offset = offset_pt + offset_avg; + //int16_t offset = (pt - ceil) + (avg - ceil); - // 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 (3<<6) - // highest temperature allowed - #define THERM_CEIL (((int16_t)therm_ceil)<<6) - // bottom of target temperature window - #define THERM_FLOOR (THERM_CEIL - THERM_WINDOW_SIZE) - - // guess what the temp will be several seconds in the future - // diff = rate of temperature change - diff = t - temperature_history[0]; - // slight bias toward zero; ignore very small changes (noise) - /* - // FIXME: this is way too small for 16-bit values - 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 - pt = projected_temperature = t + (diff< THERM_CEIL) { + // (if it's too hot and not getting colder...) + if ((offset > 0) && (diff > (-1 << 5))) { // reset counters 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) >> 6; + //int16_t howmuch = (offset >> 6) * THERM_RESPONSE_MAGNITUDE / 128; + int16_t howmuch = (offset >> 6); // send a warning emit(EV_temperature_high, howmuch); } // Too cold? - else if (pt < THERM_FLOOR) { + // (if it's too cold and not getting warmer...) + else if ((offset < -(THERM_WINDOW_SIZE << 6)) + && (diff < (1 << 5))) { // reset counters 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) >> 6; + //int16_t howmuch = (((-offset) - (THERM_WINDOW_SIZE<<6)) >> 7) * THERM_WINDOW_SIZE / 128; + int16_t howmuch = ((-offset) - (THERM_WINDOW_SIZE<<6)) >> 7; // send a notification (unless voltage is low) // (LVP and underheat warnings fight each other) if (voltage > VOLTAGE_LOW) emit(EV_temperature_low, howmuch); } - // Goldilocks? (temperature is within target window) + // Goldilocks? + // (temperature is within target window, or at least heading toward it) else { // reset counters temperature_timer = TEMPERATURE_TIMER_START; -- cgit v1.2.3 From 46af6026a2dc2bae92d41609a8ecd6144082825e Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 5 Feb 2020 22:12:45 -0700 Subject: still doesn't work, but at least it's a bit less broken than before... (ceiling value was all wrong, and the response magnitude was way too big) (also, temperatures here are unsigned, since freezing is about 270 in ADC units) --- spaghetti-monster/fsm-adc.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index d1efff3..2df884e 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -275,7 +275,7 @@ static inline void ADC_voltage_handler() { static inline void ADC_temperature_handler() { // coarse adjustment #ifndef THERM_LOOKAHEAD - #define THERM_LOOKAHEAD 5 // can be tweaked per build target + #define THERM_LOOKAHEAD 3 // can be tweaked per build target #endif // fine-grained adjustment // how proportional should the adjustments be? (not used yet) @@ -323,7 +323,7 @@ static inline void ADC_temperature_handler() { history_step = (history_step + 1) & (NUM_TEMP_HISTORY_STEPS-1); // PI[D]: guess what the temperature will be in a few seconds - int16_t pt; // predicted temperature + uint16_t pt; // predicted temperature pt = measurement + (diff * THERM_LOOKAHEAD); // P[I]D: average of recent measurements @@ -331,11 +331,15 @@ static inline void ADC_temperature_handler() { for(uint8_t i=0; i>3); - uint16_t ceil = therm_ceil << 6; + // 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) << 6; //uint16_t floor = ceil - (THERM_WINDOW_SIZE << 6); int16_t offset_pt, offset_avg; - offset_pt = pt - ceil; - offset_avg = avg - ceil; + offset_pt = (pt - ceil) >> 1; + offset_avg = (avg - ceil) >> 1; int16_t offset = offset_pt + offset_avg; //int16_t offset = (pt - ceil) + (avg - ceil); @@ -351,7 +355,7 @@ static inline void ADC_temperature_handler() { temperature_timer = TEMPERATURE_TIMER_START; // how far above the ceiling? //int16_t howmuch = (offset >> 6) * THERM_RESPONSE_MAGNITUDE / 128; - int16_t howmuch = (offset >> 6); + int16_t howmuch = (offset >> 8); // send a warning emit(EV_temperature_high, howmuch); } @@ -359,12 +363,12 @@ static inline void ADC_temperature_handler() { // Too cold? // (if it's too cold and not getting warmer...) else if ((offset < -(THERM_WINDOW_SIZE << 6)) - && (diff < (1 << 5))) { + && (diff < (1 << 4))) { // reset counters temperature_timer = TEMPERATURE_TIMER_START; // how far below the floor? //int16_t howmuch = (((-offset) - (THERM_WINDOW_SIZE<<6)) >> 7) * THERM_WINDOW_SIZE / 128; - int16_t howmuch = ((-offset) - (THERM_WINDOW_SIZE<<6)) >> 7; + int16_t howmuch = ((-offset) - (THERM_WINDOW_SIZE<<6)) >> 9; // send a notification (unless voltage is low) // (LVP and underheat warnings fight each other) if (voltage > VOLTAGE_LOW) -- cgit v1.2.3 From 14ad6787546b3a2c55c129c8bd95eb6b98f14531 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 5 Feb 2020 23:34:44 -0700 Subject: brute force method for reducing ADC noise -- average a ridiculous number of samples (because, for some reason, even though 64 samples is plenty in a test program, it ends up being extremely erratic when used inside Anduril... and I'm not sure why) also, use 15-bit ADC values instead of 16 bits, in the temperature logic (to help protect against integer overflows) ... but this code still doesn't work well. It regulates down *very* fast, and then gradually rises until the next extra-fast drop-down. :( ... also, tempcheck mode sometimes changes by 4-5 C between readouts, which is worrisome. ... and factory reset is still broken. --- spaghetti-monster/fsm-adc.c | 32 +++++++++++++------------------- spaghetti-monster/fsm-adc.h | 2 +- 2 files changed, 14 insertions(+), 20 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 2df884e..65669b3 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -135,7 +135,7 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { // doing 32-bit math) ISR(ADC_vect) { - static uint16_t adc_sum; + static uint32_t adc_sum; // keep this moving along adc_sample_count ++; @@ -146,16 +146,10 @@ ISR(ADC_vect) { adc_sum = 0; return; } - // 64 samples collected, save the result - // (actually triggers at 64 and every 32 afterward) - else if (66 == adc_sample_count) { + // 2048 samples collected, save the result + else if (2050 == adc_sample_count) { // save the latest result - adc_smooth[adc_channel] = adc_sum; - // cut sum in half and set up another half-window of samples - // (for sort of a continuous average) - // (this seems to significantly reduce noise) - adc_sum >>= 1; - adc_sample_count = 33; + adc_smooth[adc_channel] = adc_sum >> 5; } // add the latest measurement to the pile else { @@ -275,7 +269,7 @@ static inline void ADC_voltage_handler() { static inline void ADC_temperature_handler() { // coarse adjustment #ifndef THERM_LOOKAHEAD - #define THERM_LOOKAHEAD 3 // can be tweaked per build target + #define THERM_LOOKAHEAD 4 // can be tweaked per build target #endif // fine-grained adjustment // how proportional should the adjustments be? (not used yet) @@ -297,13 +291,13 @@ static inline void ADC_temperature_handler() { if (! reset_thermal_history) { // average of recent samples - measurement = adc_smooth[1]; + measurement = adc_smooth[1] >> 1; } else { // wipe out old data // don't keep resetting reset_thermal_history = 0; // ignore average, use latest sample - measurement = adc_raw[1] << 6; + measurement = adc_raw[1] << 5; // forget any past measurements for(uint8_t i=0; i>6) - 275 + THERM_CAL_OFFSET + (int16_t)therm_cal_offset; + temperature = (measurement>>5) - 275 + THERM_CAL_OFFSET + (int16_t)therm_cal_offset; // how much has the temperature changed between now and a few seconds ago? int16_t diff; @@ -335,7 +329,7 @@ static inline void ADC_temperature_handler() { // 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) << 6; + uint16_t ceil = (therm_ceil + 275 - therm_cal_offset - THERM_CAL_OFFSET) << 5; //uint16_t floor = ceil - (THERM_WINDOW_SIZE << 6); int16_t offset_pt, offset_avg; offset_pt = (pt - ceil) >> 1; @@ -350,7 +344,7 @@ static inline void ADC_temperature_handler() { // Too hot? // (if it's too hot and not getting colder...) - if ((offset > 0) && (diff > (-1 << 5))) { + if ((offset > 0) && (diff > (-1 << 4))) { // reset counters temperature_timer = TEMPERATURE_TIMER_START; // how far above the ceiling? @@ -362,13 +356,13 @@ static inline void ADC_temperature_handler() { // Too cold? // (if it's too cold and not getting warmer...) - else if ((offset < -(THERM_WINDOW_SIZE << 6)) - && (diff < (1 << 4))) { + else if ((offset < -(THERM_WINDOW_SIZE << 5)) + && (diff < (1 << 3))) { // reset counters temperature_timer = TEMPERATURE_TIMER_START; // how far below the floor? //int16_t howmuch = (((-offset) - (THERM_WINDOW_SIZE<<6)) >> 7) * THERM_WINDOW_SIZE / 128; - int16_t howmuch = ((-offset) - (THERM_WINDOW_SIZE<<6)) >> 9; + int16_t howmuch = ((-offset) - (THERM_WINDOW_SIZE<<5)) >> 8; // send a notification (unless voltage is low) // (LVP and underheat warnings fight each other) if (voltage > VOLTAGE_LOW) diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index 6283b2c..7acb505 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -40,7 +40,7 @@ #endif volatile uint8_t irq_adc = 0; // ADC interrupt happened? -uint8_t adc_sample_count = 0; // skip the first sample; it's junk +uint16_t adc_sample_count = 0; // skip the first sample; it's junk uint8_t adc_channel = 0; // 0=voltage, 1=temperature uint16_t adc_raw[2]; // last ADC measurements (0=voltage, 1=temperature) uint16_t adc_smooth[2]; // lowpassed ADC measurements (0=voltage, 1=temperature) -- cgit v1.2.3 From 930752b496ad8a1d9f3db96184839022c16a5c7f Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 28 Feb 2020 02:06:53 -0700 Subject: went back to continuous lowpass because it had the best noise reduction (also, now treating smoothed ADC values as 11-bit, with the lowest 5 bits chopped off to eliminate noise) --- spaghetti-monster/fsm-adc.c | 124 ++++++++++++++++++++++++++------------------ spaghetti-monster/fsm-wdt.c | 2 +- 2 files changed, 74 insertions(+), 52 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 65669b3..59d4e5c 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -25,7 +25,7 @@ static inline void set_admux_therm() { #if (ATTINY == 1634) ADMUX = ADMUX_THERM; #elif (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - ADMUX = ADMUX_THERM; + ADMUX = ADMUX_THERM | (1 << ADLAR); #elif (ATTINY == 841) // FIXME: not tested ADMUXA = ADMUXA_THERM; ADMUXB = ADMUXB_THERM; @@ -46,9 +46,9 @@ inline void set_admux_voltage() { #endif #elif (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7 - ADMUX = ADMUX_VOLTAGE_DIVIDER; + ADMUX = ADMUX_VOLTAGE_DIVIDER | (1 << ADLAR); #else // VCC / 1.1V reference - ADMUX = ADMUX_VCC; + ADMUX = ADMUX_VCC | (1 << ADLAR); #endif #elif (ATTINY == 841) // FIXME: not tested #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7 @@ -88,7 +88,7 @@ inline void ADC_on() #endif #if (ATTINY == 1634) //ACSRA |= (1 << ACD); // turn off analog comparator to save power - //ADCSRB |= (1 << ADLAR); // left-adjust flag is here instead of ADMUX + ADCSRB |= (1 << ADLAR); // left-adjust flag is here instead of ADMUX #endif // enable, start, auto-retrigger, prescale ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL; @@ -122,46 +122,42 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { // Each full cycle runs ~4X per second with just voltage enabled, // or ~2X per second with voltage and temperature. #if defined(USE_LVP) && defined(USE_THERMAL_REGULATION) -#define ADC_CYCLES_PER_SECOND 2 +#define ADC_CYCLES_PER_SECOND 1 #else -#define ADC_CYCLES_PER_SECOND 4 +#define ADC_CYCLES_PER_SECOND 2 #endif // happens every time the ADC sampler finishes a measurement -// collects a rolling average of 64+ samples, which increases effective number -// of bits from 10 to about 16 (ish, probably more like 14 really) (64 was -// chosen because it's the largest sample size which allows the sum to still -// fit into a 16-bit integer, and for speed and size reasons, we want to avoid -// doing 32-bit math) ISR(ADC_vect) { - static uint32_t adc_sum; + if (adc_sample_count) { - // keep this moving along - adc_sample_count ++; + uint16_t m; // latest measurement + uint16_t s; // smoothed measurement + uint8_t channel = adc_channel; - // reset on first sample - // also, ignore first value since it's probably junk - if (1 == adc_sample_count) { - adc_sum = 0; - return; - } - // 2048 samples collected, save the result - else if (2050 == adc_sample_count) { - // save the latest result - adc_smooth[adc_channel] = adc_sum >> 5; - } - // add the latest measurement to the pile - else { - uint16_t m = ADC; - // add to the running total - adc_sum += m; // update the latest value - adc_raw[adc_channel] = m; + 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; + } - // track what woke us up, and enable deferred logic - irq_adc = 1; + // the next measurement isn't the first + //adc_sample_count = 1; + adc_sample_count ++; + } void adc_deferred() { @@ -171,7 +167,7 @@ void adc_deferred() { // 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; + pseudo_rand_seed += (ADCL >> 6) + (ADCH << 2); #endif // the ADC triggers repeatedly when it's on, but we only need to run the @@ -237,9 +233,22 @@ static inline void ADC_voltage_handler() { uint16_t measurement; // latest ADC value - if (go_to_standby) measurement = adc_raw[0] << 6; + 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); #else @@ -286,27 +295,35 @@ static inline void ADC_temperature_handler() { // N seconds between thermal regulation events #define TEMPERATURE_TIMER_START (THERMAL_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) - // latest 16-bit ADC reading - uint16_t measurement; - - if (! reset_thermal_history) { - // average of recent samples - measurement = adc_smooth[1] >> 1; - } else { // wipe out old data + if (reset_thermal_history) { // wipe out old data // don't keep resetting reset_thermal_history = 0; // ignore average, use latest sample - measurement = adc_raw[1] << 5; + uint16_t foo = adc_raw[1]; + adc_smooth[1] = foo; // forget any past measurements for(uint8_t i=0; i> 5; } + // latest 16-bit ADC reading + uint16_t measurement = adc_smooth[1]; + + // 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 + // let the UI see the current temperature in C // Convert ADC units to Celsius (ish) - temperature = (measurement>>5) - 275 + THERM_CAL_OFFSET + (int16_t)therm_cal_offset; + 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; @@ -320,22 +337,27 @@ static inline void ADC_temperature_handler() { uint16_t pt; // predicted temperature pt = measurement + (diff * THERM_LOOKAHEAD); + /* seems unnecessary; simply sending repeated warnings has a similar effect // P[I]D: average of recent measurements uint16_t avg = 0; for(uint8_t i=0; i>3); + */ // 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) << 5; + uint16_t ceil = (therm_ceil + 275 - therm_cal_offset - THERM_CAL_OFFSET) << 1; //uint16_t floor = ceil - (THERM_WINDOW_SIZE << 6); + /* average of I and D terms int16_t offset_pt, offset_avg; offset_pt = (pt - ceil) >> 1; offset_avg = (avg - ceil) >> 1; int16_t offset = offset_pt + offset_avg; //int16_t offset = (pt - ceil) + (avg - ceil); + */ + int16_t offset = pt - ceil; if (temperature_timer) { @@ -344,25 +366,25 @@ static inline void ADC_temperature_handler() { // Too hot? // (if it's too hot and not getting colder...) - if ((offset > 0) && (diff > (-1 << 4))) { + if ((offset > 0) && (diff > (-1))) { // reset counters temperature_timer = TEMPERATURE_TIMER_START; // how far above the ceiling? //int16_t howmuch = (offset >> 6) * THERM_RESPONSE_MAGNITUDE / 128; - int16_t howmuch = (offset >> 8); + int16_t howmuch = (offset >> 1); // send a warning emit(EV_temperature_high, howmuch); } // Too cold? // (if it's too cold and not getting warmer...) - else if ((offset < -(THERM_WINDOW_SIZE << 5)) - && (diff < (1 << 3))) { + else if ((offset < -(THERM_WINDOW_SIZE << 1)) + && (diff < (1))) { // reset counters temperature_timer = TEMPERATURE_TIMER_START; // how far below the floor? //int16_t howmuch = (((-offset) - (THERM_WINDOW_SIZE<<6)) >> 7) * THERM_WINDOW_SIZE / 128; - int16_t howmuch = ((-offset) - (THERM_WINDOW_SIZE<<5)) >> 8; + int16_t howmuch = ((-offset) - (THERM_WINDOW_SIZE<<1)) >> 1; // send a notification (unless voltage is low) // (LVP and underheat warnings fight each other) if (voltage > VOLTAGE_LOW) diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c index 459010f..12aab7b 100644 --- a/spaghetti-monster/fsm-wdt.c +++ b/spaghetti-monster/fsm-wdt.c @@ -180,7 +180,7 @@ void WDT_inner() { #if defined(USE_LVP) || defined(USE_THERMAL_REGULATION) // start a new ADC measurement every 16 ticks adc_trigger ++; - if (0 == (adc_trigger & 15)) { + if (0 == (adc_trigger & 31)) { // in case we're in standby mode and the ADC is turned off if (go_to_standby) { //set_admux_voltage(); -- cgit v1.2.3 From 4d1c7a34fd00a4dd19e591ea0602f0f47f10d9f0 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 5 Mar 2020 17:51:27 -0700 Subject: initial support for Noctigon KR4 (not complete, but far enough that it installs and runs) New hardware support features: - allow using PCINT other than 0 (PCINT1, PCINT2, etc) - option to ignore voltage ADC while the button is pressed (because my prototype shorts the voltage divider to 0 while the button is down) --- spaghetti-monster/anduril/cfg-noctigon-kr4.h | 66 ++++++++++++++++++++++++++++ spaghetti-monster/fsm-adc.c | 6 +++ spaghetti-monster/fsm-pcint.c | 4 ++ 3 files changed, 76 insertions(+) create mode 100644 spaghetti-monster/anduril/cfg-noctigon-kr4.h (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h new file mode 100644 index 0000000..87be78e --- /dev/null +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -0,0 +1,66 @@ +// Noctigon KR4 config options for Anduril +#include "hwdef-Noctigon_KR4.h" +// ATTINY: 1634 + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS +//#define USE_AUX_RGB_LEDS_WHILE_ON +//#define USE_INDICATOR_LED_WHILE_RAMPING +#define RGB_LED_OFF_DEFAULT 0x18 // low, voltage +#define RGB_LED_LOCKOUT_DEFAULT 0x37 // blinking, rainbow + +// enable blinking aux LEDs +#define TICK_DURING_STANDBY +#define STANDBY_TICK_SPEED 3 // every 0.128 s + + +// ../../bin/level_calc.py cube 1 150 7135 1 4 1300 +// (with max_pwm set to 1023) +#define RAMP_LENGTH 150 +#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,6,7,8,9,10,11,12,13,14,15,16,17,18,20,21,23,24,26,27,29,31,32,34,36,38,40,43,45,47,49,52,54,57,60,62,65,68,71,74,77,81,84,87,91,95,98,102,106,110,114,118,122,127,131,136,141,145,150,155,160,166,171,176,182,188,193,199,205,211,218,224,231,237,244,251,258,265,272,280,287,295,303,310,319,327,335,344,352,361,370,379,388,397,407,416,426,436,446,457,467,477,488,499,510,521,533,544,556,568,580,592,604,617,629,642,655,668,682,695,709,723,737,751,766,781,795,810,826,841,857,872,888,904,921,937,954,971,988,1005,1023 +#define MAX_1x7135 50 + +// the entire ramp is regulated; don't blink halfway up +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + +// don't slow down at low levels; this isn't that sort of light +// (it needs to stay at full speed for the 10-bit PWM to work) +#ifdef USE_DYNAMIC_UNDERCLOCKING +#undef USE_DYNAMIC_UNDERCLOCKING +#endif + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 130 +// 10, 30, [50], 70, 90, 110, 130 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 + +#define MUGGLE_FLOOR RAMP_DISCRETE_FLOOR +#define MUGGLE_CEILING 70 + +// optional, makes initial turbo step-down faster so first peak isn't as hot +// the KR4 runs very very hot on turbo, so be extra careful +//#define THERM_HARD_TURBO_DROP + +// stop panicking at ~70% power or ~600 lm +#define THERM_FASTER_LEVEL 130 +// respond to thermal changes faster +#define THERMAL_WARNING_SECONDS 3 +#define THERMAL_UPDATE_SPEED 1 +#define THERM_PREDICTION_STRENGTH 4 + +// easier access to thermal config mode, for Noctigon +#define USE_TENCLICK_THERMAL_CONFIG + +// slow down party strobe; this driver can't pulse for 1ms or less +#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/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 2a3c5c6..2d8d01f 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -206,6 +206,12 @@ static inline void ADC_voltage_handler() { #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 + // (because the button causes a reading of zero volts) + if (button_last_state) return; + #endif + uint16_t measurement = adc_values[0]; // latest 10-bit ADC reading #ifdef USE_VOLTAGE_LOWPASS diff --git a/spaghetti-monster/fsm-pcint.c b/spaghetti-monster/fsm-pcint.c index 1ba1c15..d362633 100644 --- a/spaghetti-monster/fsm-pcint.c +++ b/spaghetti-monster/fsm-pcint.c @@ -66,7 +66,11 @@ inline void PCINT_off() { //void button_change_interrupt() { #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634) //EMPTY_INTERRUPT(PCINT0_vect); +#ifdef PCINT_vect +ISR(PCINT_vect) { +#else ISR(PCINT0_vect) { +#endif irq_pcint = 1; } #else -- cgit v1.2.3 From 490630291c3fb10fc63801645116a73b4c7a5e73 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 6 Mar 2020 03:20:26 -0700 Subject: KR4: added FET channel, measured output, calibrated ramp --- spaghetti-monster/anduril/cfg-noctigon-kr4.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index 87be78e..8971fca 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -14,11 +14,19 @@ #define STANDBY_TICK_SPEED 3 // every 0.128 s -// ../../bin/level_calc.py cube 1 150 7135 1 4 1300 +// brightness w/ SST-20 4000K LEDs: +// 0/1023: 0.35 lm +// 1/1023: 2.56 lm +// max regulated: 1740 lm +// FET: ~3700 lm +// level_calc.py 3.0 2 150 7135 0 2.5 1740 FET 1 10 2565 // (with max_pwm set to 1023) +// (designed to hit max regulated at 130/150) #define RAMP_LENGTH 150 -#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,6,7,8,9,10,11,12,13,14,15,16,17,18,20,21,23,24,26,27,29,31,32,34,36,38,40,43,45,47,49,52,54,57,60,62,65,68,71,74,77,81,84,87,91,95,98,102,106,110,114,118,122,127,131,136,141,145,150,155,160,166,171,176,182,188,193,199,205,211,218,224,231,237,244,251,258,265,272,280,287,295,303,310,319,327,335,344,352,361,370,379,388,397,407,416,426,436,446,457,467,477,488,499,510,521,533,544,556,568,580,592,604,617,629,642,655,668,682,695,709,723,737,751,766,781,795,810,826,841,857,872,888,904,921,937,954,971,988,1005,1023 +#define PWM1_LEVELS 0,0,1,1,2,2,3,3,4,4,5,5,6,7,8,9,10,11,12,13,15,16,17,19,21,22,24,26,28,30,32,34,36,39,41,44,47,49,52,55,58,62,65,68,72,76,80,84,88,92,96,101,105,110,115,120,125,131,136,142,147,153,159,166,172,179,185,192,199,206,214,221,229,237,245,253,262,270,279,288,298,307,317,326,336,346,357,367,378,389,401,412,424,436,448,460,472,485,498,511,525,539,552,567,581,596,611,626,641,657,673,689,705,722,739,756,773,791,809,827,846,864,883,903,922,942,962,983,1003,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,83,130,177,225,273,323,372,423,474,526,578,632,686,740,795,851,908,965,1023 #define MAX_1x7135 50 +#define MAX_Nx7135 130 // the entire ramp is regulated; don't blink halfway up #ifdef BLINK_AT_RAMP_MIDDLE -- cgit v1.2.3 From 99d1551da9cfba76840ad69cf337728dd08b3f3d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 6 Mar 2020 03:32:30 -0700 Subject: FET ramp was too steep; slowed it down by 50% (20 steps -> 30 steps) --- spaghetti-monster/anduril/cfg-noctigon-kr4.h | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index 8971fca..7771cd4 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -19,14 +19,13 @@ // 1/1023: 2.56 lm // max regulated: 1740 lm // FET: ~3700 lm -// level_calc.py 3.0 2 150 7135 0 2.5 1740 FET 1 10 2565 -// (with max_pwm set to 1023) -// (designed to hit max regulated at 130/150) +// maxreg at 130: level_calc.py cube 2 150 7135 0 2.5 1740 FET 1 10 2565 +// maxreg at 120: level_calc.py cube 2 150 7135 0 2.5 1740 FET 1 10 3190 #define RAMP_LENGTH 150 -#define PWM1_LEVELS 0,0,1,1,2,2,3,3,4,4,5,5,6,7,8,9,10,11,12,13,15,16,17,19,21,22,24,26,28,30,32,34,36,39,41,44,47,49,52,55,58,62,65,68,72,76,80,84,88,92,96,101,105,110,115,120,125,131,136,142,147,153,159,166,172,179,185,192,199,206,214,221,229,237,245,253,262,270,279,288,298,307,317,326,336,346,357,367,378,389,401,412,424,436,448,460,472,485,498,511,525,539,552,567,581,596,611,626,641,657,673,689,705,722,739,756,773,791,809,827,846,864,883,903,922,942,962,983,1003,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,83,130,177,225,273,323,372,423,474,526,578,632,686,740,795,851,908,965,1023 -#define MAX_1x7135 50 -#define MAX_Nx7135 130 +#define PWM1_LEVELS 0,0,1,1,2,2,3,3,4,4,5,6,7,8,9,10,11,13,14,15,17,19,20,22,24,26,28,30,33,35,38,40,43,46,49,52,55,59,62,66,70,74,78,82,86,91,96,100,105,111,116,121,127,133,139,145,151,158,165,172,179,186,193,201,209,217,225,234,243,251,261,270,280,289,299,310,320,331,342,353,364,376,388,400,412,425,438,451,464,478,492,506,521,536,551,566,582,597,614,630,647,664,681,699,717,735,754,772,792,811,831,851,871,892,913,935,956,978,1001,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,51,79,109,138,168,198,229,260,292,324,357,390,423,457,492,527,562,598,634,671,708,746,784,822,861,901,941,982,1023 +#define MAX_1x7135 46 +#define MAX_Nx7135 120 // the entire ramp is regulated; don't blink halfway up #ifdef BLINK_AT_RAMP_MIDDLE @@ -40,21 +39,21 @@ #endif #define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 130 -// 10, 30, [50], 70, 90, 110, 130 +#define RAMP_SMOOTH_CEIL 120 +// 10, 28, [46], 65, 83, 101, [120] #define RAMP_DISCRETE_FLOOR 10 #define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL #define RAMP_DISCRETE_STEPS 7 #define MUGGLE_FLOOR RAMP_DISCRETE_FLOOR -#define MUGGLE_CEILING 70 +#define MUGGLE_CEILING 65 // optional, makes initial turbo step-down faster so first peak isn't as hot // the KR4 runs very very hot on turbo, so be extra careful //#define THERM_HARD_TURBO_DROP // stop panicking at ~70% power or ~600 lm -#define THERM_FASTER_LEVEL 130 +#define THERM_FASTER_LEVEL 120 // respond to thermal changes faster #define THERMAL_WARNING_SECONDS 3 #define THERMAL_UPDATE_SPEED 1 -- cgit v1.2.3 From 7110fdbae15c6303eb405705bf0b319fc1381a4f Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 13 Mar 2020 18:06:27 -0600 Subject: tried to make thermal code a bit less twitchy... it regulates really fast on D4, but once it's stable, the adjustments are too large --- spaghetti-monster/anduril/anduril.c | 13 ++++++++----- spaghetti-monster/fsm-adc.c | 17 ++++++++++------- spaghetti-monster/fsm-wdt.c | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 69dd118..469d0d8 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -963,7 +963,7 @@ uint8_t steady_state(Event event, uint16_t arg) { if (diff) { uint16_t ticks_per_adjust = 256; if (diff < 0) { - diff = -diff; + //diff = -diff; if (actual_level > THERM_FASTER_LEVEL) { #ifdef THERM_HARD_TURBO_DROP ticks_per_adjust >>= 2; @@ -976,7 +976,8 @@ uint8_t steady_state(Event event, uint16_t arg) { } while (diff) { ticks_per_adjust >>= 1; - diff >>= 1; + //diff >>= 1; + diff /= 2; // because shifting produces weird behavior } if (ticks_since_adjust > ticks_per_adjust) { @@ -1040,9 +1041,11 @@ uint8_t steady_state(Event event, uint16_t arg) { // temperature is within target window // (so stop trying to adjust output) else if (event == EV_temperature_okay) { - // if we're still adjusting output... stop - gradual_target = actual_level; - //set_level_gradually(actual_level); + // 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 diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 59d4e5c..358ff26 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -288,6 +288,9 @@ static inline void ADC_temperature_handler() { // acceptable temperature window size in C #define THERM_WINDOW_SIZE 3 + // 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]; @@ -365,21 +368,21 @@ static inline void ADC_temperature_handler() { } else { // it has been long enough since the last warning // Too hot? - // (if it's too hot and not getting colder...) - if ((offset > 0) && (diff > (-1))) { + // (if it's too hot and still getting warmer...) + if ((offset > 0) && (diff > 0)) { // reset counters temperature_timer = TEMPERATURE_TIMER_START; // how far above the ceiling? //int16_t howmuch = (offset >> 6) * THERM_RESPONSE_MAGNITUDE / 128; - int16_t howmuch = (offset >> 1); + //int16_t howmuch = (offset >> 1); + int16_t howmuch = offset; // send a warning emit(EV_temperature_high, howmuch); } // Too cold? - // (if it's too cold and not getting warmer...) - else if ((offset < -(THERM_WINDOW_SIZE << 1)) - && (diff < (1))) { + // (if it's too cold and still getting colder...) + else if ((offset < -(THERM_WINDOW_SIZE << 1)) && (diff < 0)) { // reset counters temperature_timer = TEMPERATURE_TIMER_START; // how far below the floor? @@ -387,7 +390,7 @@ static inline void ADC_temperature_handler() { int16_t howmuch = ((-offset) - (THERM_WINDOW_SIZE<<1)) >> 1; // send a notification (unless voltage is low) // (LVP and underheat warnings fight each other) - if (voltage > VOLTAGE_LOW) + if (voltage > (VOLTAGE_LOW + 1)) emit(EV_temperature_low, howmuch); } diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c index 12aab7b..1d630a4 100644 --- a/spaghetti-monster/fsm-wdt.c +++ b/spaghetti-monster/fsm-wdt.c @@ -178,7 +178,7 @@ void WDT_inner() { #endif #if defined(USE_LVP) || defined(USE_THERMAL_REGULATION) - // start a new ADC measurement every 16 ticks + // enable the deferred ADC handler every 32 ticks adc_trigger ++; if (0 == (adc_trigger & 31)) { // in case we're in standby mode and the ADC is turned off -- cgit v1.2.3 From ccc82a57904097ffd1c1225ef5a8f0082f7046d8 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 15 Mar 2020 19:21:37 -0600 Subject: replaced temperature_timer (which wasn't even being used) with a variable delay between warnings, so large warnings can remain frequent while small warnings are separated by more time, based on a cumulative error counter which must pass a threshold before the next warning is sent (this is producing good test results so far on D4v2 and D4Sv2) --- spaghetti-monster/fsm-adc.c | 70 ++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 27 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 358ff26..93c58f1 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -280,6 +280,10 @@ static inline void ADC_temperature_handler() { #ifndef THERM_LOOKAHEAD #define THERM_LOOKAHEAD 4 // can be tweaked per build target #endif + // 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 @@ -294,7 +298,7 @@ static inline void ADC_temperature_handler() { #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 uint8_t temperature_timer = 0; + static int8_t warning_threshold = 0; // N seconds between thermal regulation events #define TEMPERATURE_TIMER_START (THERMAL_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) @@ -363,15 +367,17 @@ static inline void ADC_temperature_handler() { int16_t offset = pt - ceil; - if (temperature_timer) { - temperature_timer --; - } else { // it has been long enough since the last warning + //int16_t below = offset + (THERM_WINDOW_SIZE<<1); + + // 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; - // Too hot? - // (if it's too hot and still getting warmer...) - if ((offset > 0) && (diff > 0)) { - // reset counters - temperature_timer = TEMPERATURE_TIMER_START; // how far above the ceiling? //int16_t howmuch = (offset >> 6) * THERM_RESPONSE_MAGNITUDE / 128; //int16_t howmuch = (offset >> 1); @@ -379,32 +385,42 @@ static inline void ADC_temperature_handler() { // send a warning emit(EV_temperature_high, 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 ((offset < -(THERM_WINDOW_SIZE << 1)) && (diff < 0)) { + else if ((BELOW < 0) && (diff < 0)) { + // accumulated error isn't big enough yet to send a warning + if (warning_threshold < 0) { + //warning_threshold += ((THERM_WINDOW_SIZE<<1) - offset); + //warning_threshold -= (offset + (THERM_WINDOW_SIZE<<1)); + warning_threshold -= BELOW; + } else { // error is big enough; send a warning + //warning_threshold = (-THERM_NEXT_WARNING_THRESHOLD) - (offset + (THERM_WINDOW_SIZE<<1)); + warning_threshold = (-THERM_NEXT_WARNING_THRESHOLD) - BELOW; - // Too cold? - // (if it's too cold and still getting colder...) - else if ((offset < -(THERM_WINDOW_SIZE << 1)) && (diff < 0)) { - // reset counters - temperature_timer = TEMPERATURE_TIMER_START; // how far below the floor? //int16_t howmuch = (((-offset) - (THERM_WINDOW_SIZE<<6)) >> 7) * THERM_WINDOW_SIZE / 128; - int16_t howmuch = ((-offset) - (THERM_WINDOW_SIZE<<1)) >> 1; + //int16_t howmuch = ((-offset) - (THERM_WINDOW_SIZE<<1)) >> 1; + 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); } - - // Goldilocks? - // (temperature is within target window, or at least heading toward it) - else { - // reset counters - temperature_timer = TEMPERATURE_TIMER_START; - // send a notification (unless voltage is low) - // (LVP and temp-okay events fight each other) - if (voltage > VOLTAGE_LOW) - emit(EV_temperature_okay, 0); - } - + } + #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 -- cgit v1.2.3 From 4c1d17f4604bf38140381649a45a3c7c109ee97a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 15 Mar 2020 19:56:50 -0600 Subject: removed dead comments and dead code --- spaghetti-monster/fsm-adc.c | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 93c58f1..725902f 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -299,8 +299,6 @@ static inline void ADC_temperature_handler() { static uint8_t history_step = 0; static uint16_t temperature_history[NUM_TEMP_HISTORY_STEPS]; static int8_t warning_threshold = 0; - // N seconds between thermal regulation events - #define TEMPERATURE_TIMER_START (THERMAL_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) if (reset_thermal_history) { // wipe out old data // don't keep resetting @@ -344,31 +342,13 @@ static inline void ADC_temperature_handler() { uint16_t pt; // predicted temperature pt = measurement + (diff * THERM_LOOKAHEAD); - /* seems unnecessary; simply sending repeated warnings has a similar effect - // P[I]D: average of recent measurements - uint16_t avg = 0; - for(uint8_t i=0; i>3); - */ - // 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; - //uint16_t floor = ceil - (THERM_WINDOW_SIZE << 6); - /* average of I and D terms - int16_t offset_pt, offset_avg; - offset_pt = (pt - ceil) >> 1; - offset_avg = (avg - ceil) >> 1; - int16_t offset = offset_pt + offset_avg; - //int16_t offset = (pt - ceil) + (avg - ceil); - */ int16_t offset = pt - ceil; - - //int16_t below = offset + (THERM_WINDOW_SIZE<<1); - // Too hot? // (if it's too hot and still getting warmer...) if ((offset > 0) && (diff > 0)) { @@ -379,8 +359,7 @@ static inline void ADC_temperature_handler() { warning_threshold = THERM_NEXT_WARNING_THRESHOLD - offset; // how far above the ceiling? - //int16_t howmuch = (offset >> 6) * THERM_RESPONSE_MAGNITUDE / 128; - //int16_t howmuch = (offset >> 1); + //int16_t howmuch = offset * THERM_RESPONSE_MAGNITUDE / 128; int16_t howmuch = offset; // send a warning emit(EV_temperature_high, howmuch); @@ -391,20 +370,15 @@ static inline void ADC_temperature_handler() { // (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 ((offset < -(THERM_WINDOW_SIZE << 1)) && (diff < 0)) { else if ((BELOW < 0) && (diff < 0)) { // accumulated error isn't big enough yet to send a warning if (warning_threshold < 0) { - //warning_threshold += ((THERM_WINDOW_SIZE<<1) - offset); - //warning_threshold -= (offset + (THERM_WINDOW_SIZE<<1)); warning_threshold -= BELOW; } else { // error is big enough; send a warning - //warning_threshold = (-THERM_NEXT_WARNING_THRESHOLD) - (offset + (THERM_WINDOW_SIZE<<1)); warning_threshold = (-THERM_NEXT_WARNING_THRESHOLD) - BELOW; // how far below the floor? - //int16_t howmuch = (((-offset) - (THERM_WINDOW_SIZE<<6)) >> 7) * THERM_WINDOW_SIZE / 128; - //int16_t howmuch = ((-offset) - (THERM_WINDOW_SIZE<<1)) >> 1; + // 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) -- cgit v1.2.3 From eccf9c3d4df44c5a8fd88571ee2aaeca70975926 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 15 Mar 2020 19:58:35 -0600 Subject: the ADC sample count doesn't need to be 16-bit any more, and isn't really a count any more... ... just a boolean flag for whether this is the first sample or a later sample (so I changed it and reduced the ROM size by ~28 bytes) --- spaghetti-monster/fsm-adc.c | 5 +++-- spaghetti-monster/fsm-adc.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 725902f..c382a8a 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -155,8 +155,9 @@ ISR(ADC_vect) { } // the next measurement isn't the first - //adc_sample_count = 1; - adc_sample_count ++; + adc_sample_count = 1; + // rollover doesn't really matter + //adc_sample_count ++; } diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index 7acb505..6283b2c 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -40,7 +40,7 @@ #endif volatile uint8_t irq_adc = 0; // ADC interrupt happened? -uint16_t adc_sample_count = 0; // skip the first sample; it's junk +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_raw[2]; // last ADC measurements (0=voltage, 1=temperature) uint16_t adc_smooth[2]; // lowpassed ADC measurements (0=voltage, 1=temperature) -- cgit v1.2.3 From 79c9e662b98bf4219de9419eb2ccb171f80ef12b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 16 Mar 2020 00:11:02 -0600 Subject: reduced regulation jitter by biasing errors toward zero by a constant amount, which mostly impacts small errors (and reduces jitter during the flat phase of regulation) while leaving large errors pretty much unaffected... also, made acceptable thermal window smaller to make up for this new extra tolerance --- spaghetti-monster/fsm-adc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index c382a8a..dd43cb9 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -291,7 +291,7 @@ static inline void ADC_temperature_handler() { #define THERM_RESPONSE_MAGNITUDE 128 #endif // acceptable temperature window size in C - #define THERM_WINDOW_SIZE 3 + #define THERM_WINDOW_SIZE 2 // TODO: make this configurable per build target? // (shorter time for hosts with a lower power-to-mass ratio) @@ -350,6 +350,19 @@ static inline void ADC_temperature_handler() { 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 ++; + } + } + // Too hot? // (if it's too hot and still getting warmer...) if ((offset > 0) && (diff > 0)) { -- cgit v1.2.3 From 6e7884cf5b4756ffba9f6dc9dd1fb94184779bf1 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 16 Mar 2020 00:13:44 -0600 Subject: cleaned up WDT ADC timer code slightly, and removed a bit of redundant code --- spaghetti-monster/fsm-wdt.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c index 1d630a4..9858e09 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(); @@ -121,7 +121,7 @@ void WDT_inner() { // stop here, usually... but proceed often enough for sleep LVP to work 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,18 +178,20 @@ void WDT_inner() { #endif #if defined(USE_LVP) || defined(USE_THERMAL_REGULATION) - // enable the deferred ADC handler every 32 ticks - adc_trigger ++; - if (0 == (adc_trigger & 31)) { + // enable the deferred ADC handler once in a while + if (! adc_trigger) { + /* redundant; it was already turned on earlier in this function // in case we're in standby mode and the ADC is turned off if (go_to_standby) { //set_admux_voltage(); ADC_on(); } + */ ADC_start_measurement(); - // allow regulation logic to run adc_deferred_enable = 1; } + // timing for the ADC handler is every 32 ticks (~2Hz) + adc_trigger = (adc_trigger + 1) & 31; #endif } -- cgit v1.2.3 From 46e0f50a224c300b7e66ef00719edc0cef1f4c8d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 16 Mar 2020 00:15:19 -0600 Subject: deleted commented-out WDT code from previous revision (had only saved it so there would be a note in history about why it's gone) --- spaghetti-monster/fsm-wdt.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c index 9858e09..94266c1 100644 --- a/spaghetti-monster/fsm-wdt.c +++ b/spaghetti-monster/fsm-wdt.c @@ -180,13 +180,6 @@ void WDT_inner() { #if defined(USE_LVP) || defined(USE_THERMAL_REGULATION) // enable the deferred ADC handler once in a while if (! adc_trigger) { - /* redundant; it was already turned on earlier in this function - // in case we're in standby mode and the ADC is turned off - if (go_to_standby) { - //set_admux_voltage(); - ADC_on(); - } - */ ADC_start_measurement(); adc_deferred_enable = 1; } -- cgit v1.2.3 From a9dfc872aab50767a2e7749b70e9ed6c61e579cb Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 16 Mar 2020 02:45:25 -0600 Subject: added FETless KR4 build target, calibrated other KR4 therm faster level better --- spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h | 45 ++++++++++++++++++++++ spaghetti-monster/anduril/cfg-noctigon-kr4.h | 4 +- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h new file mode 100644 index 0000000..66177bf --- /dev/null +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h @@ -0,0 +1,45 @@ +// Noctigon KR4 (fetless) config options for Anduril +#include "cfg-noctigon-kr4.h" +// ATTINY: 1634 + +// brightness w/ SST-20 4000K LEDs: +// 0/1023: 0.35 lm +// 1/1023: 2.56 lm +// max regulated: 1740 lm +// level_calc.py 3.0 1 150 7135 0 5 1740 +#undef PWM_CHANNELS +#define PWM_CHANNELS 1 +#define RAMP_LENGTH 150 +#undef PWM1_LEVELS +#define PWM1_LEVELS 0,0,1,1,2,2,3,3,4,4,5,5,6,7,8,9,10,11,12,13,15,16,17,18,20,21,23,24,26,27,29,31,33,35,37,39,41,43,45,48,50,53,55,58,61,63,66,69,72,75,79,82,85,89,92,96,100,104,108,112,116,120,125,129,134,138,143,148,153,158,163,169,174,180,185,191,197,203,209,215,222,228,235,242,248,255,263,270,277,285,292,300,308,316,324,333,341,350,359,368,377,386,395,405,414,424,434,444,454,465,475,486,497,508,519,531,542,554,566,578,590,603,615,628,641,654,667,680,694,708,722,736,750,765,779,794,809,825,840,856,872,888,904,920,937,954,971,988,1005,1023 +#undef PWM2_LEVELS +#undef MAX_1x7135 +#define MAX_1x7135 50 +#undef MAX_Nx7135 + +#undef RAMP_SMOOTH_FLOOR +#undef RAMP_SMOOTH_CEIL +#undef RAMP_DISCRETE_FLOOR +#undef RAMP_DISCRETE_CEIL +#undef RAMP_DISCRETE_STEPS + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 130 +// 10, 30, [50], 70, 90, 110, 130 (plus [150] on turbo) +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 + +#undef MUGGLE_FLOOR +#undef MUGGLE_CEILING +#define MUGGLE_FLOOR RAMP_DISCRETE_FLOOR +#define MUGGLE_CEILING 70 + +// stop panicking at ~70% power or ~1200 lm +#undef THERM_FASTER_LEVEL +#define THERM_FASTER_LEVEL 130 +// 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-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index 7771cd4..9b810ab 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -52,8 +52,8 @@ // the KR4 runs very very hot on turbo, so be extra careful //#define THERM_HARD_TURBO_DROP -// stop panicking at ~70% power or ~600 lm -#define THERM_FASTER_LEVEL 120 +// stop panicking at ~25% power or ~1000 lm +#define THERM_FASTER_LEVEL 100 // respond to thermal changes faster #define THERMAL_WARNING_SECONDS 3 #define THERMAL_UPDATE_SPEED 1 -- cgit v1.2.3 From 84f9a0c9daf991b23d665a5dffdb3b76e6753491 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 16 Mar 2020 03:17:14 -0600 Subject: increased blink speed slightly, and added a library function to blink out 16-bit numbers --- spaghetti-monster/fsm-misc.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'spaghetti-monster') 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= 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; -- cgit v1.2.3 From 49f1b5ccd2033109814b99ea4650375e8f33a6be Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 16 Mar 2020 03:19:42 -0600 Subject: merged some misc fixes from pakutrai, cleaned up comments, removed unused symbols --- spaghetti-monster/anduril/anduril.c | 10 ++++++++-- spaghetti-monster/anduril/cfg-emisar-d18.h | 2 -- spaghetti-monster/anduril/cfg-emisar-d4.h | 4 ---- spaghetti-monster/anduril/cfg-emisar-d4s.h | 5 ----- spaghetti-monster/anduril/cfg-emisar-d4sv2.h | 14 -------------- spaghetti-monster/anduril/cfg-emisar-d4v2.h | 12 ------------ spaghetti-monster/anduril/cfg-ff-pl47.h | 5 ----- spaghetti-monster/anduril/cfg-ff-pl47g2.h | 5 ----- spaghetti-monster/anduril/cfg-ff-rot66.h | 3 --- spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h | 5 ----- spaghetti-monster/anduril/cfg-sofirn-sp36.h | 7 ------- spaghetti-monster/fsm-adc.c | 5 +++-- spaghetti-monster/fsm-adc.h | 12 +++--------- spaghetti-monster/fsm-standby.c | 4 ---- spaghetti-monster/spaghetti-monster.txt | 12 ++++-------- 15 files changed, 18 insertions(+), 87 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 469d0d8..bc2f9c6 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 @@ -275,6 +275,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 @@ -497,6 +498,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); @@ -1585,11 +1587,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); @@ -1615,7 +1619,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; @@ -1997,6 +2001,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); @@ -2007,6 +2012,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 dd43cb9..59d624b 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -119,8 +119,8 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { } #endif -// Each full cycle runs ~4X per second with just voltage enabled, -// or ~2X 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 1 #else @@ -276,6 +276,7 @@ static inline void ADC_voltage_handler() { #ifdef USE_THERMAL_REGULATION +// generally happens once per second while awake static inline void ADC_temperature_handler() { // coarse adjustment #ifndef THERM_LOOKAHEAD diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index 6283b2c..241dee4 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -52,7 +52,9 @@ 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(); @@ -67,10 +69,6 @@ void battcheck(); #ifdef USE_THERMAL_REGULATION -// default 1 seconds between thermal regulation events -#ifndef THERMAL_WARNING_SECONDS -#define THERMAL_WARNING_SECONDS 1 -#endif // try to keep temperature below 45 C #ifndef DEFAULT_THERM_CEIL #define DEFAULT_THERM_CEIL 45 @@ -83,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-standby.c b/spaghetti-monster/fsm-standby.c index 14b6df1..b002b91 100644 --- a/spaghetti-monster/fsm-standby.c +++ b/spaghetti-monster/fsm-standby.c @@ -87,10 +87,6 @@ void sleep_until_eswitch_pressed() #ifdef USE_THERMAL_REGULATION // forget what the temperature was last time we were on reset_thermal_history = 1; - // FIXME: not sure if this should be here - // (the intent is to make sure temperature gets measured before - // thermal logic gets executed) - //set_admux_therm(); #endif // go back to normal running mode 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 -- cgit v1.2.3 From b7f6dd21c396d1431e8864158d1868620ae334d6 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 16 Mar 2020 03:33:51 -0600 Subject: fixed a few things in ramping-ui, rampingiosv3, and werner's UI (just copied a few updates from anduril, particularly regarding FSM's "temperature" variable) --- spaghetti-monster/ramping-ui/ramping-ui.c | 3 +-- spaghetti-monster/rampingios/rampingiosv3.c | 12 +++++++----- spaghetti-monster/werner/werner.c | 12 +++++------- 3 files changed, 13 insertions(+), 14 deletions(-) (limited to 'spaghetti-monster') 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/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>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 -- cgit v1.2.3 From 227b54b1095e47ae9d0ab4b4c2a49862fd708559 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 16 Mar 2020 04:13:55 -0600 Subject: fixed calc_voltage_divider() (use 10-bit calibration values, not 8-bit) --- spaghetti-monster/fsm-adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 7880238..e7b7feb 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -112,7 +112,7 @@ 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<<7) - (ADC_22<<7)) / (44-22); + uint16_t adc_per_volt = ((ADC_44<<5) - (ADC_22<<5)) / (44-22); // shift incoming value into a matching position uint8_t result = ((value>>1) / adc_per_volt) + VOLTAGE_FUDGE_FACTOR; return result; -- cgit v1.2.3 From a749a489c0895388336b1f2ac532b345243fa5f7 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 16 Mar 2020 04:16:12 -0600 Subject: removed old thermal junk and voltage_lowpass junk from cfg files --- spaghetti-monster/anduril/cfg-noctigon-k1.h | 12 ------------ spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h | 5 ----- spaghetti-monster/anduril/cfg-noctigon-kr4.h | 12 ------------ 3 files changed, 29 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/cfg-noctigon-k1.h b/spaghetti-monster/anduril/cfg-noctigon-k1.h index 6a8e8ee..4db8787 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k1.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k1.h @@ -46,16 +46,8 @@ #define MUGGLE_FLOOR RAMP_DISCRETE_FLOOR #define MUGGLE_CEILING 70 -// 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 ~70% power or ~600 lm #define THERM_FASTER_LEVEL 130 -// respond to thermal changes faster -#define THERMAL_WARNING_SECONDS 3 -#define THERMAL_UPDATE_SPEED 1 -#define THERM_PREDICTION_STRENGTH 4 // easier access to thermal config mode, for Noctigon #define USE_TENCLICK_THERMAL_CONFIG @@ -65,7 +57,3 @@ #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-noctigon-kr4-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h index 66177bf..0434258 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h @@ -38,8 +38,3 @@ // stop panicking at ~70% power or ~1200 lm #undef THERM_FASTER_LEVEL #define THERM_FASTER_LEVEL 130 -// 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-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index 9b810ab..d3e6d7b 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -48,16 +48,8 @@ #define MUGGLE_FLOOR RAMP_DISCRETE_FLOOR #define MUGGLE_CEILING 65 -// optional, makes initial turbo step-down faster so first peak isn't as hot -// the KR4 runs very very hot on turbo, so be extra careful -//#define THERM_HARD_TURBO_DROP - // stop panicking at ~25% power or ~1000 lm #define THERM_FASTER_LEVEL 100 -// respond to thermal changes faster -#define THERMAL_WARNING_SECONDS 3 -#define THERMAL_UPDATE_SPEED 1 -#define THERM_PREDICTION_STRENGTH 4 // easier access to thermal config mode, for Noctigon #define USE_TENCLICK_THERMAL_CONFIG @@ -67,7 +59,3 @@ #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 - -- cgit v1.2.3 From 7134924ce13956770ff07ae5da978b6f2061b00e Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 20 Mar 2020 00:07:34 -0600 Subject: added reboot() support for tiny1634 --- spaghetti-monster/fsm-misc.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-misc.c b/spaghetti-monster/fsm-misc.c index 152f047..82be745 100644 --- a/spaghetti-monster/fsm-misc.c +++ b/spaghetti-monster/fsm-misc.c @@ -231,18 +231,20 @@ uint8_t triangle_wave(uint8_t phase) { #ifdef USE_REBOOT void reboot() { - #if 1 // WDT method, safer but larger + // put the WDT in hard reset mode, then trigger it cli(); - WDTCR = 0xD8 | WDTO_15MS; + #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) + WDTCR = 0xD8 | WDTO_15MS; + #elif (ATTINY == 1634) + // allow protected configuration changes for next 4 clock cycles + CCP = 0xD8; // magic number + // reset (WDIF + WDE), no WDIE, fastest (16ms) timing (0000) + // (DS section 8.5.2 and table 8-4) + WDTCSR = 0b10001000; + #endif sei(); wdt_reset(); while (1) {} - #else // raw assembly method, doesn't reset registers or anything - __asm__ __volatile__ ( - "cli" "\n\t" - "rjmp 0x00" "\n\t" - ); - #endif } #endif -- cgit v1.2.3 From 8d5584c789fe95a97a8385adfce8c52c572c1536 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 20 Mar 2020 00:09:04 -0600 Subject: enabled soft factory reset on KR4, raised default floor to the lowest reliable level (moon level 1 flickers or doesn't work at all on some hardware) --- spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h | 2 +- spaghetti-monster/anduril/cfg-noctigon-kr4.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h index 0434258..0e53e5f 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h @@ -23,7 +23,7 @@ #undef RAMP_DISCRETE_CEIL #undef RAMP_DISCRETE_STEPS -#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_FLOOR 3 // level 1 is unreliable #define RAMP_SMOOTH_CEIL 130 // 10, 30, [50], 70, 90, 110, 130 (plus [150] on turbo) #define RAMP_DISCRETE_FLOOR 10 diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index d3e6d7b..6f52eb3 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -38,7 +38,7 @@ #undef USE_DYNAMIC_UNDERCLOCKING #endif -#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_FLOOR 3 // level 1 is unreliable #define RAMP_SMOOTH_CEIL 120 // 10, 28, [46], 65, 83, 101, [120] #define RAMP_DISCRETE_FLOOR 10 @@ -59,3 +59,5 @@ #define THERM_CAL_OFFSET 5 +// can't reset the normal way because power is connected before the button +#define USE_SOFT_FACTORY_RESET -- cgit v1.2.3 From 52c58c46f7c9c7aced3a5eb174c88d444a6d8a57 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 21 Mar 2020 21:03:42 -0600 Subject: fixed potential eeprom corruption after turning boost/opamp chip on/off (some boost chips can make power unstable for a few ms, so we have to wait before accessing eeprom) --- spaghetti-monster/fsm-eeprom.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-eeprom.c b/spaghetti-monster/fsm-eeprom.c index 277e2b2..77352cf 100644 --- a/spaghetti-monster/fsm-eeprom.c +++ b/spaghetti-monster/fsm-eeprom.c @@ -30,6 +30,10 @@ uint8_t eeprom[EEPROM_BYTES]; #endif uint8_t load_eeprom() { + #ifdef LED_ENABLE_PIN + delay_4ms(2); // wait for power to stabilize + #endif + cli(); // check if eeprom has been initialized; abort if it hasn't uint8_t marker = eeprom_read_byte((uint8_t *)EEP_START); @@ -44,6 +48,10 @@ uint8_t load_eeprom() { } void save_eeprom() { + #ifdef LED_ENABLE_PIN + delay_4ms(2); // wait for power to stabilize + #endif + cli(); // save the actual data @@ -62,6 +70,10 @@ uint8_t eeprom_wl[EEPROM_WL_BYTES]; EEP_OFFSET_T eep_wl_prev_offset; uint8_t load_eeprom_wl() { + #ifdef LED_ENABLE_PIN + delay_4ms(2); // wait for power to stabilize + #endif + cli(); // check if eeprom has been initialized; abort if it hasn't uint8_t found = 0; @@ -87,6 +99,10 @@ uint8_t load_eeprom_wl() { } void save_eeprom_wl() { + #ifdef LED_ENABLE_PIN + delay_4ms(2); // wait for power to stabilize + #endif + cli(); // erase old state EEP_OFFSET_T offset = eep_wl_prev_offset; -- cgit v1.2.3 From 9caa6cd6daf4875856e0d91247d8e9f46fa5f2ad Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 21 Mar 2020 21:23:21 -0600 Subject: added dynamic underclocking to KR4 to increase moon runtime, fixed ramp milestone levels --- spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h | 8 ++++++-- spaghetti-monster/anduril/cfg-noctigon-kr4.h | 18 +++++------------- 2 files changed, 11 insertions(+), 15 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h index 0e53e5f..00751fd 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h @@ -13,9 +13,10 @@ #undef PWM1_LEVELS #define PWM1_LEVELS 0,0,1,1,2,2,3,3,4,4,5,5,6,7,8,9,10,11,12,13,15,16,17,18,20,21,23,24,26,27,29,31,33,35,37,39,41,43,45,48,50,53,55,58,61,63,66,69,72,75,79,82,85,89,92,96,100,104,108,112,116,120,125,129,134,138,143,148,153,158,163,169,174,180,185,191,197,203,209,215,222,228,235,242,248,255,263,270,277,285,292,300,308,316,324,333,341,350,359,368,377,386,395,405,414,424,434,444,454,465,475,486,497,508,519,531,542,554,566,578,590,603,615,628,641,654,667,680,694,708,722,736,750,765,779,794,809,825,840,856,872,888,904,920,937,954,971,988,1005,1023 #undef PWM2_LEVELS +#undef DEFAULT_LEVEL +#define DEFAULT_LEVEL 50 #undef MAX_1x7135 -#define MAX_1x7135 50 -#undef MAX_Nx7135 +#define MAX_1x7135 150 #undef RAMP_SMOOTH_FLOOR #undef RAMP_SMOOTH_CEIL @@ -38,3 +39,6 @@ // stop panicking at ~70% power or ~1200 lm #undef THERM_FASTER_LEVEL #define THERM_FASTER_LEVEL 130 +#undef MIN_THERM_STEPDOWN +#define MIN_THERM_STEPDOWN DEFAULT_LEVEL + diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index 6f52eb3..98dc209 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -24,19 +24,10 @@ #define RAMP_LENGTH 150 #define PWM1_LEVELS 0,0,1,1,2,2,3,3,4,4,5,6,7,8,9,10,11,13,14,15,17,19,20,22,24,26,28,30,33,35,38,40,43,46,49,52,55,59,62,66,70,74,78,82,86,91,96,100,105,111,116,121,127,133,139,145,151,158,165,172,179,186,193,201,209,217,225,234,243,251,261,270,280,289,299,310,320,331,342,353,364,376,388,400,412,425,438,451,464,478,492,506,521,536,551,566,582,597,614,630,647,664,681,699,717,735,754,772,792,811,831,851,871,892,913,935,956,978,1001,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,51,79,109,138,168,198,229,260,292,324,357,390,423,457,492,527,562,598,634,671,708,746,784,822,861,901,941,982,1023 -#define MAX_1x7135 46 -#define MAX_Nx7135 120 - -// the entire ramp is regulated; don't blink halfway up -#ifdef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_MIDDLE -#endif - -// don't slow down at low levels; this isn't that sort of light -// (it needs to stay at full speed for the 10-bit PWM to work) -#ifdef USE_DYNAMIC_UNDERCLOCKING -#undef USE_DYNAMIC_UNDERCLOCKING -#endif +#define DEFAULT_LEVEL 46 +#define MAX_1x7135 120 +#define HALFSPEED_LEVEL 10 +#define QUARTERSPEED_LEVEL 2 #define RAMP_SMOOTH_FLOOR 3 // level 1 is unreliable #define RAMP_SMOOTH_CEIL 120 @@ -50,6 +41,7 @@ // stop panicking at ~25% power or ~1000 lm #define THERM_FASTER_LEVEL 100 +#define MIN_THERM_STEPDOWN DEFAULT_LEVEL // easier access to thermal config mode, for Noctigon #define USE_TENCLICK_THERMAL_CONFIG -- cgit v1.2.3 From ef1d96b85485000e70ef5423c9494eb91286d3d7 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 26 Mar 2020 03:46:47 -0600 Subject: made thermal regulation use a smaller target window, and prioritize cooling more --- spaghetti-monster/fsm-adc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index e7b7feb..edf1809 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -362,7 +362,7 @@ static inline void ADC_temperature_handler() { // (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++) { + for(uint8_t foo=0; foo<3; foo++) { if (offset > 0) { offset --; } else if (offset < 0) { @@ -371,8 +371,8 @@ static inline void ADC_temperature_handler() { } // Too hot? - // (if it's too hot and still getting warmer...) - if ((offset > 0) && (diff > 0)) { + // (if it's too hot and not getting cooler...) + if ((offset > 0) && (diff > -1)) { // accumulated error isn't big enough yet to send a warning if (warning_threshold > 0) { warning_threshold -= offset; -- cgit v1.2.3 From b6059fdcaad276f65d55e73ce8b3003e884684ad Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 26 Mar 2020 03:47:46 -0600 Subject: Noctigon KR4 needed tighter/faster thermal response, and Hank wants RGB rainbow to be default instead of voltage mode. --- spaghetti-monster/anduril/cfg-noctigon-kr4.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index 98dc209..01310b5 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -6,7 +6,7 @@ #define USE_AUX_RGB_LEDS //#define USE_AUX_RGB_LEDS_WHILE_ON //#define USE_INDICATOR_LED_WHILE_RAMPING -#define RGB_LED_OFF_DEFAULT 0x18 // low, voltage +#define RGB_LED_OFF_DEFAULT 0x17 // low, rainbow #define RGB_LED_LOCKOUT_DEFAULT 0x37 // blinking, rainbow // enable blinking aux LEDs @@ -42,6 +42,8 @@ // stop panicking at ~25% power or ~1000 lm #define THERM_FASTER_LEVEL 100 #define MIN_THERM_STEPDOWN DEFAULT_LEVEL +#define THERM_LOOKAHEAD 6 +#define THERM_NEXT_WARNING_THRESHOLD 12 // easier access to thermal config mode, for Noctigon #define USE_TENCLICK_THERMAL_CONFIG -- cgit v1.2.3 From 691abdd22f83a9e8a35e2887e6345fb4234fba7c Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 28 Mar 2020 19:44:26 -0600 Subject: added a Noctigon KR4 219 (75% FET) build target --- spaghetti-monster/anduril/cfg-noctigon-kr4-219.h | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 spaghetti-monster/anduril/cfg-noctigon-kr4-219.h (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-219.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-219.h new file mode 100644 index 0000000..0cfccf2 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-219.h @@ -0,0 +1,11 @@ +// Noctigon KR4 (75% FET) config options for Anduril +#include "cfg-noctigon-kr4.h" +// ATTINY: 1634 + +// don't turn off first channel at turbo level +#undef PWM1_LEVELS +#define PWM1_LEVELS 0,0,1,1,2,2,3,3,4,4,5,6,7,8,9,10,11,13,14,15,17,19,20,22,24,26,28,30,33,35,38,40,43,46,49,52,55,59,62,66,70,74,78,82,86,91,96,100,105,111,116,121,127,133,139,145,151,158,165,172,179,186,193,201,209,217,225,234,243,251,261,270,280,289,299,310,320,331,342,353,364,376,388,400,412,425,438,451,464,478,492,506,521,536,551,566,582,597,614,630,647,664,681,699,717,735,754,772,792,811,831,851,871,892,913,935,956,978,1001,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023 +// 75% FET power +#undef PWM2_LEVELS +#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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,39,60,82,104,126,149,172,195,219,243,268,293,318,343,369,396,422,449,476,504,531,560,588,617,646,676,706,737,768 + -- cgit v1.2.3 From 83f1f66ca9760bcb968b2104d5f270804663961c Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Apr 2020 03:10:56 -0600 Subject: anduril: made aux RGB rainbow mode speed configurable per build target --- spaghetti-monster/anduril/anduril.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index cb48b45..e87a30c 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -355,6 +355,9 @@ const PROGMEM uint8_t rgb_led_colors[] = { #ifndef RGB_LED_LOCKOUT_DEFAULT #define RGB_LED_LOCKOUT_DEFAULT 0x37 // blinking, rainbow #endif +#ifndef RGB_RAINBOW_SPEED +#define RGB_RAINBOW_SPEED 0x0f // change color every 16 frames +#endif uint8_t rgb_led_off_mode = RGB_LED_OFF_DEFAULT; uint8_t rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT; #endif @@ -2400,7 +2403,7 @@ void rgb_led_update(uint8_t mode, uint8_t arg) { } else if (color == 7) { // rainbow uint8_t speed = 0x03; // awake speed - if (go_to_standby) speed = 0x0f; // asleep speed + if (go_to_standby) speed = RGB_RAINBOW_SPEED; // asleep speed if (0 == (arg & speed)) { rainbow = (rainbow + 1) % 6; } -- cgit v1.2.3 From d9105a32fee77822745c25e3c4b778cc079155da Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Apr 2020 03:12:25 -0600 Subject: KR4-noFET: made candle mode vary more since the ramp is stretched out, raised therm faster level --- spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h index 00751fd..19cbc23 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h @@ -36,9 +36,12 @@ #define MUGGLE_FLOOR RAMP_DISCRETE_FLOOR #define MUGGLE_CEILING 70 -// stop panicking at ~70% power or ~1200 lm +// make candle mode wobble more +#define CANDLE_AMPLITUDE 32 + +// stop panicking at ~90% power or ~1600 lm #undef THERM_FASTER_LEVEL -#define THERM_FASTER_LEVEL 130 +#define THERM_FASTER_LEVEL 143 #undef MIN_THERM_STEPDOWN #define MIN_THERM_STEPDOWN DEFAULT_LEVEL -- cgit v1.2.3 From 43eec5d7b84f1ac617519723373850733d3adcb1 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Apr 2020 03:17:24 -0600 Subject: made thermal response larger when error is large, smaller when error is small (helps on KR4, but will probably need to add the response magnitude thing to adjust speed per build target) --- spaghetti-monster/fsm-adc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index edf1809..760acc4 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -377,11 +377,17 @@ static inline void ADC_temperature_handler() { if (warning_threshold > 0) { warning_threshold -= offset; } else { // error is big enough; send a warning - warning_threshold = THERM_NEXT_WARNING_THRESHOLD - offset; + //warning_threshold = THERM_NEXT_WARNING_THRESHOLD - offset; // how far above the ceiling? //int16_t howmuch = offset * THERM_RESPONSE_MAGNITUDE / 128; - int16_t howmuch = offset; + //int16_t howmuch = offset; + // increase the amount, except for small values + // 1:1, 2:1, 3:3, 4:5, 6:9, 8:13, 10:17, 40:77 + int16_t howmuch = offset + offset - 3; + if (howmuch < 1) howmuch = 1; + warning_threshold = THERM_NEXT_WARNING_THRESHOLD - (uint8_t)howmuch; + // send a warning emit(EV_temperature_high, howmuch); } -- cgit v1.2.3 From 536e9c0d3e89fea0e37a840c0c72136c25f71889 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Apr 2020 03:29:43 -0600 Subject: added tweakable thermal_response_magnitude option, adjusted KR4 thermal vars, made KR4 rainbow mode faster --- spaghetti-monster/anduril/cfg-noctigon-kr4.h | 4 ++-- spaghetti-monster/fsm-adc.c | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'spaghetti-monster') diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index 01310b5..66c5a28 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -8,6 +8,7 @@ //#define USE_INDICATOR_LED_WHILE_RAMPING #define RGB_LED_OFF_DEFAULT 0x17 // low, rainbow #define RGB_LED_LOCKOUT_DEFAULT 0x37 // blinking, rainbow +#define RGB_RAINBOW_SPEED 0x03 // half a second per color // enable blinking aux LEDs #define TICK_DURING_STANDBY @@ -42,8 +43,7 @@ // stop panicking at ~25% power or ~1000 lm #define THERM_FASTER_LEVEL 100 #define MIN_THERM_STEPDOWN DEFAULT_LEVEL -#define THERM_LOOKAHEAD 6 -#define THERM_NEXT_WARNING_THRESHOLD 12 +#define THERM_NEXT_WARNING_THRESHOLD 16 // easier access to thermal config mode, for Noctigon #define USE_TENCLICK_THERMAL_CONFIG diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 760acc4..68361ae 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -286,21 +286,21 @@ static inline void ADC_voltage_handler() { static inline void ADC_temperature_handler() { // coarse adjustment #ifndef THERM_LOOKAHEAD - #define THERM_LOOKAHEAD 4 // can be tweaked per build target + #define THERM_LOOKAHEAD 4 #endif // 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) + // how proportional should the adjustments be? #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? + // 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 @@ -377,14 +377,14 @@ static inline void ADC_temperature_handler() { 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; - // increase the amount, except for small values - // 1:1, 2:1, 3:3, 4:5, 6:9, 8:13, 10:17, 40:77 - int16_t howmuch = offset + offset - 3; + // original method works, but is too slow on some small hosts: + // (and typically has a minimum response magnitude of 2 instead of 1) + // int16_t howmuch = offset; + // ... so increase the amount, except for small values + // (for example, 1:1, 2:1, 3:3, 4:5, 6:9, 8:13, 10:17, 40:77) + // ... and let us tune the response per build target if desired + int16_t howmuch = (offset + offset - 3) * THERM_RESPONSE_MAGNITUDE / 128; if (howmuch < 1) howmuch = 1; warning_threshold = THERM_NEXT_WARNING_THRESHOLD - (uint8_t)howmuch; -- cgit v1.2.3