Use INA for device battery level (#2536)

* WIP

* Continued wip

* We got em

* Voltage sensor base class

* INA voltage

* Log it

* Stacie's mom has got it going on

* Move declaration up

* Last one

* Sneaky little bugger

* Macro guard to avoid calling methods
This commit is contained in:
Ben Meadors 2023-06-02 06:32:34 -05:00 committed by GitHub
parent 344baf7ffc
commit cd787232ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 92 additions and 22 deletions

View File

@ -37,12 +37,18 @@ static const adc_atten_t atten = ADC_ATTENUATION;
#endif #endif
#endif // BATTERY_PIN && ARCH_ESP32 #endif // BATTERY_PIN && ARCH_ESP32
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
INA260Sensor ina260Sensor;
INA219Sensor ina219Sensor;
#endif
#ifdef HAS_PMU #ifdef HAS_PMU
#include "XPowersAXP192.tpp" #include "XPowersAXP192.tpp"
#include "XPowersAXP2101.tpp" #include "XPowersAXP2101.tpp"
#include "XPowersLibInterface.hpp" #include "XPowersLibInterface.hpp"
XPowersLibInterface *PMU = NULL; XPowersLibInterface *PMU = NULL;
#else #else
// Copy of the base class defined in axp20x.h. // Copy of the base class defined in axp20x.h.
// I'd rather not inlude axp20x.h as it brings Wire dependency. // I'd rather not inlude axp20x.h as it brings Wire dependency.
class HasBatteryLevel class HasBatteryLevel
@ -128,6 +134,13 @@ class AnalogBatteryLevel : public HasBatteryLevel
virtual uint16_t getBattVoltage() override virtual uint16_t getBattVoltage() override
{ {
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU)
if (hasINA()) {
LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address);
return getINAVoltage();
}
#endif
#ifndef ADC_MULTIPLIER #ifndef ADC_MULTIPLIER
#define ADC_MULTIPLIER 2.0 #define ADC_MULTIPLIER 2.0
#endif #endif
@ -246,6 +259,35 @@ class AnalogBatteryLevel : public HasBatteryLevel
const float fullVolt = BAT_FULLVOLT, emptyVolt = BAT_EMPTYVOLT, chargingVolt = BAT_CHARGINGVOLT, noBatVolt = BAT_NOBATVOLT; const float fullVolt = BAT_FULLVOLT, emptyVolt = BAT_EMPTYVOLT, chargingVolt = BAT_CHARGINGVOLT, noBatVolt = BAT_NOBATVOLT;
float last_read_value = 0.0; float last_read_value = 0.0;
uint32_t last_read_time_ms = 0; uint32_t last_read_time_ms = 0;
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO)
uint16_t getINAVoltage()
{
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) {
return ina219Sensor.getBusVoltageMv();
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) {
return ina260Sensor.getBusVoltageMv();
}
return 0;
}
bool hasINA()
{
if (!config.power.device_battery_ina_address) {
return false;
}
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) {
if (!ina219Sensor.isInitialized())
return ina219Sensor.runOnce() > 0;
return ina219Sensor.isRunning();
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) {
if (!ina260Sensor.isInitialized())
return ina260Sensor.runOnce() > 0;
return ina260Sensor.isRunning();
}
return false;
}
#endif
}; };
AnalogBatteryLevel analogLevel; AnalogBatteryLevel analogLevel;
@ -639,7 +681,6 @@ bool Power::axpChipInit()
// GNSS VDD 3300mV // GNSS VDD 3300mV
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300); PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO3); PMU->enablePowerOutput(XPOWERS_ALDO3);
} else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) { } else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) {
// t-beam s3 core // t-beam s3 core
/** /**

View File

@ -38,8 +38,6 @@ extern bool isUSBPowered;
extern ATECCX08A atecc; extern ATECCX08A atecc;
#endif #endif
extern uint8_t nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1];
extern int TCPPort; // set by Portduino extern int TCPPort; // set by Portduino
// Global Screen singleton. // Global Screen singleton.

View File

@ -7,6 +7,7 @@
#include "Router.h" #include "Router.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include "power.h"
#include <OLEDDisplay.h> #include <OLEDDisplay.h>
#include <OLEDDisplayUi.h> #include <OLEDDisplayUi.h>
@ -14,8 +15,6 @@
#include "Sensor/BME280Sensor.h" #include "Sensor/BME280Sensor.h"
#include "Sensor/BME680Sensor.h" #include "Sensor/BME680Sensor.h"
#include "Sensor/BMP280Sensor.h" #include "Sensor/BMP280Sensor.h"
#include "Sensor/INA219Sensor.h"
#include "Sensor/INA260Sensor.h"
#include "Sensor/LPS22HBSensor.h" #include "Sensor/LPS22HBSensor.h"
#include "Sensor/MCP9808Sensor.h" #include "Sensor/MCP9808Sensor.h"
#include "Sensor/SHT31Sensor.h" #include "Sensor/SHT31Sensor.h"
@ -25,8 +24,6 @@ BMP280Sensor bmp280Sensor;
BME280Sensor bme280Sensor; BME280Sensor bme280Sensor;
BME680Sensor bme680Sensor; BME680Sensor bme680Sensor;
MCP9808Sensor mcp9808Sensor; MCP9808Sensor mcp9808Sensor;
INA260Sensor ina260Sensor;
INA219Sensor ina219Sensor;
SHTC3Sensor shtc3Sensor; SHTC3Sensor shtc3Sensor;
LPS22HBSensor lps22hbSensor; LPS22HBSensor lps22hbSensor;
SHT31Sensor sht31Sensor; SHT31Sensor sht31Sensor;
@ -83,15 +80,10 @@ int32_t EnvironmentTelemetryModule::runOnce()
result = bme680Sensor.runOnce(); result = bme680Sensor.runOnce();
if (mcp9808Sensor.hasSensor()) if (mcp9808Sensor.hasSensor())
result = mcp9808Sensor.runOnce(); result = mcp9808Sensor.runOnce();
if (ina260Sensor.hasSensor())
result = ina260Sensor.runOnce();
if (ina219Sensor.hasSensor())
result = ina219Sensor.runOnce();
if (shtc3Sensor.hasSensor()) if (shtc3Sensor.hasSensor())
result = shtc3Sensor.runOnce(); result = shtc3Sensor.runOnce();
if (lps22hbSensor.hasSensor()) { if (lps22hbSensor.hasSensor())
result = lps22hbSensor.runOnce(); result = lps22hbSensor.runOnce();
}
if (sht31Sensor.hasSensor()) if (sht31Sensor.hasSensor())
result = sht31Sensor.runOnce(); result = sht31Sensor.runOnce();
} }

View File

@ -12,8 +12,12 @@ int32_t INA219Sensor::runOnce()
if (!hasSensor()) { if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
} }
ina219 = Adafruit_INA219(nodeTelemetrySensorsMap[sensorType]); if (!ina219.success()) {
status = ina219.begin(); ina219 = Adafruit_INA219(nodeTelemetrySensorsMap[sensorType]);
status = ina219.begin();
} else {
status = ina219.success();
}
return initI2CSensor(); return initI2CSensor();
} }
@ -25,3 +29,8 @@ bool INA219Sensor::getMetrics(meshtastic_Telemetry *measurement)
measurement->variant.environment_metrics.current = ina219.getCurrent_mA(); measurement->variant.environment_metrics.current = ina219.getCurrent_mA();
return true; return true;
} }
uint16_t INA219Sensor::getBusVoltageMv()
{
return lround(ina219.getBusVoltage_V() * 1000);
}

View File

@ -1,8 +1,9 @@
#include "../mesh/generated/meshtastic/telemetry.pb.h" #include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h" #include "TelemetrySensor.h"
#include "VoltageSensor.h"
#include <Adafruit_INA219.h> #include <Adafruit_INA219.h>
class INA219Sensor : virtual public TelemetrySensor class INA219Sensor : virtual public TelemetrySensor, VoltageSensor
{ {
private: private:
Adafruit_INA219 ina219; Adafruit_INA219 ina219;
@ -14,4 +15,5 @@ class INA219Sensor : virtual public TelemetrySensor
INA219Sensor(); INA219Sensor();
virtual int32_t runOnce() override; virtual int32_t runOnce() override;
virtual bool getMetrics(meshtastic_Telemetry *measurement) override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
virtual uint16_t getBusVoltageMv() override;
}; };

View File

@ -12,7 +12,10 @@ int32_t INA260Sensor::runOnce()
if (!hasSensor()) { if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
} }
status = ina260.begin(nodeTelemetrySensorsMap[sensorType]);
if (!status) {
status = ina260.begin(nodeTelemetrySensorsMap[sensorType]);
}
return initI2CSensor(); return initI2CSensor();
} }
@ -25,3 +28,8 @@ bool INA260Sensor::getMetrics(meshtastic_Telemetry *measurement)
measurement->variant.environment_metrics.current = ina260.readCurrent(); measurement->variant.environment_metrics.current = ina260.readCurrent();
return true; return true;
} }
uint16_t INA260Sensor::getBusVoltageMv()
{
return lround(ina260.readBusVoltage());
}

View File

@ -1,8 +1,9 @@
#include "../mesh/generated/meshtastic/telemetry.pb.h" #include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h" #include "TelemetrySensor.h"
#include "VoltageSensor.h"
#include <Adafruit_INA260.h> #include <Adafruit_INA260.h>
class INA260Sensor : virtual public TelemetrySensor class INA260Sensor : virtual public TelemetrySensor, VoltageSensor
{ {
private: private:
Adafruit_INA260 ina260 = Adafruit_INA260(); Adafruit_INA260 ina260 = Adafruit_INA260();
@ -14,4 +15,5 @@ class INA260Sensor : virtual public TelemetrySensor
INA260Sensor(); INA260Sensor();
virtual int32_t runOnce() override; virtual int32_t runOnce() override;
virtual bool getMetrics(meshtastic_Telemetry *measurement) override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
virtual uint16_t getBusVoltageMv() override;
}; };

View File

@ -1,9 +1,9 @@
#pragma once #pragma once
#include "../mesh/generated/meshtastic/telemetry.pb.h" #include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "main.h"
#define DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 #define DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
extern uint8_t nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1];
class TelemetrySensor class TelemetrySensor
{ {
@ -18,6 +18,7 @@ class TelemetrySensor
const char *sensorName; const char *sensorName;
meshtastic_TelemetrySensorType sensorType; meshtastic_TelemetrySensorType sensorType;
unsigned status; unsigned status;
bool initialized = false;
int32_t initI2CSensor() int32_t initI2CSensor()
{ {
@ -28,6 +29,7 @@ class TelemetrySensor
LOG_INFO("Opened %s sensor on default i2c bus\n", sensorName); LOG_INFO("Opened %s sensor on default i2c bus\n", sensorName);
setup(); setup();
} }
initialized = true;
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
} }
virtual void setup(); virtual void setup();
@ -36,5 +38,8 @@ class TelemetrySensor
bool hasSensor() { return sensorType < sizeof(nodeTelemetrySensorsMap) && nodeTelemetrySensorsMap[sensorType] > 0; } bool hasSensor() { return sensorType < sizeof(nodeTelemetrySensorsMap) && nodeTelemetrySensorsMap[sensorType] > 0; }
virtual int32_t runOnce() = 0; virtual int32_t runOnce() = 0;
virtual bool isInitialized() { return initialized; }
virtual bool isRunning() { return status > 0; }
virtual bool getMetrics(meshtastic_Telemetry *measurement) = 0; virtual bool getMetrics(meshtastic_Telemetry *measurement) = 0;
}; };

View File

@ -0,0 +1,7 @@
#pragma once
class VoltageSensor
{
public:
virtual uint16_t getBusVoltageMv() = 0;
};

View File

@ -22,6 +22,13 @@ extern RTC_NOINIT_ATTR uint64_t RTC_reg_b;
#include "soc/sens_reg.h" // needed for adc pin reset #include "soc/sens_reg.h" // needed for adc pin reset
#endif #endif
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
#include "modules/Telemetry/Sensor/INA219Sensor.h"
#include "modules/Telemetry/Sensor/INA260Sensor.h"
extern INA260Sensor ina260Sensor;
extern INA219Sensor ina219Sensor;
#endif
class Power : private concurrency::OSThread class Power : private concurrency::OSThread
{ {
@ -41,7 +48,6 @@ class Power : private concurrency::OSThread
/// Setup a xpowers chip axp192/axp2101, return true if found /// Setup a xpowers chip axp192/axp2101, return true if found
bool axpChipInit(); bool axpChipInit();
/// Setup a simple ADC input based battery sensor /// Setup a simple ADC input based battery sensor
bool analogInit(); bool analogInit();