From fbcac59563c32f14de4861449c1b267c247b5b78 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 16 Apr 2023 18:21:29 -0600 Subject: reduced ROM by ~600 bytes by moving all eeprom config values to a "cfg" struct (this also made some parts of the code cleaner) --- spaghetti-monster/fsm-adc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'spaghetti-monster/fsm-adc.c') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 60eb843..9dc8866 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -149,7 +149,7 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { uint8_t result = ((value / adc_per_volt) + VOLTAGE_FUDGE_FACTOR #ifdef USE_VOLTAGE_CORRECTION - + voltage_correction - 7 + + VOLT_CORR - 7 #endif ) >> 1; return result; @@ -349,7 +349,7 @@ static inline void ADC_voltage_handler() { voltage = ((uint16_t)(2*1.1*1024*10)/(measurement>>6) + VOLTAGE_FUDGE_FACTOR #ifdef USE_VOLTAGE_CORRECTION - + voltage_correction - 7 + + VOLT_CORR - 7 #endif ) >> 1; #endif @@ -428,10 +428,10 @@ static inline void ADC_temperature_handler() { // Convert ADC units to Celsius (ish) #ifndef USE_EXTERNAL_TEMP_SENSOR // onboard sensor for attiny25/45/85/1634 - temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)therm_cal_offset - 275; + 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)therm_cal_offset; + temperature = EXTERN_TEMP_FORMULA(measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL; #endif // how much has the temperature changed between now and a few seconds ago? @@ -447,10 +447,10 @@ static inline void ADC_temperature_handler() { pt = measurement + (diff * THERM_LOOKAHEAD); // convert temperature limit from C to raw 16-bit ADC units - // C = (ADC>>6) - 275 + THERM_CAL_OFFSET + therm_cal_offset; + // C = (ADC>>6) - 275 + THERM_CAL_OFFSET + TH_CAL; // ... so ... - // (C + 275 - THERM_CAL_OFFSET - therm_cal_offset) << 6 = ADC; - uint16_t ceil = (therm_ceil + 275 - therm_cal_offset - THERM_CAL_OFFSET) << 1; + // (C + 275 - THERM_CAL_OFFSET - TH_CAL) << 6 = ADC; + uint16_t ceil = (TH_CEIL + 275 - TH_CAL - THERM_CAL_OFFSET) << 1; int16_t offset = pt - ceil; // bias small errors toward zero, while leaving large errors mostly unaffected -- cgit v1.2.3 From 583854e37efde7f461e073e735a1736b02d28c70 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 17 Apr 2023 00:08:32 -0600 Subject: switched the rest of FSM + Anduril to use SPDX license headers instead of full GPL headers (or all too often, nothing at all) There are a few "FIXME" entries where I'm not sure about the correct copyright. --- spaghetti-monster/fsm-adc.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) (limited to 'spaghetti-monster/fsm-adc.c') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 9dc8866..5b238aa 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -1,24 +1,8 @@ -/* - * fsm-adc.c: ADC (voltage, temperature) functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef FSM_ADC_C -#define FSM_ADC_C +// fsm-adc.c: ADC (voltage, temperature) functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once // override onboard temperature sensor definition, if relevant #ifdef USE_EXTERNAL_TEMP_SENSOR @@ -557,4 +541,3 @@ void battcheck() { } #endif -#endif -- cgit v1.2.3 From 847485ca96a6ef99abd19984ec025cf1d6841d3d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 25 Apr 2023 23:28:30 -0600 Subject: fixed bug behind K93_LOCKOUT_KLUDGE which could exit lockout in solid aux mode (also reduced avg standby power by about 15 uA) (also fixed oscillating voltage mode colors, I think) The bug happened because sometimes sleep LVP would get triggered, because the ADC would read zero under some conditions. This in turn happened because the ADC needs the MCU to be at least partially awake in order to finish a measurement. So in standby mode, with the MCU only waking up very briefly to send a sleep tick and go back to sleep, the ADC required several cycles (like 375ms to 625ms) to finish a single measurement. This varied depending on how many instructions the MCU executed while it was awake. In the single-color mode, so few instructions were being executed that the ADC seemed to time out and abort its measurement, returning a zero. Then a low voltage warning was sent, which knocked the light back into "Off" mode. Adding no-op instructions inside the single-color clause was sufficient to prevent the ADC from timing out, because it kept the MCU awake just barely long enough. But it was a kludge, and it still took like half a second to finish a measurement, and the measurements were noisy. It also used more power, because it required keeping the ADC powered on far too long. This fix puts the MCU into "ADC Noise Reduction" mode instead, when a voltage measurement is needed during sleep. It reduces noise to make measurements more stable... but more importantly, it lets the measurement finish in like 0.5ms instead of 500ms. So it uses less power and isn't dependent on the number of calculations the MCU does during each "sleep tick". As a bonus, this can also measure voltage much more often, while still using less total energy than before. It was once every 8 seconds, and now it's once per second. Avg power use in aux low mode, on a D4Sv2: (avg of 30k samples each) - before: 101 uA - after: 86 uA --- spaghetti-monster/fsm-adc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'spaghetti-monster/fsm-adc.c') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 5b238aa..0b79767 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -244,6 +244,8 @@ void adc_deferred() { // (and the usual standby level is only ~20 uA) if (go_to_standby) { ADC_off(); + // if any measurements were in progress, they're done now + adc_active_now = 0; // also, only check the battery while asleep, not the temperature adc_channel = 0; } -- cgit v1.2.3 From aa4c627377b07cc07cd1e904f9f7d2f24c1155a4 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 26 Apr 2023 01:34:53 -0600 Subject: made sleep voltage work on attiny1616 again (oops, it has no "ADC Noise Reduction" mode... needs different setup code) --- spaghetti-monster/fsm-adc.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'spaghetti-monster/fsm-adc.c') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 0b79767..a196b7b 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -12,6 +12,8 @@ #define ADMUX_THERM ADMUX_THERM_EXTERNAL_SENSOR #endif +#include + static inline void set_admux_therm() { #if (ATTINY == 1634) @@ -70,6 +72,29 @@ inline void set_admux_voltage() { ADC_start_measurement(); } + +#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 the RUNSTDBY bit so ADC will run in standby mode + ADC0.CTRLA |= 1; + // set a INITDLY value because the AVR manual says so + // (section 30.3.5) + ADC0.CTRLD |= (1 << 5); + set_sleep_mode(SLEEP_MODE_STANDBY); + #else + #error No ADC sleep mode defined for this hardware. + #endif +} +#endif + inline void ADC_start_measurement() { #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 841) || (ATTINY == 1634) ADCSRA |= (1 << ADSC) | (1 << ADIE); -- cgit v1.2.3 From 7400cbf6a1370035400607c22d57366c54304fb9 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 8 Jul 2023 03:55:02 -0600 Subject: Fixed spurious voltage warnings in attiny1616 sleep mode. Fixed by SammysHP. https://budgetlightforum.com/t/anduril-2-feature-change-suggestions/218045/467 I was never able to reproduce the issue here, but the fix seems good and others tested it successfully. --- spaghetti-monster/fsm-adc.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'spaghetti-monster/fsm-adc.c') diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index a196b7b..d11cca8 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -83,11 +83,6 @@ inline void adc_sleep_mode() { // attiny1634 set_sleep_mode(SLEEP_MODE_ADC); #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - // set the RUNSTDBY bit so ADC will run in standby mode - ADC0.CTRLA |= 1; - // set a INITDLY value because the AVR manual says so - // (section 30.3.5) - ADC0.CTRLD |= (1 << 5); set_sleep_mode(SLEEP_MODE_STANDBY); #else #error No ADC sleep mode defined for this hardware. @@ -133,10 +128,13 @@ inline void ADC_on() ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL; //ADCSRA |= (1 << ADSC); // start measuring #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - set_admux_voltage(); VREF.CTRLA |= VREF_ADC0REFSEL_1V1_gc; // Set Vbg ref to 1.1V - ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm; // Enabled, free-running (aka, auto-retrigger) - ADC0.COMMAND |= ADC_STCONV_bm; // Start the ADC conversions + // 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 @@ -144,7 +142,7 @@ inline void ADC_on() inline void ADC_off() { #ifdef AVRXMEGA3 // ATTINY816, 817, etc - ADC0.CTRLA &= ~(ADC_ENABLE_bm); // disable the ADC + ADC0.CTRLA &= ~(ADC_ENABLE_bm); // disable the ADC #else ADCSRA &= ~(1< v) { v += 64; } + // fixed-rate lowpass, stable but very slow + // (move by only 0.5 ADC units per measurement, 1 ADC unit = 64) + if (r < s) { s -= 32; } + if (r > s) { s += 32; } + #elif 1 + // 1/8th proportional lowpass, faster but less stable + int16_t diff = (r/8) - (s/8); + s += diff; #else - // weighted lowpass, faster but less stable - v = (m>>1) + (v>>1); + // 50% proportional lowpass, fastest but least stable + s = (r>>1) + (s>>1); #endif - adc_smooth[0] = v; - measurement = v; + adc_smooth[0] = s; + measurement = s; } #endif else measurement = adc_smooth[0]; -- cgit v1.2.3