From 3d12b7066d27b591e0283e20ed066bc66e29fbe4 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 10 Nov 2023 21:34:40 -0700 Subject: refactor checkpoint: splitting MCU-specific code into arch/$MCU.[ch] Phew, that's a lot of changes! And there's still a lot more to do... --- fsm/adc.c | 159 ++++++------------------------------------------ fsm/adc.h | 12 ++-- fsm/main.c | 62 +------------------ fsm/misc.c | 22 ------- fsm/misc.h | 4 -- fsm/pcint.c | 54 +--------------- fsm/pcint.h | 6 +- fsm/spaghetti-monster.h | 9 ++- fsm/wdt.c | 78 +----------------------- fsm/wdt.h | 7 ++- 10 files changed, 47 insertions(+), 366 deletions(-) (limited to 'fsm') diff --git a/fsm/adc.c b/fsm/adc.c index 31b250f..6d4eeb1 100644 --- a/fsm/adc.c +++ b/fsm/adc.c @@ -16,57 +16,14 @@ static inline void set_admux_therm() { - #if (ATTINY == 1634) - ADMUX = ADMUX_THERM; - #elif (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - ADMUX = ADMUX_THERM | (1 << ADLAR); - #elif (ATTINY == 841) // FIXME: not tested - ADMUXA = ADMUXA_THERM; - ADMUXB = ADMUXB_THERM; - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - ADC0.MUXPOS = ADC_MUXPOS_TEMPSENSE_gc; // read temperature - ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_INTREF_gc; // Internal ADC reference - #else - #error Unrecognized MCU type - #endif + hwdef_set_admux_therm(); adc_channel = 1; adc_sample_count = 0; // first result is unstable ADC_start_measurement(); } inline void set_admux_voltage() { - #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 == 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 - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - #ifdef USE_VOLTAGE_DIVIDER // 1.1V / ADC input pin - // verify that this is correct!!! untested - ADC0.MUXPOS = ADMUX_VOLTAGE_DIVIDER; // read the requested ADC pin - ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_INTREF_gc; // Use internal ADC reference - #else // VCC / 1.1V reference - ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc; // read internal reference - ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_VDDREF_gc; // Vdd (Vcc) be ADC reference - #endif - #else - #error Unrecognized MCU type - #endif + hwdef_set_admux_voltage(); adc_channel = 0; adc_sample_count = 0; // first result is unstable ADC_start_measurement(); @@ -74,79 +31,19 @@ inline void set_admux_voltage() { #ifdef TICK_DURING_STANDBY -inline void adc_sleep_mode() { // needs a special sleep mode to get accurate measurements quickly // ... full power-down ends up using more power overall, and causes // some weird issues when the MCU doesn't stay awake enough cycles // to complete a reading - #ifdef SLEEP_MODE_ADC - // attiny1634 - set_sleep_mode(SLEEP_MODE_ADC); - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - set_sleep_mode(SLEEP_MODE_STANDBY); - #else - #error No ADC sleep mode defined for this hardware. - #endif -} + #define adc_sleep_mode mcu_adc_sleep_mode #endif -inline void ADC_start_measurement() { - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 841) || (ATTINY == 1634) - ADCSRA |= (1 << ADSC) | (1 << ADIE); - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - ADC0.INTCTRL |= ADC_RESRDY_bm; // enable interrupt - ADC0.COMMAND |= ADC_STCONV_bm; // Start the ADC conversions - #else - #error unrecognized MCU type - #endif -} +#define ADC_start_measurement mcu_adc_start_measurement // set up ADC for reading battery voltage -inline void ADC_on() -{ - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634) - set_admux_voltage(); - #ifdef USE_VOLTAGE_DIVIDER - // disable digital input on divider pin to reduce power consumption - VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); - #else - // disable digital input on VCC pin to reduce power consumption - //VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); // FIXME: unsure how to handle for VCC pin - #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, auto-retrigger, prescale - ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL; - // end tiny25/45/85 - #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, auto-retrigger, prescale - ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL; - //ADCSRA |= (1 << ADSC); // start measuring - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - VREF.CTRLA |= VREF_ADC0REFSEL_1V1_gc; // Set Vbg ref to 1.1V - // Enabled, free-running (aka, auto-retrigger), run in standby - ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm | ADC_RUNSTBY_bm; - // set a INITDLY value because the AVR manual says so (section 30.3.5) - // (delay 1st reading until Vref is stable) - ADC0.CTRLD |= ADC_INITDLY_DLY16_gc; - set_admux_voltage(); - #else - #error Unrecognized MCU type - #endif -} - -inline void ADC_off() { - #ifdef AVRXMEGA3 // ATTINY816, 817, etc - ADC0.CTRLA &= ~(ADC_ENABLE_bm); // disable the ADC - #else - ADCSRA &= ~(1<>= 8; // Divide result to get Kelvin - m = (temp << 6); // left align it - } - else { m = (ADC0.RES << 6); } // voltage, force left-alignment - + #ifdef MCU_ADC_RESULT_PER_TYPE + // thermal, convert ADC reading to left-aligned Kelvin + if (channel) m = mcu_adc_result_temp(); + else m = mcu_adc_result_volts(); #else - m = ADC; + m = mcu_adc_result(); #endif adc_raw[channel] = m; @@ -235,11 +118,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. - #ifdef AVRXMEGA3 // ATTINY816, 817, etc - pseudo_rand_seed += ADC0.RESL; // right aligned, not left... so should be equivalent? - #else - pseudo_rand_seed += (ADCL >> 6) + (ADCH << 2); - #endif + pseudo_rand_seed += mcu_adc_lsb(); #endif // the ADC triggers repeatedly when it's on, but we only need to run the @@ -373,9 +252,9 @@ static inline void ADC_voltage_handler() { if (lvp_timer) { lvp_timer --; } else { // it has been long enough since the last warning - #ifdef DUAL_VOLTAGE_FLOOR - if (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) || (voltage < DUAL_VOLTAGE_LOW_LOW)) { - #else + #ifdef DUAL_VOLTAGE_FLOOR + if (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) || (voltage < DUAL_VOLTAGE_LOW_LOW)) { + #else if (voltage < VOLTAGE_LOW) { #endif // send out a warning @@ -440,6 +319,8 @@ static inline void ADC_temperature_handler() { // let the UI see the current temperature in C // Convert ADC units to Celsius (ish) + // FIXME: call something in arch/$mcu.h or hwdef.h + // instead of calculating this here #ifndef USE_EXTERNAL_TEMP_SENSOR // onboard sensor for attiny25/45/85/1634 temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; diff --git a/fsm/adc.h b/fsm/adc.h index 1bb67ed..e4046a4 100644 --- a/fsm/adc.h +++ b/fsm/adc.h @@ -102,11 +102,15 @@ static inline void ADC_temperature_handler(); #endif // ifdef USE_THERMAL_REGULATION -inline void ADC_on(); -inline void ADC_off(); -inline void ADC_start_measurement(); +//inline void ADC_on(); +#define ADC_on mcu_adc_on +//inline void ADC_off(); +#define ADC_off mcu_adc_off +//inline void ADC_start_measurement(); +#define ADC_start_measurement mcu_adc_start_measurement #ifdef TICK_DURING_STANDBY -inline void adc_sleep_mode(); + //inline void adc_sleep_mode(); + #define adc_sleep_mode mcu_adc_sleep_mode #endif diff --git a/fsm/main.c b/fsm/main.c index 0524115..1c01878 100644 --- a/fsm/main.c +++ b/fsm/main.c @@ -23,66 +23,6 @@ ISR(TIMER1_COMPA_vect) { } #endif -// FIXME: hw_setup() shouldn't be here ... move it entirely to hwdef files -#if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) -static inline void hw_setup() { - #if !defined(USE_GENERIC_HWDEF_SETUP) - hwdef_setup(); - #else - // configure PWM channels - #if PWM_CHANNELS >= 1 - DDRB |= (1 << PWM1_PIN); - TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) - TCCR0A = PHASE; - #if (PWM1_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - // tint ramping needs second channel enabled, - // despite PWM_CHANNELS being only 1 - #if (PWM_CHANNELS >= 2) || defined(USE_TINT_RAMPING) - DDRB |= (1 << PWM2_PIN); - #if (PWM2_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - #if PWM_CHANNELS >= 3 - DDRB |= (1 << PWM3_PIN); - #if (PWM3_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - #if PWM_CHANNELS >= 4 - // 4th PWM channel is ... not actually supported in hardware :( - DDRB |= (1 << PWM4_PIN); - //OCR1C = 255; // Set ceiling value to maximum - TCCR1 = 1< -#include +#include "arch/mcu.h" // include project definitions to help with recognizing symbols #include "fsm/events.h" @@ -39,6 +38,10 @@ #include "arch/delay.h" #endif +////////// include all the .c files ////////// + +#include "arch/mcu.c" + #ifdef USE_DEBUG_BLINK #define DEBUG_FLASH PWM1_LVL = 64; delay_4ms(2); PWM1_LVL = 0; void debug_blink(uint8_t num) { diff --git a/fsm/wdt.c b/fsm/wdt.c index 64f006e..1095d44 100644 --- a/fsm/wdt.c +++ b/fsm/wdt.c @@ -7,85 +7,9 @@ #include #include -// *** Note for the AVRXMEGA3 (1-Series, eg 816 and 817), the WDT -// is not used for time-based interrupts. A new peripheral, the -// Periodic Interrupt Timer ("PIT") is used for this purpose. - -void WDT_on() -{ - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - // interrupt every 16ms - //cli(); // Disable interrupts - wdt_reset(); // Reset the WDT - WDTCR |= (1< 0) {} // make sure the register is ready to be updated - RTC.PITCTRLA = RTC_PERIOD_CYC512_gc | RTC_PITEN_bm; // Period = 16ms, enable the PI Timer - #else - #error Unrecognized MCU type - #endif -} - -#ifdef TICK_DURING_STANDBY -inline void WDT_slow() -{ - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - // interrupt slower - //cli(); // Disable interrupts - wdt_reset(); // Reset the WDT - WDTCR |= (1< 0) {} // make sure the register is ready to be updated - RTC.PITCTRLA = (1<<6) | (STANDBY_TICK_SPEED<<3) | RTC_PITEN_bm; // Set period, enable the PI Timer - #else - #error Unrecognized MCU type - #endif -} -#endif - -inline void WDT_off() -{ - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - //cli(); // Disable interrupts - wdt_reset(); // Reset the WDT - MCUSR &= ~(1< 0) {} // make sure the register is ready to be updated - RTC.PITCTRLA = 0; // Disable the PI Timer - #else - #error Unrecognized MCU type - #endif -} - // clock tick -- this runs every 16ms (62.5 fps) -#ifdef AVRXMEGA3 // ATTINY816, 817, etc -ISR(RTC_PIT_vect) { - RTC.PITINTFLAGS = RTC_PI_bm; // clear the PIT interrupt flag -#else ISR(WDT_vect) { -#endif + mcu_wdt_vect_clear(); irq_wdt = 1; // WDT event happened } diff --git a/fsm/wdt.h b/fsm/wdt.h index abf34c5..98eaf25 100644 --- a/fsm/wdt.h +++ b/fsm/wdt.h @@ -6,8 +6,11 @@ #define TICKS_PER_SECOND 62 -void WDT_on(); -inline void WDT_off(); +//void WDT_on(); +//inline void WDT_off(); +#define WDT_on mcu_wdt_active +#define WDT_slow mcu_wdt_standby +#define WDT_off mcu_wdt_stop volatile uint8_t irq_wdt = 0; // WDT interrupt happened? -- cgit v1.2.3 From 66b15ad887c2ae74bc7019c006549ac451557a6d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:46:34 -0700 Subject: temporary fix for aux LEDs on avrdd; needs proper refactoring --- fsm/misc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'fsm') diff --git a/fsm/misc.c b/fsm/misc.c index 5d58f52..fa8ddd7 100644 --- a/fsm/misc.c +++ b/fsm/misc.c @@ -118,7 +118,8 @@ uint8_t blink_num(uint8_t num) { #ifdef USE_INDICATOR_LED void indicator_led(uint8_t lvl) { switch (lvl) { - #ifdef AVRXMEGA3 // ATTINY816, 817, etc + // FIXME: move this logic to arch/* + #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc case 0: // indicator off AUXLED_PORT.DIRSET = (1 << AUXLED_PIN); // set as output @@ -192,7 +193,8 @@ void indicator_led_auto() { void button_led_set(uint8_t lvl) { switch (lvl) { - #ifdef AVRXMEGA3 // ATTINY816, 817, etc + // FIXME: move this logic to arch/* + #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc case 0: // LED off BUTTON_LED_PORT.DIRSET = (1 << BUTTON_LED_PIN); // set as output @@ -240,7 +242,8 @@ void rgb_led_set(uint8_t value) { uint8_t pin = pins[i]; switch (lvl) { - #ifdef AVRXMEGA3 // ATTINY816, 817, etc + // FIXME: move this logic to arch/* + #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc case 0: // LED off AUXLED_RGB_PORT.DIRSET = (1 << pin); // set as output -- cgit v1.2.3 From e6909adcb1d44797e097dcf93ee7459276a4516a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:47:40 -0700 Subject: moved prevent_reboot_loop() and some other junk out of fsm/main.c --- fsm/main.c | 50 +++----------------------------------------------- 1 file changed, 3 insertions(+), 47 deletions(-) (limited to 'fsm') diff --git a/fsm/main.c b/fsm/main.c index 1c01878..bb93862 100644 --- a/fsm/main.c +++ b/fsm/main.c @@ -6,46 +6,14 @@ #include "fsm/main.h" -#if PWM_CHANNELS == 4 -#ifdef AVRXMEGA3 // ATTINY816, 817, etc -#error 4-channel PWM not currently set up for the AVR 1-Series -#endif -// 4th PWM channel requires manually turning the pin on/off via interrupt :( -ISR(TIMER1_OVF_vect) { - //bitClear(PORTB, 3); - PORTB &= 0b11110111; - //PORTB |= 0b00001000; -} -ISR(TIMER1_COMPA_vect) { - //if (!bitRead(TIFR,TOV1)) bitSet(PORTB, 3); - if (! (TIFR & (1<= 1 - PWM1_LVL = 0; - #endif - #if PWM_CHANNELS >= 2 - PWM2_LVL = 0; - #endif - #if PWM_CHANNELS >= 3 - PWM3_LVL = 0; - #endif - #if PWM_CHANNELS >= 4 - PWM4_LVL = 255; // inverted :( - #endif - #endif standby_mode(); } -- cgit v1.2.3 From 76db685f66baa7787ad94ce91585e7cba8b94cfb Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:56:17 -0700 Subject: started refactoring fsm/adc.*, but need a checkpoint before continuing --- fsm/adc.c | 23 ++++------------------- fsm/adc.h | 15 ++++++++++----- 2 files changed, 14 insertions(+), 24 deletions(-) (limited to 'fsm') diff --git a/fsm/adc.c b/fsm/adc.c index 6d4eeb1..13a76b6 100644 --- a/fsm/adc.c +++ b/fsm/adc.c @@ -15,14 +15,14 @@ #include -static inline void set_admux_therm() { +static inline void adc_therm_mode() { hwdef_set_admux_therm(); adc_channel = 1; adc_sample_count = 0; // first result is unstable ADC_start_measurement(); } -inline void set_admux_voltage() { +void adc_voltage_mode() { hwdef_set_admux_voltage(); adc_channel = 0; adc_sample_count = 0; // first result is unstable @@ -30,21 +30,6 @@ inline void set_admux_voltage() { } -#ifdef TICK_DURING_STANDBY - // needs a special sleep mode to get accurate measurements quickly - // ... full power-down ends up using more power overall, and causes - // some weird issues when the MCU doesn't stay awake enough cycles - // to complete a reading - #define adc_sleep_mode mcu_adc_sleep_mode -#endif - -#define ADC_start_measurement mcu_adc_start_measurement - -// set up ADC for reading battery voltage -#define ADC_on mcu_adc_on -// stop the ADC -#define ADC_off mcu_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 @@ -160,7 +145,7 @@ void adc_deferred() { ADC_voltage_handler(); #ifdef USE_THERMAL_REGULATION // set the correct type of measurement for next time - if (! go_to_standby) set_admux_therm(); + if (! go_to_standby) adc_therm_mode(); #endif } #endif @@ -170,7 +155,7 @@ void adc_deferred() { ADC_temperature_handler(); #ifdef USE_LVP // set the correct type of measurement for next time - set_admux_voltage(); + adc_voltage_mode(); #endif } #endif diff --git a/fsm/adc.h b/fsm/adc.h index e4046a4..65d7d6c 100644 --- a/fsm/adc.h +++ b/fsm/adc.h @@ -32,6 +32,9 @@ volatile uint8_t adc_reset = 2; #endif #endif + +void adc_voltage_mode(); + #ifdef TICK_DURING_STANDBY volatile uint8_t adc_active_now = 0; // sleep LVP needs a different sleep mode #endif @@ -103,14 +106,16 @@ static inline void ADC_temperature_handler(); //inline void ADC_on(); -#define ADC_on mcu_adc_on +#define ADC_on adc_voltage_mode //inline void ADC_off(); #define ADC_off mcu_adc_off //inline void ADC_start_measurement(); #define ADC_start_measurement mcu_adc_start_measurement -#ifdef TICK_DURING_STANDBY - //inline void adc_sleep_mode(); - #define adc_sleep_mode mcu_adc_sleep_mode -#endif +// needs a special sleep mode to get accurate measurements quickly +// ... full power-down ends up using more power overall, and causes +// some weird issues when the MCU doesn't stay awake enough cycles +// to complete a reading +//inline void adc_sleep_mode(); +#define adc_sleep_mode mcu_adc_sleep_mode -- cgit v1.2.3 From fdb47b96e86924bf81852205b2b3078b8b21d040 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 21 Nov 2023 02:52:00 -0700 Subject: got ADC voltage+temp working on avrdd... but broke all other builds/MCUs This patch changes the ADC code to use two internal standard units, and everything else must convert to these units: - FSM Volts: centiVolts << 6 (range 0 to 10.24 V per cell) - FSM Kelvin: Kelvin << 6 (range 0 to 1024 K) UI-level voltage is still "Volts * 10", and temperature is still Celsius. FSM expects functions to be provided, to convert from the hardware's raw ADC measurements to these internal units: `voltage_raw2cooked()` and `temp_raw2cooked()`. Defaults will be provided by arch/*.[ch] for each MCU type, or the hwdef can make its own. Anyway, gotta go fix all the other MCUs and builds now. :( --- fsm/adc.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'fsm') diff --git a/fsm/adc.c b/fsm/adc.c index 13a76b6..73e282d 100644 --- a/fsm/adc.c +++ b/fsm/adc.c @@ -30,6 +30,7 @@ void adc_voltage_mode() { } +#if 0 #ifdef USE_VOLTAGE_DIVIDER static inline uint8_t calc_voltage_divider(uint16_t value) { // use 9.7 fixed-point to get sufficient precision @@ -44,6 +45,7 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { return result; } #endif +#endif // Each full cycle runs ~2X per second with just voltage enabled, // or ~1X per second with voltage and temperature. @@ -67,7 +69,6 @@ ISR(ADC_vect) { // update the latest value #ifdef MCU_ADC_RESULT_PER_TYPE - // thermal, convert ADC reading to left-aligned Kelvin if (channel) m = mcu_adc_result_temp(); else m = mcu_adc_result_volts(); #else @@ -208,6 +209,19 @@ static inline void ADC_voltage_handler() { #endif else measurement = adc_smooth[0]; + // convert raw ADC value to FSM voltage units: (V * 100) << 6 + // 0 .. 65535 = 0.0V .. 10.24V + measurement = voltage_raw2cooked(measurement) / (10 << 5); + + // calculate actual voltage: volts * 10 + // TODO: should be (volts * 40) for extra precision + voltage = (measurement + VOLTAGE_FUDGE_FACTOR + #ifdef USE_VOLTAGE_CORRECTION + + VOLT_CORR - 7 + #endif + ) >> 1; + + #if 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, @@ -231,6 +245,7 @@ static inline void ADC_voltage_handler() { #endif ) >> 1; #endif + #endif // if low, callback EV_voltage_low / EV_voltage_critical // (but only if it has been more than N seconds since last call) @@ -290,8 +305,14 @@ static inline void ADC_temperature_handler() { } // latest 16-bit ADC reading - uint16_t measurement = adc_smooth[1]; + // convert raw ADC value to Kelvin << 6 + // 0 .. 65535 = 0 K .. 1024 K + uint16_t measurement = temp_raw2cooked(adc_smooth[1]); + // (Kelvin << 6) to Celsius + temperature = (measurement>>6) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; + + #if 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, @@ -313,6 +334,12 @@ static inline void ADC_temperature_handler() { // external sensor temperature = EXTERN_TEMP_FORMULA(measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL; #endif + #endif + + // instead of (K << 6), use (K << 1) now + // TODO: use more precision, if it can be done without overflow in 16 bits + // (and still work on attiny85 without increasing ROM size) + measurement = measurement >> 5; // how much has the temperature changed between now and a few seconds ago? int16_t diff; -- cgit v1.2.3 From baaa035cf93340b8f2c626bdba47e8066cf40067 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 22 Nov 2023 05:34:26 -0700 Subject: ADC voltage: battcheck 3 digits, fixed t1616, switched back to 8-bit internal volt unit Before this branch, `voltage` was 6 bits: Volts * 10 A couple patches ago, I upgraded it to 16 bits: 65535 * Volts / 10.24 That costs too much extra ROM on attiny85 though, for extra precision it doesn't even use... so I switched back to an 8-bit value. It's still more precise than before though: Volts * 40 ... and battcheck displays an extra digit now, on devices with ROM for it. ... and battcheck waits a second to get a more accurate measurement before displaying the first value. It has *much* less variation between first and later readings now. Also: - got t1616 builds working again (tested fc13 and thefreeman-boost-fwaa) - upgraded t1616 voltage and temp to 12-bit (10 bits + 4x oversampling) - removed expensive temp conversion from t1616 ADC interrupt - recalibrated t1616 bogomips again; runs faster after interrupt fix - increased t1616 internal VDD measurement resolution by 36% (1.5V Vref, not 1.1V) - fixed sloppy setting of Vref bits I still need to test / update other t1616 builds, and fix all the t85 + t1634 code and build targets. --- fsm/adc.c | 47 +++++++++++++++++++++++++++++------------------ fsm/adc.h | 4 ++-- 2 files changed, 31 insertions(+), 20 deletions(-) (limited to 'fsm') diff --git a/fsm/adc.c b/fsm/adc.c index 73e282d..97dfc93 100644 --- a/fsm/adc.c +++ b/fsm/adc.c @@ -209,10 +209,16 @@ static inline void ADC_voltage_handler() { #endif else measurement = adc_smooth[0]; - // convert raw ADC value to FSM voltage units: (V * 100) << 6 - // 0 .. 65535 = 0.0V .. 10.24V - measurement = voltage_raw2cooked(measurement) / (10 << 5); - + // convert raw ADC value to FSM voltage units: Volts * 40 + // 0 .. 200 = 0.0V .. 5.0V + voltage = voltage_raw2cooked(measurement) + + (VOLTAGE_FUDGE_FACTOR << 1) + #ifdef USE_VOLTAGE_CORRECTION + + ((VOLT_CORR - 7) << 1) + #endif + ; + + /* // calculate actual voltage: volts * 10 // TODO: should be (volts * 40) for extra precision voltage = (measurement + VOLTAGE_FUDGE_FACTOR @@ -220,6 +226,7 @@ static inline void ADC_voltage_handler() { + VOLT_CORR - 7 #endif ) >> 1; + */ #if 0 // values stair-step between intervals of 64, with random variations @@ -433,33 +440,37 @@ static inline void ADC_temperature_handler() { #ifdef USE_BATTCHECK #ifdef BATTCHECK_4bars PROGMEM const uint8_t voltage_blinks[] = { - 30, 35, 38, 40, 42, 99, + 4*30, 4*35, 4*38, 4*40, 4*42, 255, }; #endif #ifdef BATTCHECK_6bars PROGMEM const uint8_t voltage_blinks[] = { - 30, 34, 36, 38, 40, 41, 43, 99, + 4*30, 4*34, 4*36, 4*38, 4*40, 4*41, 4*43, 255, }; #endif #ifdef BATTCHECK_8bars PROGMEM const uint8_t voltage_blinks[] = { - 30, 33, 35, 37, 38, 39, 40, 41, 42, 99, + 4*30, 4*33, 4*35, 4*37, 4*38, 4*39, 4*40, 4*41, 4*42, 255, }; #endif void battcheck() { #ifdef BATTCHECK_VpT - blink_num(voltage); - #else - uint8_t i; - for(i=0; - voltage >= pgm_read_byte(voltage_blinks + i); - i++) {} - #ifdef DONT_DELAY_AFTER_BATTCHECK - blink_digit(i); + blink_num(voltage / 4); + #ifdef USE_EXTRA_BATTCHECK_DIGIT + // 0 1 2 3 --> 0 2 5 7, representing x.x00 x.x25 x.x50 x.x75 + blink_num(((voltage % 4)<<1) + ((voltage % 4)>>1)); + #endif #else - if (blink_digit(i)) - nice_delay_ms(1000); - #endif + uint8_t i; + for(i=0; + voltage >= pgm_read_byte(voltage_blinks + i); + i++) {} + #ifdef DONT_DELAY_AFTER_BATTCHECK + blink_digit(i); + #else + if (blink_digit(i)) + nice_delay_ms(1000); + #endif #endif } #endif diff --git a/fsm/adc.h b/fsm/adc.h index 65d7d6c..0c0a9e5 100644 --- a/fsm/adc.h +++ b/fsm/adc.h @@ -17,11 +17,11 @@ volatile uint8_t adc_reset = 2; #endif // low-battery threshold in volts * 10 #ifndef VOLTAGE_LOW -#define VOLTAGE_LOW 29 +#define VOLTAGE_LOW (4*29) #endif // battery is low but not critical #ifndef VOLTAGE_RED -#define VOLTAGE_RED 33 +#define VOLTAGE_RED (4*33) #endif // MCU sees voltage 0.X volts lower than actual, add X/2 to readings #ifndef VOLTAGE_FUDGE_FACTOR -- cgit v1.2.3 From 04198bbe232cb8b4a86551da3c738a0fb2bc06f5 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 28 Nov 2023 10:30:48 -0700 Subject: fsm/adc: removed dead code --- fsm/adc.c | 89 +++++++++++++++++++++++---------------------------------------- 1 file changed, 32 insertions(+), 57 deletions(-) (limited to 'fsm') diff --git a/fsm/adc.c b/fsm/adc.c index 97dfc93..93f9a1a 100644 --- a/fsm/adc.c +++ b/fsm/adc.c @@ -218,42 +218,6 @@ static inline void ADC_voltage_handler() { #endif ; - /* - // calculate actual voltage: volts * 10 - // TODO: should be (volts * 40) for extra precision - voltage = (measurement + VOLTAGE_FUDGE_FACTOR - #ifdef USE_VOLTAGE_CORRECTION - + VOLT_CORR - 7 - #endif - ) >> 1; - */ - - #if 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 - // calculate actual voltage: volts * 10 - // ADC = 1.1 * 1024 / volts - // volts = 1.1 * 1024 / ADC - voltage = ((uint16_t)(2*1.1*1024*10)/(measurement>>6) - + VOLTAGE_FUDGE_FACTOR - #ifdef USE_VOLTAGE_CORRECTION - + VOLT_CORR - 7 - #endif - ) >> 1; - #endif - #endif - // if low, callback EV_voltage_low / EV_voltage_critical // (but only if it has been more than N seconds since last call) if (lvp_timer) { @@ -316,10 +280,17 @@ static inline void ADC_temperature_handler() { // 0 .. 65535 = 0 K .. 1024 K uint16_t measurement = temp_raw2cooked(adc_smooth[1]); + // let the UI see the current temperature in C // (Kelvin << 6) to Celsius + // Why 275? Because Atmel's docs use 275 instead of 273. temperature = (measurement>>6) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; - #if 0 + // instead of (K << 6), use (K << 1) now + // TODO: use more precision, if it can be done without overflow in 16 bits + // (and still work on attiny85 without increasing ROM size) + #if 1 + measurement = measurement >> 5; + #else // TODO: is this still needed? // 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, @@ -329,24 +300,7 @@ static inline void ADC_temperature_handler() { //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) - // FIXME: call something in arch/$mcu.h or hwdef.h - // instead of calculating this here - #ifndef USE_EXTERNAL_TEMP_SENSOR - // onboard sensor for attiny25/45/85/1634 - temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; - #else - // external sensor - temperature = EXTERN_TEMP_FORMULA(measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL; #endif - #endif - - // instead of (K << 6), use (K << 1) now - // TODO: use more precision, if it can be done without overflow in 16 bits - // (and still work on attiny85 without increasing ROM size) - measurement = measurement >> 5; // how much has the temperature changed between now and a few seconds ago? int16_t diff; @@ -440,17 +394,38 @@ static inline void ADC_temperature_handler() { #ifdef USE_BATTCHECK #ifdef BATTCHECK_4bars PROGMEM const uint8_t voltage_blinks[] = { - 4*30, 4*35, 4*38, 4*40, 4*42, 255, + 4*30, + 4*35, + 4*38, + 4*40, + 4*42, + 255, }; #endif #ifdef BATTCHECK_6bars PROGMEM const uint8_t voltage_blinks[] = { - 4*30, 4*34, 4*36, 4*38, 4*40, 4*41, 4*43, 255, + 4*30, + 4*34, + 4*36, + 4*38, + 4*40, + 4*41, + 4*43, + 255, }; #endif #ifdef BATTCHECK_8bars PROGMEM const uint8_t voltage_blinks[] = { - 4*30, 4*33, 4*35, 4*37, 4*38, 4*39, 4*40, 4*41, 4*42, 255, + 4*30, + 4*33, + 4*35, + 4*37, + 4*38, + 4*39, + 4*40, + 4*41, + 4*42, + 255, }; #endif void battcheck() { -- cgit v1.2.3 From 56370218c5ca1b542a967e72b134f43a82f69ddc Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 28 Nov 2023 12:36:39 -0700 Subject: fixed incorrect temperature history for a few seconds after waking (it used raw ADC units instead of cooked Kelvin units ... ... which was only noticeable on hardware which has different ADC units) --- fsm/adc.c | 20 +++++++++----------- fsm/adc.h | 4 ++-- 2 files changed, 11 insertions(+), 13 deletions(-) (limited to 'fsm') diff --git a/fsm/adc.c b/fsm/adc.c index 93f9a1a..fbe84a1 100644 --- a/fsm/adc.c +++ b/fsm/adc.c @@ -166,7 +166,7 @@ void adc_deferred() { #ifdef USE_LVP -static inline void ADC_voltage_handler() { +static void ADC_voltage_handler() { // rate-limit low-voltage warnings to a max of 1 per N seconds static uint8_t lvp_timer = 0; #define LVP_TIMER_START (VOLTAGE_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) // N seconds between LVP warnings @@ -240,7 +240,7 @@ static inline void ADC_voltage_handler() { #ifdef USE_THERMAL_REGULATION // generally happens once per second while awake -static inline void ADC_temperature_handler() { +static void ADC_temperature_handler() { // coarse adjustment #ifndef THERM_LOOKAHEAD #define THERM_LOOKAHEAD 4 @@ -265,15 +265,7 @@ static inline void ADC_temperature_handler() { static uint16_t temperature_history[NUM_TEMP_HISTORY_STEPS]; static int8_t warning_threshold = 0; - if (adc_reset) { // wipe out old data - // ignore average, use latest sample - uint16_t foo = adc_raw[1]; - adc_smooth[1] = foo; - - // forget any past measurements - for(uint8_t i=0; i> 5; - } + if (adc_reset) adc_smooth[1] = adc_raw[1]; // latest 16-bit ADC reading // convert raw ADC value to Kelvin << 6 @@ -302,6 +294,12 @@ static inline void ADC_temperature_handler() { //measurement = (measurement + 16) & 0xffe0; // 1111 1111 1110 0000 #endif + if (adc_reset) { // wipe out old data after waking up + // forget any past measurements + for(uint8_t i=0; i