Add battery sensing (mostly) for TBEAM0.7

However, disabled until someone with suitable hardware can test and report
back.

@slavino and @tschundler would you be willing to try it with your boards?

You'll need to uncomment the following line in configuration.h

// #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
This commit is contained in:
geeksville 2020-08-12 17:03:36 -07:00
parent c30b570e16
commit 6a402b13fa
5 changed files with 131 additions and 57 deletions

View File

@ -69,6 +69,7 @@ lib_deps =
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
https://github.com/meshtastic/RadioLib.git#d6b12f7eb0a06bd2414c79b437b25d377e3f603f https://github.com/meshtastic/RadioLib.git#d6b12f7eb0a06bd2414c79b437b25d377e3f603f
https://github.com/meshtastic/TinyGPSPlus.git https://github.com/meshtastic/TinyGPSPlus.git
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
; Common settings for ESP targes, mixin with extends = esp32_base ; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base] [esp32_base]
@ -99,7 +100,6 @@ extends = esp32_base
board = ttgo-t-beam board = ttgo-t-beam
lib_deps = lib_deps =
${env.lib_deps} ${env.lib_deps}
https://github.com/meshtastic/AXP202X_Library.git
build_flags = build_flags =
${esp32_base.build_flags} -D TBEAM_V10 ${esp32_base.build_flags} -D TBEAM_V10

View File

@ -1,27 +1,92 @@
#include "power.h" #include "power.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "main.h" #include "main.h"
#include "utils.h"
#include "sleep.h" #include "sleep.h"
#include "utils.h"
#ifdef TBEAM_V10
// FIXME. nasty hack cleanup how we load axp192 // FIXME. nasty hack cleanup how we load axp192
#undef AXP192_SLAVE_ADDRESS #undef AXP192_SLAVE_ADDRESS
#include "axp20x.h" #include "axp20x.h"
#ifdef TBEAM_V10
AXP20X_Class axp; AXP20X_Class axp;
#endif
bool pmu_irq = false; bool pmu_irq = false;
Power *power; Power *power;
/**
* If this board has a battery level sensor, set this to a valid implementation
*/
static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level sensor
/**
* A simple battery level sensor that assumes the battery voltage is attached via a voltage-divider to an analog input
*/
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 getBattPercentage()
{
float v = getBattVoltage();
if (v < 2.1)
return -1;
return 100 * (getBattVoltage() - 3.27) / (4.2 - 3.27);
}
/**
* The raw voltage of the battery or NAN if unknown
*/
virtual float getBattVoltage()
{
return
#ifdef BATTERY_PIN
analogRead(BATTERY_PIN) * 2.0 * (3.3 / 1024.0);
#else
NAN;
#endif
}
/**
* return true if there is a battery installed in this unit
*/
virtual bool isBatteryConnect() { return true; }
} analogLevel;
bool Power::analogInit()
{
#ifdef BATTERY_PIN
DEBUG_MSG("Using analog input for battery level\n");
adcAttachPin(BATTERY_PIN);
// adcStart(BATTERY_PIN);
analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
batteryLevel = &analogLevel;
return true;
#else
return false;
#endif
}
bool Power::setup() bool Power::setup()
{ {
bool found = axp192Init();
axp192Init(); if (!found) {
found = analogInit();
}
if (found) {
concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
setPeriod(1); setPeriod(1);
}
return axp192_found; return found;
} }
/// Reads power status to powerStatus singleton. /// Reads power status to powerStatus singleton.
@ -29,30 +94,35 @@ bool Power::setup()
// TODO(girts): move this and other axp stuff to power.h/power.cpp. // TODO(girts): move this and other axp stuff to power.h/power.cpp.
void Power::readPowerStatus() void Power::readPowerStatus()
{ {
bool hasBattery = axp.isBatteryConnect(); if (batteryLevel) {
bool hasBattery = batteryLevel->isBatteryConnect();
int batteryVoltageMv = 0; int batteryVoltageMv = 0;
uint8_t batteryChargePercent = 0; uint8_t batteryChargePercent = 0;
if (hasBattery) { if (hasBattery) {
batteryVoltageMv = axp.getBattVoltage(); batteryVoltageMv = batteryLevel->getBattVoltage();
// If the AXP192 returns a valid battery percentage, use it // If the AXP192 returns a valid battery percentage, use it
if (axp.getBattPercentage() >= 0) { if (batteryLevel->getBattPercentage() >= 0) {
batteryChargePercent = axp.getBattPercentage(); batteryChargePercent = batteryLevel->getBattPercentage();
} else { } else {
// If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error // 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 maximum and minimum voltages defined in
batteryChargePercent = clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)), 0, 100); // power.h
batteryChargePercent =
clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)),
0, 100);
} }
} }
// Notify any status instances that are observing us // Notify any status instances that are observing us
const meshtastic::PowerStatus powerStatus = meshtastic::PowerStatus(hasBattery, axp.isVBUSPlug(), axp.isChargeing(), batteryVoltageMv, batteryChargePercent); const meshtastic::PowerStatus powerStatus = meshtastic::PowerStatus(
hasBattery, batteryLevel->isVBUSPlug(), batteryLevel->isChargeing(), batteryVoltageMv, batteryChargePercent);
newStatus.notifyObservers(&powerStatus); newStatus.notifyObservers(&powerStatus);
// If we have a battery at all and it is less than 10% full, force deep sleep // If we have a battery at all and it is less than 10% full, force deep sleep
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() && if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
axp.getBattVoltage() < MIN_BAT_MILLIVOLTS)
powerFSM.trigger(EVENT_LOW_BATTERY); powerFSM.trigger(EVENT_LOW_BATTERY);
} }
}
void Power::doTask() void Power::doTask()
{ {
@ -62,9 +132,7 @@ void Power::doTask()
if (statusHandler && statusHandler->isInitialized()) if (statusHandler && statusHandler->isInitialized())
setPeriod(1000 * 20); setPeriod(1000 * 20);
} }
#endif // TBEAM_V10
#ifdef AXP192_SLAVE_ADDRESS
/** /**
* Init the power manager chip * Init the power manager chip
* *
@ -74,10 +142,13 @@ void Power::doTask()
30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can 30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
*/ */
void Power::axp192Init() bool Power::axp192Init()
{ {
#ifdef TBEAM_V10
if (axp192_found) { if (axp192_found) {
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) { if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
batteryLevel = &axp;
DEBUG_MSG("AXP192 Begin PASS\n"); DEBUG_MSG("AXP192 Begin PASS\n");
// axp.setChgLEDMode(LED_BLINK_4HZ); // axp.setChgLEDMode(LED_BLINK_4HZ);
@ -135,12 +206,16 @@ void Power::axp192Init()
} else { } else {
DEBUG_MSG("AXP192 not found\n"); DEBUG_MSG("AXP192 not found\n");
} }
}
return axp192_found;
#else
return false;
#endif #endif
}
void Power::loop() void Power::loop()
{ {
#ifdef PMU_IRQ #ifdef PMU_IRQ
if (pmu_irq) { if (pmu_irq) {
pmu_irq = false; pmu_irq = false;
@ -174,6 +249,5 @@ void Power::loop()
axp.clearIRQ(); axp.clearIRQ();
} }
#endif // T_BEAM_V10 #endif
} }

View File

@ -167,7 +167,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Leave undefined to disable our PMU IRQ handler // Leave undefined to disable our PMU IRQ handler
#define PMU_IRQ 35 #define PMU_IRQ 35
#define AXP192_SLAVE_ADDRESS 0x34 #define AXP192_SLAVE_ADDRESS 0x34
#elif defined(TBEAM_V07) #elif defined(TBEAM_V07)
@ -180,6 +179,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define I2C_SCL 22 #define I2C_SCL 22
#define BUTTON_PIN 39 #define BUTTON_PIN 39
// #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#ifndef USE_JTAG #ifndef USE_JTAG
#define RF95_RESET 23 #define RF95_RESET 23
@ -278,6 +278,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define GPS_RX_PIN 36 #define GPS_RX_PIN 36
#define GPS_TX_PIN 39 #define GPS_TX_PIN 39
// #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define I2C_SDA 21 // I2C pins for this board #define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22 #define I2C_SCL 22

View File

@ -210,13 +210,11 @@ void setup()
esp32Setup(); esp32Setup();
#endif #endif
#ifdef TBEAM_V10
// Currently only the tbeam has a PMU // Currently only the tbeam has a PMU
power = new Power(); power = new Power();
power->setup(); power->setup();
power->setStatusHandler(powerStatus); power->setStatusHandler(powerStatus);
powerStatus->observe(&power->newStatus); powerStatus->observe(&power->newStatus);
#endif
#ifdef NRF52_SERIES #ifdef NRF52_SERIES
nrf52Setup(); nrf52Setup();

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "concurrency/PeriodicTask.h"
#include "PowerStatus.h" #include "PowerStatus.h"
#include "concurrency/PeriodicTask.h"
/** /**
* Per @spattinson * Per @spattinson
@ -19,22 +19,22 @@ class Power : public concurrency::PeriodicTask
{ {
public: public:
Observable<const meshtastic::PowerStatus *> newStatus; Observable<const meshtastic::PowerStatus *> newStatus;
void readPowerStatus(); void readPowerStatus();
void loop(); void loop();
virtual bool setup(); virtual bool setup();
virtual void doTask(); virtual void doTask();
void setStatusHandler(meshtastic::PowerStatus *handler) void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; }
{
statusHandler = handler;
}
protected: protected:
meshtastic::PowerStatus *statusHandler; meshtastic::PowerStatus *statusHandler;
virtual void axp192Init();
/// Setup a axp192, return true if found
bool axp192Init();
/// Setup a simple ADC input based battery sensor
bool analogInit();
}; };
extern Power *power; extern Power *power;