diff --git a/src/Power.cpp b/src/Power.cpp index a9ed6360e..14797dfa5 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -214,13 +214,29 @@ static void adcDisable() #endif } -#endif +#endif //BATTERY_PIN /** * A simple battery level sensor that assumes the battery voltage is attached via a voltage-divider to an analog input */ class AnalogBatteryLevel : public HasBatteryLevel { + private: + /// If we see a battery voltage higher than physics allows - assume charger is pumping + /// 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 (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. + // This value is over-written by the first ADC reading, it the voltage seems reasonable. + bool initial_read_done = false; + float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS); + uint32_t last_read_time_ms = 0; + public: /** * Battery state of charge, from 0 to 100 or -1 for unknown @@ -475,22 +491,6 @@ class AnalogBatteryLevel : public HasBatteryLevel return isVbusIn(); } - private: - /// If we see a battery voltage higher than physics allows - assume charger is pumping - /// 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 (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. - // This value is over-written by the first ADC reading, it the voltage seems reasonable. - bool initial_read_done = false; - float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS); - uint32_t last_read_time_ms = 0; - #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(HAS_RAKPROT) uint16_t getRAKVoltage() { return rak9154Sensor.getBusVoltageMv(); } @@ -502,7 +502,6 @@ class AnalogBatteryLevel : public HasBatteryLevel return rak9154Sensor.isRunning(); } #endif - #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_STM32WL) uint16_t getINAVoltage() { @@ -654,6 +653,23 @@ bool Power::analogInit() #endif } +/** + * Initializes the INA sensor for power monitoring. + * + * @return true if the INA sensor is ready, false otherwise. + */ +bool Power::inaInit() +{ + #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_STM32WL) + bool result = analogLevel.hasINA(); + batteryLevel = &analogLevel; + + LOG_DEBUG("Power::inaInit INA sensor is %s", result ? "ready" : "not ready yet"); + return result; + #endif + return false; +} + /** * Initializes the Power class. * @@ -667,6 +683,8 @@ bool Power::setup() found = lipoInit(); if (!found) found = analogInit(); + if (!found) + found = inaInit(); #ifdef NRF_APM found = true; diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index dbe4796cf..ead24e74c 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -34,7 +34,7 @@ void PowerFSM_setup(){}; static bool isPowered() { // Circumvent the battery sensing logic and assumes constant power if no battery pin or power mgmt IC -#if !defined(BATTERY_PIN) && !defined(HAS_AXP192) && !defined(HAS_AXP2101) && !defined(NRF_APM) +#if !defined(HAS_BATTERY) && !defined(BATTERY_PIN) && !defined(HAS_AXP192) && !defined(HAS_AXP2101) && !defined(NRF_APM) return true; #endif diff --git a/src/PowerStatus.h b/src/PowerStatus.h index fe4543e08..010488dde 100644 --- a/src/PowerStatus.h +++ b/src/PowerStatus.h @@ -61,14 +61,14 @@ class PowerStatus : public Status /** * Note: for boards with battery pin or PMU, 0% battery means 'unknown/this board doesn't have a battery installed' */ -#if defined(HAS_PMU) || defined(BATTERY_PIN) +#if defined(HAS_PMU) || defined(BATTERY_PIN) || defined(HAS_BATTERY) uint8_t getBatteryChargePercent() const { return getHasBattery() ? batteryChargePercent : 0; } #endif /** * Note: for boards without battery pin and PMU, 101% battery means 'the board is using external power' */ -#if !defined(HAS_PMU) && !defined(BATTERY_PIN) +#if !defined(HAS_PMU) && !defined(BATTERY_PIN) && !defined(HAS_BATTERY) uint8_t getBatteryChargePercent() const { return getHasBattery() ? batteryChargePercent : 101; } #endif diff --git a/src/configuration.h b/src/configuration.h index 32d99295e..e6808110f 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -297,6 +297,9 @@ along with this program. If not, see . #ifndef HAS_BLUETOOTH #define HAS_BLUETOOTH 0 #endif +#ifndef HAS_BATTERY +#define HAS_BATTERY 0 +#endif #ifndef HW_VENDOR #error HW_VENDOR must be defined diff --git a/src/main.cpp b/src/main.cpp index c12707cdb..4c7929955 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -530,12 +530,14 @@ void setup() tftSetup(); #endif +#if defined(HAS_PMU) // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning power = new Power(); power->setStatusHandler(powerStatus); powerStatus->observe(&power->newStatus); power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration +#endif #if !MESHTASTIC_EXCLUDE_I2C // We need to scan here to decide if we have a screen for nodeDB.init() and because power has been applied to @@ -1276,6 +1278,15 @@ void setup() 1000); } +#if !defined(HAS_PMU) + // Currently only the tbeam has a PMU + // PMU initialization needs to be placed before i2c scanning + power = new Power(); + power->setStatusHandler(powerStatus); + powerStatus->observe(&power->newStatus); + power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration +#endif + // This must be _after_ service.init because we need our preferences loaded from flash to have proper timeout values PowerFSM_setup(); // we will transition to ON in a couple of seconds, FIXME, only do this for cold boots, not waking from SDS powerFSMthread = new PowerFSMThread(); diff --git a/src/power.h b/src/power.h index d7fa7f8a9..7e60adeb6 100644 --- a/src/power.h +++ b/src/power.h @@ -122,7 +122,8 @@ class Power : private concurrency::OSThread bool analogInit(); /// Setup a Lipo battery level sensor bool lipoInit(); - + /// Setup INA battery level sensor + bool inaInit(); private: // open circuit voltage lookup table uint8_t low_voltage_counter; diff --git a/variants/rp2040-lora/variant.h b/variants/rp2040-lora/variant.h index 92b067457..069b32543 100644 --- a/variants/rp2040-lora/variant.h +++ b/variants/rp2040-lora/variant.h @@ -23,6 +23,14 @@ // ratio of voltage divider = 3.0 (R17=200k, R18=100k) // #define ADC_MULTIPLIER 3.1 // 3.0 + a bit for being optimistic +// Enables battery-related code and requires BATTERY_IMMUTABLE to be defined. +// Ensure a valid address is configured for the INA sensor from which voltage readings are to be obtained. +#define HAS_BATTERY +#define BATTERY_IMMUTABLE +// Disable ina charging detection to prevent charge percentage readings going to 100% while battery is charging. +#define DISABLE_INA_CHARGING_DETECTION + + #define HAS_CPU_SHUTDOWN 1 #define USE_SX1262