From 4cfd927f3c98eceed4ed2b017daaf44afbffd310 Mon Sep 17 00:00:00 2001 From: Gabrielerusso Date: Mon, 12 Feb 2024 15:26:57 +0100 Subject: [PATCH 1/9] Add battery level with lookup table now uses a lookup table to better calculate battery level of different cells --- src/Power.cpp | 62 +++++++++++++++++++++++++++++++-------------------- src/power.h | 31 +++++++++++++++----------- 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 24f5eee0bb..71c47ef10b 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -127,8 +127,6 @@ class AnalogBatteryLevel : public HasBatteryLevel { /** * Battery state of charge, from 0 to 100 or -1 for unknown - * - * FIXME - use a lipo lookup table, the current % full is super wrong */ virtual int getBatteryPercent() override { @@ -142,8 +140,30 @@ class AnalogBatteryLevel : public HasBatteryLevel if (v > chargingVolt) return 0; // While charging we can't report % full on the battery #endif - - return clamp((int)(100 * (v - emptyVolt) / (fullVolt - emptyVolt)), 0, 100); + /** + * @brief Battery voltage lookup table interpolation to obtain a more + * precise percentage rather than the old proportional one. + * @author Gabriele Russo + * @date 06/02/2024 + */ + float battery_SOC = 0.0; + uint16_t voltage = v/NUM_CELLS; + const uint16_t OCV[NUM_OCV_POINTS] = OCV_ARRAY; + for (int i = 0; i < NUM_OCV_POINTS; i++){ + if (OCV[i] <= voltage){ + if (i == 0) { + battery_SOC = 100.0; // 100% full + } + else { + // interpolate between OCV[i] and OCV[i-1] + battery_SOC = (float) 100.0 / (NUM_OCV_POINTS - 1.0) * + (NUM_OCV_POINTS - 1.0 - i + ((float)voltage - OCV[i]) / + (OCV[i-1] - OCV[i])); + } + break; + } + } + return clamp((int)(battery_SOC),0,100); } /** @@ -272,21 +292,14 @@ class AnalogBatteryLevel : public HasBatteryLevel /// If we see a battery voltage higher than physics allows - assume charger is pumping /// in power -#ifndef BAT_FULLVOLT -#define BAT_FULLVOLT 4200 -#endif -#ifndef BAT_EMPTYVOLT -#define BAT_EMPTYVOLT 3270 -#endif -#ifndef BAT_CHARGINGVOLT -#define BAT_CHARGINGVOLT 4210 -#endif -#ifndef BAT_NOBATVOLT -#define BAT_NOBATVOLT 2230 -#endif + /// For heltecs with no battery connected, the measured voltage is 2204, so + //need to be higher than that, in this case is 2500mV + const uint16_t OCV[NUM_OCV_POINTS] = OCV_ARRAY; + const float fullVolt = OCV[0]*NUM_CELLS; + const float emptyVolt = OCV[NUM_OCV_POINTS-1]*NUM_CELLS; + const float chargingVolt = (OCV[0]+10)*NUM_CELLS; + const float noBatVolt = (OCV[NUM_OCV_POINTS-1]-500)*NUM_CELLS; - /// For heltecs with no battery connected, the measured voltage is 2204, so raising to 2230 from 2100 - const float fullVolt = BAT_FULLVOLT, emptyVolt = BAT_EMPTYVOLT, chargingVolt = BAT_CHARGINGVOLT, noBatVolt = BAT_NOBATVOLT; float last_read_value = 0.0; uint32_t last_read_time_ms = 0; @@ -461,10 +474,10 @@ void Power::readPowerStatus() batteryChargePercent = batteryLevel->getBatteryPercent(); } else { // If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error - // In that case, we compute an estimate of the charge percent based on maximum and minimum voltages defined in - // power.h + // In that case, we compute an estimate of the charge percent based on open circuite voltage table defined + // in power.h batteryChargePercent = - clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)), + clamp((int)(((batteryVoltageMv - (OCV[NUM_OCV_POINTS-1]*NUM_CELLS)) * 1e2) / ((OCV[0]*NUM_CELLS) - (OCV[NUM_OCV_POINTS-1]*NUM_CELLS))), 0, 100); } } @@ -530,10 +543,11 @@ void Power::readPowerStatus() #endif - // If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 10 low readings in - // a row + // If we have a battery at all and it is less than 0%, force deep sleep if we have more than 10 low readings in + // a row. NOTE: min LiIon/LiPo voltage is 2.0 to 2.5V, current OCV min is set to 3100 that is large enough. + // if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) { - if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) { + if (batteryLevel->getBattVoltage() < OCV[NUM_OCV_POINTS-1]) { low_voltage_counter++; LOG_DEBUG("Low voltage counter: %d/10\n", low_voltage_counter); if (low_voltage_counter > 10) { diff --git a/src/power.h b/src/power.h index 54d98e7150..7c1914c34b 100644 --- a/src/power.h +++ b/src/power.h @@ -5,18 +5,22 @@ #include #include #endif -/** - * Per @spattinson - * MIN_BAT_MILLIVOLTS seems high. Typical 18650 are different chemistry to LiPo, even for LiPos that chart seems a bit off, other - * charts put 3690mV at about 30% for a lipo, for 18650 i think 10% remaining iis in the region of 3.2-3.3V. Reference 1st graph - * in [this test report](https://lygte-info.dk/review/batteries2012/Samsung%20INR18650-30Q%203000mAh%20%28Pink%29%20UK.html) - * looking at the red line - discharge at 0.2A - he gets a capacity of 2900mah, 90% of 2900 = 2610, that point in the graph looks - * to be a shade above 3.2V - */ -#define MIN_BAT_MILLIVOLTS 3250 // millivolts. 10% per https://blog.ampow.com/lipo-voltage-chart/ - -#define BAT_MILLIVOLTS_FULL 4100 -#define BAT_MILLIVOLTS_EMPTY 3500 + +#ifndef NUM_OCV_POINTS +#define NUM_OCV_POINTS 11 +#endif + +#ifndef OCV_ARRAY +//{4200,4050,3990,3890,3790,3700,3650,3550,3450,3300,3200} //4.2 to 3.2 +//{4200,4050,3990,3890,3790,3700,3650,3550,3400,3300,3000} //4.2 to 3.0 +//{4150,4050,3990,3890,3790,3690,3620,3520,3420,3300,3100} //4.15 to 3.1 +#define OCV_ARRAY {4150,4050,3990,3890,3790,3690,3620,3520,3420,3300,3100} +#endif + +#ifndef NUM_CELLS +#define NUM_CELLS 1 +#endif + #ifdef BAT_MEASURE_ADC_UNIT extern RTC_NOINIT_ATTR uint64_t RTC_reg_b; #include "soc/sens_reg.h" // needed for adc pin reset @@ -44,7 +48,7 @@ class Power : private concurrency::OSThread virtual bool setup(); virtual int32_t runOnce() override; void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; } - + const uint16_t OCV[11] = OCV_ARRAY; protected: meshtastic::PowerStatus *statusHandler; @@ -54,6 +58,7 @@ class Power : private concurrency::OSThread bool analogInit(); private: + //open circuit voltage lookup table uint8_t low_voltage_counter; #ifdef DEBUG_HEAP uint32_t lastheap; From 6f50d8b3d697d46055fc5346d30ff116725a08a3 Mon Sep 17 00:00:00 2001 From: Gabrielerusso Date: Mon, 12 Feb 2024 15:35:47 +0100 Subject: [PATCH 2/9] LifePo4 and PB battery table - added voltage filter removed delay from adc reading, added a software filter to smooth out voltage readings. In those applications battery would last hours to days, no sudden change should be expected so a less frequent voltage reading or a more aggressive filtering could be done. Note: to speed up convergence i initiliazied the last value to the minimum voltage, there are other and better ways to init the filter. Added LiFePO4 and PB open circuit volta battery tables, --- src/Power.cpp | 61 +++++++++++++++++++++++---------------------------- src/power.h | 22 ++++++++++++++----- 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 71c47ef10b..ec0c66aae4 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -135,7 +135,7 @@ class AnalogBatteryLevel : public HasBatteryLevel if (v < noBatVolt) return -1; // If voltage is super low assume no battery installed -#ifdef ARCH_ESP32 +#ifdef NO_BATTERY_LEVEL_ON_CHARGE // This does not work on a RAK4631 with battery connected if (v > chargingVolt) return 0; // While charging we can't report % full on the battery @@ -147,23 +147,20 @@ class AnalogBatteryLevel : public HasBatteryLevel * @date 06/02/2024 */ float battery_SOC = 0.0; - uint16_t voltage = v/NUM_CELLS; - const uint16_t OCV[NUM_OCV_POINTS] = OCV_ARRAY; - for (int i = 0; i < NUM_OCV_POINTS; i++){ - if (OCV[i] <= voltage){ + uint16_t voltage = v / NUM_CELLS; // single cell voltage (average) + for (int i = 0; i < NUM_OCV_POINTS; i++) { + if (OCV[i] <= voltage) { if (i == 0) { - battery_SOC = 100.0; // 100% full - } - else { + battery_SOC = 100.0; // 100% full + } else { // interpolate between OCV[i] and OCV[i-1] - battery_SOC = (float) 100.0 / (NUM_OCV_POINTS - 1.0) * - (NUM_OCV_POINTS - 1.0 - i + ((float)voltage - OCV[i]) / - (OCV[i-1] - OCV[i])); + battery_SOC = (float)100.0 / (NUM_OCV_POINTS - 1.0) * + (NUM_OCV_POINTS - 1.0 - i + ((float)voltage - OCV[i]) / (OCV[i - 1] - OCV[i])); } break; } } - return clamp((int)(battery_SOC),0,100); + return clamp((int)(battery_SOC), 0, 100); } /** @@ -212,7 +209,7 @@ class AnalogBatteryLevel : public HasBatteryLevel scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw; #endif // LOG_DEBUG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled)); - last_read_value = scaled; + last_read_value += (scaled - last_read_value) * 0.5; // Virtual LPF return scaled; } else { return last_read_value; @@ -232,19 +229,16 @@ class AnalogBatteryLevel : public HasBatteryLevel #ifndef BAT_MEASURE_ADC_UNIT // ADC1 #ifdef ADC_CTRL - if (heltec_version == 5) { - pinMode(ADC_CTRL, OUTPUT); - digitalWrite(ADC_CTRL, HIGH); - delay(10); - } + pinMode(ADC_CTRL, OUTPUT); + digitalWrite(ADC_CTRL, HIGH); + delay(10); #endif for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) { raw += adc1_get_raw(adc_channel); + // delayMicroseconds(100); } #ifdef ADC_CTRL - if (heltec_version == 5) { - digitalWrite(ADC_CTRL, LOW); - } + digitalWrite(ADC_CTRL, LOW); #endif #else // ADC2 int32_t adc_buf = 0; @@ -293,14 +287,13 @@ class AnalogBatteryLevel : public HasBatteryLevel /// in power /// For heltecs with no battery connected, the measured voltage is 2204, so - //need to be higher than that, in this case is 2500mV - const uint16_t OCV[NUM_OCV_POINTS] = OCV_ARRAY; - const float fullVolt = OCV[0]*NUM_CELLS; - const float emptyVolt = OCV[NUM_OCV_POINTS-1]*NUM_CELLS; - const float chargingVolt = (OCV[0]+10)*NUM_CELLS; - const float noBatVolt = (OCV[NUM_OCV_POINTS-1]-500)*NUM_CELLS; - - float last_read_value = 0.0; + // need to be higher than that, in this case is 2500mV (3000-500) + const uint16_t OCV[NUM_OCV_POINTS] = {OCV_ARRAY}; + const float chargingVolt = (OCV[0] + 10) * NUM_CELLS; + const float noBatVolt = (OCV[NUM_OCV_POINTS - 1] - 500) * NUM_CELLS; + // Start value from minimum voltage for the filter to not start from 0 + // that could trigger some events. + float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS); uint32_t last_read_time_ms = 0; #if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) @@ -476,9 +469,9 @@ void Power::readPowerStatus() // If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error // In that case, we compute an estimate of the charge percent based on open circuite voltage table defined // in power.h - batteryChargePercent = - clamp((int)(((batteryVoltageMv - (OCV[NUM_OCV_POINTS-1]*NUM_CELLS)) * 1e2) / ((OCV[0]*NUM_CELLS) - (OCV[NUM_OCV_POINTS-1]*NUM_CELLS))), - 0, 100); + batteryChargePercent = clamp((int)(((batteryVoltageMv - (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS)) * 1e2) / + ((OCV[0] * NUM_CELLS) - (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS))), + 0, 100); } } @@ -545,9 +538,9 @@ void Power::readPowerStatus() // If we have a battery at all and it is less than 0%, force deep sleep if we have more than 10 low readings in // a row. NOTE: min LiIon/LiPo voltage is 2.0 to 2.5V, current OCV min is set to 3100 that is large enough. - // + // if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) { - if (batteryLevel->getBattVoltage() < OCV[NUM_OCV_POINTS-1]) { + if (batteryLevel->getBattVoltage() < OCV[NUM_OCV_POINTS - 1]) { low_voltage_counter++; LOG_DEBUG("Low voltage counter: %d/10\n", low_voltage_counter); if (low_voltage_counter > 10) { diff --git a/src/power.h b/src/power.h index 7c1914c34b..5cb325b574 100644 --- a/src/power.h +++ b/src/power.h @@ -10,13 +10,22 @@ #define NUM_OCV_POINTS 11 #endif +// 3400,3350,3320,3300,3270,3260,3250,3220,3200,3120,3000 //3.4 to 3.0 LiFePO4 +// 2120,2090,2070,2050,2030,2010,1990,1980,1970,1960,1950 //2.12 to 1.95 Lead Acid +// 4200,4050,3990,3890,3790,3700,3650,3550,3450,3300,3200 //4.2 to 3.2 LiIon/LiPo +// 4200,4050,3990,3890,3790,3700,3650,3550,3400,3300,3000 //4.2 to 3.0 LiIon/LiPo +// 4150,4050,3990,3890,3790,3690,3620,3520,3420,3300,3100 //4.15 to 3.1 LiIon/LiPo #ifndef OCV_ARRAY -//{4200,4050,3990,3890,3790,3700,3650,3550,3450,3300,3200} //4.2 to 3.2 -//{4200,4050,3990,3890,3790,3700,3650,3550,3400,3300,3000} //4.2 to 3.0 -//{4150,4050,3990,3890,3790,3690,3620,3520,3420,3300,3100} //4.15 to 3.1 -#define OCV_ARRAY {4150,4050,3990,3890,3790,3690,3620,3520,3420,3300,3100} +#ifdef CELL_TYPE_LIFEPO4 +#define OCV_ARRAY 3400, 3350, 3320, 3300, 3270, 3260, 3250, 3220, 3200, 3120, 3000 +#elif defined(CELL_TYPE_LEADACID) +#define OCV_ARRAY 2120, 2090, 2070, 2050, 2030, 2010, 1990, 1980, 1970, 1960, 1950 +#else // LiIon +#define OCV_ARRAY 4190, 4050, 3990, 3890, 3790, 3690, 3620, 3520, 3420, 3300, 3100 +#endif #endif +/*Note: 12V lead acid is 6 cells, most board accept only 1 cell LiIon/LiPo*/ #ifndef NUM_CELLS #define NUM_CELLS 1 #endif @@ -48,7 +57,8 @@ class Power : private concurrency::OSThread virtual bool setup(); virtual int32_t runOnce() override; void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; } - const uint16_t OCV[11] = OCV_ARRAY; + const uint16_t OCV[11] = {OCV_ARRAY}; + protected: meshtastic::PowerStatus *statusHandler; @@ -58,7 +68,7 @@ class Power : private concurrency::OSThread bool analogInit(); private: - //open circuit voltage lookup table + // open circuit voltage lookup table uint8_t low_voltage_counter; #ifdef DEBUG_HEAP uint32_t lastheap; From b3238e4c29ae8d51b82f1197814ebfb275c6d008 Mon Sep 17 00:00:00 2001 From: Gabrielerusso Date: Sun, 11 Feb 2024 19:13:08 +0100 Subject: [PATCH 3/9] Fixed ADC_CTRL , Checks for valid ADC readings line 230/386 For heltec v3 and heltec tracker a different approach was used with the ADC_CTRL pin, now is more uniform using the same code for the 3 boards. line 236 Check if the raw reading we are getting is Valid or not, count only the valid readings. This could lead to a division by 0 (improbable) so that's why at line 258 there is a check for that. --- src/Power.cpp | 31 +++++++++++----------- variants/heltec_v2.1/variant.h | 3 ++- variants/heltec_v3/variant.h | 2 ++ variants/heltec_wireless_tracker/variant.h | 1 + variants/heltec_wsl_v3/variant.h | 2 ++ 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index ec0c66aae4..059d82e87a 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -182,7 +182,7 @@ class AnalogBatteryLevel : public HasBatteryLevel #ifndef BATTERY_SENSE_SAMPLES #define BATTERY_SENSE_SAMPLES \ - 30 // Set the number of samples, it has an effect of increasing sensitivity in complex electromagnetic environment. + 15 // Set the number of samples, it has an effect of increasing sensitivity in complex electromagnetic environment. #endif #ifdef BATTERY_PIN @@ -208,12 +208,10 @@ class AnalogBatteryLevel : public HasBatteryLevel raw = raw / BATTERY_SENSE_SAMPLES; scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw; #endif - // LOG_DEBUG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled)); last_read_value += (scaled - last_read_value) * 0.5; // Virtual LPF - return scaled; - } else { - return last_read_value; + //LOG_DEBUG("battery gpio %d raw val=%u scaled=%u filtered=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled), (uint32_t) (last_read_value)); } + return last_read_value; #endif // BATTERY_PIN return 0; } @@ -226,19 +224,24 @@ class AnalogBatteryLevel : public HasBatteryLevel { uint32_t raw = 0; + uint8_t raw_c = 0; //raw reading counter #ifndef BAT_MEASURE_ADC_UNIT // ADC1 -#ifdef ADC_CTRL +#ifdef ADC_CTRL //enable adc voltage divider when we need to read pinMode(ADC_CTRL, OUTPUT); - digitalWrite(ADC_CTRL, HIGH); + digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED); delay(10); #endif for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) { - raw += adc1_get_raw(adc_channel); + int val_ = adc1_get_raw(adc_channel); + if(val_ >= 0){ //save only valid readings + raw += val_; + raw_c ++; + } // delayMicroseconds(100); } -#ifdef ADC_CTRL - digitalWrite(ADC_CTRL, LOW); +#ifdef ADC_CTRL //disable adc voltage divider when we need to read + digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED); #endif #else // ADC2 int32_t adc_buf = 0; @@ -249,10 +252,10 @@ class AnalogBatteryLevel : public HasBatteryLevel SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV); adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf); raw += adc_buf; + raw_c ++; } #endif // BAT_MEASURE_ADC_UNIT - raw = raw / BATTERY_SENSE_SAMPLES; - return raw; + return (raw / (raw_c < 1 ? 1 : raw_c)); } #endif @@ -383,10 +386,6 @@ bool Power::analogInit() } else { LOG_INFO("ADCmod: ADC characterization based on default reference voltage\n"); } -#if defined(HELTEC_V3) || defined(HELTEC_WSL_V3) - pinMode(37, OUTPUT); // needed for P channel mosfet to work - digitalWrite(37, LOW); -#endif #endif // ARCH_ESP32 #ifdef ARCH_NRF52 diff --git a/variants/heltec_v2.1/variant.h b/variants/heltec_v2.1/variant.h index ed123efec8..396bd3daa3 100644 --- a/variants/heltec_v2.1/variant.h +++ b/variants/heltec_v2.1/variant.h @@ -29,7 +29,8 @@ #define LORA_DIO1 35 // https://www.thethingsnetwork.org/forum/t/big-esp32-sx127x-topic-part-3/18436 #define LORA_DIO2 34 // Not really used -#define ADC_MULTIPLIER 3.8 +#define ADC_MULTIPLIER 3.2 //220k + 100k (320k/100k=3.2) +//#define ADC_WIDTH ADC_WIDTH_BIT_10 #define BATTERY_PIN 37 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define ADC_CHANNEL ADC1_GPIO37_CHANNEL diff --git a/variants/heltec_v3/variant.h b/variants/heltec_v3/variant.h index 2532ea682a..70b122f584 100644 --- a/variants/heltec_v3/variant.h +++ b/variants/heltec_v3/variant.h @@ -11,6 +11,8 @@ #define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost #define BUTTON_PIN 0 +#define ADC_CTRL 37 +#define ADC_CTRL_ENABLED LOW #define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define ADC_CHANNEL ADC1_GPIO1_CHANNEL #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider diff --git a/variants/heltec_wireless_tracker/variant.h b/variants/heltec_wireless_tracker/variant.h index 88b4804a12..ba2a0676a4 100644 --- a/variants/heltec_wireless_tracker/variant.h +++ b/variants/heltec_wireless_tracker/variant.h @@ -35,6 +35,7 @@ #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider #define ADC_MULTIPLIER 4.9 #define ADC_CTRL 2 // active HIGH, powers the voltage divider. Only on 1.1 +#define ADC_CTRL_ENABLED HIGH #undef GPS_RX_PIN #undef GPS_TX_PIN diff --git a/variants/heltec_wsl_v3/variant.h b/variants/heltec_wsl_v3/variant.h index 0ad1b8487b..d3a009adeb 100644 --- a/variants/heltec_wsl_v3/variant.h +++ b/variants/heltec_wsl_v3/variant.h @@ -8,6 +8,8 @@ #define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost #define BUTTON_PIN 0 +#define ADC_CTRL 37 +#define ADC_CTRL_ENABLED LOW #define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define ADC_CHANNEL ADC1_GPIO1_CHANNEL #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider From 4e0976af8f69fcb8b4b98c529a2fa066a2f91a51 Mon Sep 17 00:00:00 2001 From: Gabrielerusso Date: Mon, 12 Feb 2024 20:58:43 +0100 Subject: [PATCH 4/9] updated OCV values updated value to not OCV but to very low current, almost the same anyway --- src/power.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/power.h b/src/power.h index 5cb325b574..df3e575cab 100644 --- a/src/power.h +++ b/src/power.h @@ -10,18 +10,18 @@ #define NUM_OCV_POINTS 11 #endif -// 3400,3350,3320,3300,3270,3260,3250,3220,3200,3120,3000 //3.4 to 3.0 LiFePO4 +// 3400,3350,3320,3290,3270,3260,3250,3230,3200,3120,3000 //3.4 to 3.0 LiFePO4 // 2120,2090,2070,2050,2030,2010,1990,1980,1970,1960,1950 //2.12 to 1.95 Lead Acid // 4200,4050,3990,3890,3790,3700,3650,3550,3450,3300,3200 //4.2 to 3.2 LiIon/LiPo // 4200,4050,3990,3890,3790,3700,3650,3550,3400,3300,3000 //4.2 to 3.0 LiIon/LiPo // 4150,4050,3990,3890,3790,3690,3620,3520,3420,3300,3100 //4.15 to 3.1 LiIon/LiPo #ifndef OCV_ARRAY #ifdef CELL_TYPE_LIFEPO4 -#define OCV_ARRAY 3400, 3350, 3320, 3300, 3270, 3260, 3250, 3220, 3200, 3120, 3000 +#define OCV_ARRAY 3400, 3350, 3320, 3290, 3270, 3260, 3250, 3230, 3200, 3120, 3000 #elif defined(CELL_TYPE_LEADACID) #define OCV_ARRAY 2120, 2090, 2070, 2050, 2030, 2010, 1990, 1980, 1970, 1960, 1950 #else // LiIon -#define OCV_ARRAY 4190, 4050, 3990, 3890, 3790, 3690, 3620, 3520, 3420, 3300, 3100 +#define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100 #endif #endif From 99ab3860b6dd9c163b7f643d9f38de1d13887f73 Mon Sep 17 00:00:00 2001 From: Gabrielerusso Date: Wed, 14 Feb 2024 13:55:24 +0100 Subject: [PATCH 5/9] Added Alkaline/Nimh voltage curve Added Alkaline/Nimh voltage curve for AA/AAA and similar cells --- src/power.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/power.h b/src/power.h index df3e575cab..05160149c6 100644 --- a/src/power.h +++ b/src/power.h @@ -20,6 +20,10 @@ #define OCV_ARRAY 3400, 3350, 3320, 3290, 3270, 3260, 3250, 3230, 3200, 3120, 3000 #elif defined(CELL_TYPE_LEADACID) #define OCV_ARRAY 2120, 2090, 2070, 2050, 2030, 2010, 1990, 1980, 1970, 1960, 1950 +#elif defined(CELL_TYPE_ALKALINE) +#define OCV_ARRAY 1580, 1400, 1350, 1300, 1280, 1250, 1230, 1190, 1150, 1100, 1000 +#elif defined(CELL_TYPE_NIMH) +#define OCV_ARRAY 1400, 1300, 1280, 1270, 1260, 1250, 1240, 1230, 1210, 1150, 1000 #else // LiIon #define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100 #endif From 5ef07095c33d2181ecf3c69dc407b4d3aadcab9f Mon Sep 17 00:00:00 2001 From: Gabrielerusso Date: Wed, 14 Feb 2024 13:57:19 +0100 Subject: [PATCH 6/9] updates variants for new capacity measurement --- variants/chatter2/variant.h | 6 +++--- variants/station-g1/variant.h | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/variants/chatter2/variant.h b/variants/chatter2/variant.h index b7ffcf7329..1a07f11828 100644 --- a/variants/chatter2/variant.h +++ b/variants/chatter2/variant.h @@ -77,9 +77,9 @@ // lower dB for lower voltage rnage #define ADC_MULTIPLIER \ 5.0 // VBATT---10k--pin34---2.5K---GND - // Chatter2 uses 3 AAA cells -#define BAT_FULLVOLT 4800 // with the 5.0 divider, input to BATTERY_PIN is 900mv -#define BAT_EMPTYVOLT 3300 +// Chatter2 uses 3 AAA cells +#define CELL_TYPE_ALKALINE +#define NUM_CELLS 3 #undef EXT_PWR_DETECT // GPS diff --git a/variants/station-g1/variant.h b/variants/station-g1/variant.h index e58853fb7d..d26ecffcf0 100644 --- a/variants/station-g1/variant.h +++ b/variants/station-g1/variant.h @@ -37,10 +37,8 @@ #define ADC_CHANNEL ADC1_GPIO35_CHANNEL #define BATTERY_SENSE_SAMPLES 30 // Set the number of samples, It has an effect of increasing sensitivity. #define ADC_MULTIPLIER 6.45 -#define BAT_FULLVOLT 12600 -#define BAT_EMPTYVOLT 8200 -#define BAT_CHARGINGVOLT 12600 -#define BAT_NOBATVOLT 6690 +#define CELL_TYPE_LION //same curve for liion/lipo +#define NUM_CELLS 3 // different screen #define USE_SH1106 From 7d72ede0849954895c6d49802f4a7581b3d774a6 Mon Sep 17 00:00:00 2001 From: Gabrielerusso Date: Wed, 14 Feb 2024 14:03:44 +0100 Subject: [PATCH 7/9] trunk reformatting --- src/Power.cpp | 15 ++++++++------- variants/chatter2/variant.h | 9 ++++----- variants/heltec_v2.1/variant.h | 4 ++-- variants/station-g1/variant.h | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 059d82e87a..fea5f6e08b 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -209,7 +209,8 @@ class AnalogBatteryLevel : public HasBatteryLevel scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw; #endif last_read_value += (scaled - last_read_value) * 0.5; // Virtual LPF - //LOG_DEBUG("battery gpio %d raw val=%u scaled=%u filtered=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled), (uint32_t) (last_read_value)); + // LOG_DEBUG("battery gpio %d raw val=%u scaled=%u filtered=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled), (uint32_t) + // (last_read_value)); } return last_read_value; #endif // BATTERY_PIN @@ -224,23 +225,23 @@ class AnalogBatteryLevel : public HasBatteryLevel { uint32_t raw = 0; - uint8_t raw_c = 0; //raw reading counter + uint8_t raw_c = 0; // raw reading counter #ifndef BAT_MEASURE_ADC_UNIT // ADC1 -#ifdef ADC_CTRL //enable adc voltage divider when we need to read +#ifdef ADC_CTRL // enable adc voltage divider when we need to read pinMode(ADC_CTRL, OUTPUT); digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED); delay(10); #endif for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) { int val_ = adc1_get_raw(adc_channel); - if(val_ >= 0){ //save only valid readings + if (val_ >= 0) { // save only valid readings raw += val_; - raw_c ++; + raw_c++; } // delayMicroseconds(100); } -#ifdef ADC_CTRL //disable adc voltage divider when we need to read +#ifdef ADC_CTRL // disable adc voltage divider when we need to read digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED); #endif #else // ADC2 @@ -252,7 +253,7 @@ class AnalogBatteryLevel : public HasBatteryLevel SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV); adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf); raw += adc_buf; - raw_c ++; + raw_c++; } #endif // BAT_MEASURE_ADC_UNIT return (raw / (raw_c < 1 ? 1 : raw_c)); diff --git a/variants/chatter2/variant.h b/variants/chatter2/variant.h index 1a07f11828..90faa1d7ba 100644 --- a/variants/chatter2/variant.h +++ b/variants/chatter2/variant.h @@ -72,11 +72,10 @@ #define BATTERY_PIN 34 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define ADC_CHANNEL ADC1_GPIO34_CHANNEL #define ADC_ATTENUATION \ - ADC_ATTEN_DB_2_5 // 2_5-> 100mv-1250mv, 11-> 150mv-3100mv for ESP32 - // ESP32-S2/C3/S3 are different - // lower dB for lower voltage rnage -#define ADC_MULTIPLIER \ - 5.0 // VBATT---10k--pin34---2.5K---GND + ADC_ATTEN_DB_2_5 // 2_5-> 100mv-1250mv, 11-> 150mv-3100mv for ESP32 + // ESP32-S2/C3/S3 are different + // lower dB for lower voltage rnage +#define ADC_MULTIPLIER 5.0 // VBATT---10k--pin34---2.5K---GND // Chatter2 uses 3 AAA cells #define CELL_TYPE_ALKALINE #define NUM_CELLS 3 diff --git a/variants/heltec_v2.1/variant.h b/variants/heltec_v2.1/variant.h index 396bd3daa3..8ebccc54fb 100644 --- a/variants/heltec_v2.1/variant.h +++ b/variants/heltec_v2.1/variant.h @@ -29,8 +29,8 @@ #define LORA_DIO1 35 // https://www.thethingsnetwork.org/forum/t/big-esp32-sx127x-topic-part-3/18436 #define LORA_DIO2 34 // Not really used -#define ADC_MULTIPLIER 3.2 //220k + 100k (320k/100k=3.2) -//#define ADC_WIDTH ADC_WIDTH_BIT_10 +#define ADC_MULTIPLIER 3.2 // 220k + 100k (320k/100k=3.2) +// #define ADC_WIDTH ADC_WIDTH_BIT_10 #define BATTERY_PIN 37 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define ADC_CHANNEL ADC1_GPIO37_CHANNEL diff --git a/variants/station-g1/variant.h b/variants/station-g1/variant.h index d26ecffcf0..9a3c37b735 100644 --- a/variants/station-g1/variant.h +++ b/variants/station-g1/variant.h @@ -37,7 +37,7 @@ #define ADC_CHANNEL ADC1_GPIO35_CHANNEL #define BATTERY_SENSE_SAMPLES 30 // Set the number of samples, It has an effect of increasing sensitivity. #define ADC_MULTIPLIER 6.45 -#define CELL_TYPE_LION //same curve for liion/lipo +#define CELL_TYPE_LION // same curve for liion/lipo #define NUM_CELLS 3 // different screen From 95ff73dcd8c2b66d2f62edc5ce74df06c353cd98 Mon Sep 17 00:00:00 2001 From: code8buster <20384924+code8buster@users.noreply.github.com> Date: Fri, 16 Feb 2024 00:35:35 -0500 Subject: [PATCH 8/9] trunk fmt --- src/Power.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Power.cpp b/src/Power.cpp index 9da552cdf2..8e44ddb983 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -274,7 +274,7 @@ class AnalogBatteryLevel : public HasBatteryLevel } } -#else // Other ESP32 +#else // Other ESP32 int32_t adc_buf = 0; for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) { // ADC2 wifi bug workaround, see From f4d6388411d4bae15932caf81ca607905dede81f Mon Sep 17 00:00:00 2001 From: code8buster <20384924+code8buster@users.noreply.github.com> Date: Fri, 16 Feb 2024 01:55:06 -0500 Subject: [PATCH 9/9] Add LTO chemistry --- src/power.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/power.h b/src/power.h index 05160149c6..4dd35e7103 100644 --- a/src/power.h +++ b/src/power.h @@ -15,6 +15,8 @@ // 4200,4050,3990,3890,3790,3700,3650,3550,3450,3300,3200 //4.2 to 3.2 LiIon/LiPo // 4200,4050,3990,3890,3790,3700,3650,3550,3400,3300,3000 //4.2 to 3.0 LiIon/LiPo // 4150,4050,3990,3890,3790,3690,3620,3520,3420,3300,3100 //4.15 to 3.1 LiIon/LiPo +// 2770,2650,2540,2420,2300,2180,2060,1940,1800,1680,1550 //2.8 to 1.5 Lithium Titanate + #ifndef OCV_ARRAY #ifdef CELL_TYPE_LIFEPO4 #define OCV_ARRAY 3400, 3350, 3320, 3290, 3270, 3260, 3250, 3230, 3200, 3120, 3000 @@ -24,6 +26,8 @@ #define OCV_ARRAY 1580, 1400, 1350, 1300, 1280, 1250, 1230, 1190, 1150, 1100, 1000 #elif defined(CELL_TYPE_NIMH) #define OCV_ARRAY 1400, 1300, 1280, 1270, 1260, 1250, 1240, 1230, 1210, 1150, 1000 +#elif defined(CELL_TYPE_LTO) +#define OCV_ARRAY 2770, 2650, 2540, 2420, 2300, 2180, 2060, 1940, 1800, 1680, 1550 #else // LiIon #define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100 #endif