2020-06-29 02:03:39 +00:00
|
|
|
#include "power.h"
|
2021-01-17 07:10:08 +00:00
|
|
|
#include "NodeDB.h"
|
2020-06-28 04:19:49 +00:00
|
|
|
#include "PowerFSM.h"
|
2023-01-21 13:34:29 +00:00
|
|
|
#include "buzz/buzz.h"
|
2022-05-07 10:31:21 +00:00
|
|
|
#include "configuration.h"
|
2020-06-28 04:19:49 +00:00
|
|
|
#include "main.h"
|
|
|
|
#include "sleep.h"
|
2020-08-13 00:03:36 +00:00
|
|
|
#include "utils.h"
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2023-02-04 13:56:04 +00:00
|
|
|
#ifdef DEBUG_HEAP_MQTT
|
|
|
|
#include "mqtt/MQTT.h"
|
|
|
|
#include "target_specific.h"
|
|
|
|
#include <WiFi.h>
|
|
|
|
#endif
|
|
|
|
|
2023-03-11 21:40:33 +00:00
|
|
|
#ifndef DELAY_FOREVER
|
2023-03-11 21:48:08 +00:00
|
|
|
#define DELAY_FOREVER portMAX_DELAY
|
2023-03-11 21:40:33 +00:00
|
|
|
#endif
|
|
|
|
|
2022-09-08 02:36:53 +00:00
|
|
|
#ifdef HAS_PMU
|
2022-09-06 07:58:33 +00:00
|
|
|
#include "XPowersAXP192.tpp"
|
2023-01-21 13:34:29 +00:00
|
|
|
#include "XPowersAXP2101.tpp"
|
|
|
|
#include "XPowersLibInterface.hpp"
|
2022-09-06 07:58:33 +00:00
|
|
|
XPowersLibInterface *PMU = NULL;
|
2021-03-15 02:00:20 +00:00
|
|
|
#else
|
2022-05-07 10:31:21 +00:00
|
|
|
// Copy of the base class defined in axp20x.h.
|
2021-03-15 02:00:20 +00:00
|
|
|
// I'd rather not inlude axp20x.h as it brings Wire dependency.
|
2022-05-07 10:31:21 +00:00
|
|
|
class HasBatteryLevel
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Battery state of charge, from 0 to 100 or -1 for unknown
|
|
|
|
*/
|
2022-09-06 07:58:33 +00:00
|
|
|
virtual int getBatteryPercent() { return -1; }
|
2022-05-07 10:31:21 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The raw voltage of the battery or NAN if unknown
|
|
|
|
*/
|
2022-09-06 07:58:33 +00:00
|
|
|
virtual uint16_t getBattVoltage() { return 0; }
|
2022-05-07 10:31:21 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* return true if there is a battery installed in this unit
|
|
|
|
*/
|
|
|
|
virtual bool isBatteryConnect() { return false; }
|
|
|
|
|
2022-09-06 07:58:33 +00:00
|
|
|
virtual bool isVbusIn() { return false; }
|
|
|
|
virtual bool isCharging() { return false; }
|
2021-03-15 02:00:20 +00:00
|
|
|
};
|
2020-08-13 00:03:36 +00:00
|
|
|
#endif
|
|
|
|
|
2020-06-28 04:19:49 +00:00
|
|
|
bool pmu_irq = false;
|
|
|
|
|
|
|
|
Power *power;
|
|
|
|
|
2020-08-25 19:48:47 +00:00
|
|
|
using namespace meshtastic;
|
|
|
|
|
2021-07-24 17:44:27 +00:00
|
|
|
#ifndef AREF_VOLTAGE
|
2022-07-31 12:11:47 +00:00
|
|
|
#if defined(ARCH_NRF52)
|
2020-10-16 09:00:27 +00:00
|
|
|
/*
|
|
|
|
* Internal Reference is +/-0.6V, with an adjustable gain of 1/6, 1/5, 1/4,
|
|
|
|
* 1/3, 1/2 or 1, meaning 3.6, 3.0, 2.4, 1.8, 1.2 or 0.6V for the ADC levels.
|
|
|
|
*
|
|
|
|
* External Reference is VDD/4, with an adjustable gain of 1, 2 or 4, meaning
|
|
|
|
* VDD/4, VDD/2 or VDD for the ADC levels.
|
|
|
|
*
|
|
|
|
* Default settings are internal reference with 1/6 gain (GND..3.6V ADC range)
|
|
|
|
*/
|
|
|
|
#define AREF_VOLTAGE 3.6
|
|
|
|
#else
|
|
|
|
#define AREF_VOLTAGE 3.3
|
|
|
|
#endif
|
2021-07-24 17:44:27 +00:00
|
|
|
#endif
|
2020-10-16 09:00:27 +00:00
|
|
|
|
2020-08-13 00:03:36 +00:00
|
|
|
/**
|
|
|
|
* 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
|
2020-06-28 04:19:49 +00:00
|
|
|
{
|
2020-08-13 00:03:36 +00:00
|
|
|
/**
|
|
|
|
* Battery state of charge, from 0 to 100 or -1 for unknown
|
|
|
|
*
|
|
|
|
* FIXME - use a lipo lookup table, the current % full is super wrong
|
|
|
|
*/
|
2022-09-06 07:58:33 +00:00
|
|
|
virtual int getBatteryPercent() override
|
2020-08-13 00:03:36 +00:00
|
|
|
{
|
2021-03-15 02:00:20 +00:00
|
|
|
float v = getBattVoltage();
|
2020-08-13 00:03:36 +00:00
|
|
|
|
2020-10-18 01:44:29 +00:00
|
|
|
if (v < noBatVolt)
|
2020-08-27 21:46:59 +00:00
|
|
|
return -1; // If voltage is super low assume no battery installed
|
2020-08-13 00:03:36 +00:00
|
|
|
|
2022-07-31 12:11:47 +00:00
|
|
|
#ifdef ARCH_ESP32
|
2021-08-10 07:23:26 +00:00
|
|
|
// This does not work on a RAK4631 with battery connected
|
2020-10-18 01:44:29 +00:00
|
|
|
if (v > chargingVolt)
|
|
|
|
return 0; // While charging we can't report % full on the battery
|
2021-08-10 07:23:26 +00:00
|
|
|
#endif
|
2020-10-18 01:44:29 +00:00
|
|
|
|
2021-08-10 07:23:26 +00:00
|
|
|
return clamp((int)(100 * (v - emptyVolt) / (fullVolt - emptyVolt)), 0, 100);
|
2020-08-13 00:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-08-13 18:23:27 +00:00
|
|
|
* The raw voltage of the batteryin millivolts or NAN if unknown
|
2020-08-13 00:03:36 +00:00
|
|
|
*/
|
2022-09-06 07:58:33 +00:00
|
|
|
virtual uint16_t getBattVoltage() override
|
2020-08-13 00:03:36 +00:00
|
|
|
{
|
2021-03-15 02:00:20 +00:00
|
|
|
|
|
|
|
#ifndef ADC_MULTIPLIER
|
|
|
|
#define ADC_MULTIPLIER 2.0
|
2022-05-07 10:31:21 +00:00
|
|
|
#endif
|
2021-03-15 02:00:20 +00:00
|
|
|
|
2022-12-05 15:40:23 +00:00
|
|
|
#ifndef BATTERY_SENSE_SAMPLES
|
|
|
|
#define BATTERY_SENSE_SAMPLES 30
|
|
|
|
#endif
|
|
|
|
|
2020-08-13 00:03:36 +00:00
|
|
|
#ifdef BATTERY_PIN
|
2022-05-01 19:21:30 +00:00
|
|
|
// Override variant or default ADC_MULTIPLIER if we have the override pref
|
2023-01-21 13:34:29 +00:00
|
|
|
float operativeAdcMultiplier =
|
|
|
|
config.power.adc_multiplier_override > 0 ? config.power.adc_multiplier_override : ADC_MULTIPLIER;
|
2022-05-07 10:31:21 +00:00
|
|
|
// Do not call analogRead() often.
|
2021-03-15 02:00:20 +00:00
|
|
|
const uint32_t min_read_interval = 5000;
|
|
|
|
if (millis() - last_read_time_ms > min_read_interval) {
|
|
|
|
last_read_time_ms = millis();
|
2022-07-30 12:12:28 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic
|
|
|
|
// environment.
|
2022-07-30 12:12:28 +00:00
|
|
|
uint32_t raw = 0;
|
2023-01-21 13:34:29 +00:00
|
|
|
for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
|
2022-07-30 12:12:28 +00:00
|
|
|
raw += analogRead(BATTERY_PIN);
|
|
|
|
}
|
2023-01-21 13:34:29 +00:00
|
|
|
raw = raw / BATTERY_SENSE_SAMPLES;
|
2022-07-30 12:12:28 +00:00
|
|
|
|
2021-07-24 17:44:27 +00:00
|
|
|
float scaled;
|
2022-05-07 10:31:21 +00:00
|
|
|
#ifndef VBAT_RAW_TO_SCALED
|
2022-02-09 19:37:48 +00:00
|
|
|
scaled = 1000.0 * operativeAdcMultiplier * (AREF_VOLTAGE / 1024.0) * raw;
|
2022-05-07 10:31:21 +00:00
|
|
|
#else
|
|
|
|
scaled = VBAT_RAW_TO_SCALED(raw); // defined in variant.h
|
|
|
|
#endif
|
2022-12-30 02:41:37 +00:00
|
|
|
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
|
2021-03-15 02:00:20 +00:00
|
|
|
last_read_value = scaled;
|
2022-09-28 20:53:26 +00:00
|
|
|
return scaled;
|
2021-03-15 02:00:20 +00:00
|
|
|
} else {
|
|
|
|
return last_read_value;
|
|
|
|
}
|
2020-08-13 00:03:36 +00:00
|
|
|
#else
|
2022-09-06 07:58:33 +00:00
|
|
|
return 0;
|
2020-08-13 00:03:36 +00:00
|
|
|
#endif
|
|
|
|
}
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2020-08-13 00:03:36 +00:00
|
|
|
/**
|
|
|
|
* return true if there is a battery installed in this unit
|
|
|
|
*/
|
2023-01-21 13:34:29 +00:00
|
|
|
virtual bool isBatteryConnect() override
|
|
|
|
{
|
|
|
|
return getBatteryPercent() != -1;
|
|
|
|
}
|
2020-10-18 01:44:29 +00:00
|
|
|
|
|
|
|
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
|
|
|
/// in power
|
2023-03-31 10:43:42 +00:00
|
|
|
/// On some boards we don't have the power management chip (like AXPxxxx)
|
|
|
|
/// so we use EXT_PWR_DETECT GPIO pin to detect external power source
|
2023-01-21 13:34:29 +00:00
|
|
|
virtual bool isVbusIn() override
|
|
|
|
{
|
2023-03-31 10:43:42 +00:00
|
|
|
#ifdef EXT_PWR_DETECT
|
2023-04-02 08:34:31 +00:00
|
|
|
// if external powered that pin will be pulled up
|
|
|
|
if (digitalRead(EXT_PWR_DETECT) == HIGH) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// if it's not HIGH - check the battery
|
2023-03-31 10:43:42 +00:00
|
|
|
#endif
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
return getBattVoltage() > chargingVolt;
|
|
|
|
}
|
2020-10-18 01:44:29 +00:00
|
|
|
|
|
|
|
/// Assume charging if we have a battery and external power is connected.
|
|
|
|
/// we can't be smart enough to say 'full'?
|
2023-01-21 13:34:29 +00:00
|
|
|
virtual bool isCharging() override
|
|
|
|
{
|
|
|
|
return isBatteryConnect() && isVbusIn();
|
|
|
|
}
|
2020-10-18 01:44:29 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
|
|
|
/// in power
|
2021-05-09 02:31:42 +00:00
|
|
|
|
2022-08-10 11:26:43 +00:00
|
|
|
#ifndef BAT_FULLVOLT
|
|
|
|
#define BAT_FULLVOLT 4200
|
2023-01-21 13:34:29 +00:00
|
|
|
#endif
|
2022-08-10 11:26:43 +00:00
|
|
|
#ifndef BAT_EMPTYVOLT
|
|
|
|
#define BAT_EMPTYVOLT 3270
|
2023-01-21 13:34:29 +00:00
|
|
|
#endif
|
2022-08-10 11:26:43 +00:00
|
|
|
#ifndef BAT_CHARGINGVOLT
|
|
|
|
#define BAT_CHARGINGVOLT 4210
|
2023-01-21 13:34:29 +00:00
|
|
|
#endif
|
2022-08-10 11:26:43 +00:00
|
|
|
#ifndef BAT_NOBATVOLT
|
|
|
|
#define BAT_NOBATVOLT 2230
|
2023-01-21 13:34:29 +00:00
|
|
|
#endif
|
2022-08-10 11:26:43 +00:00
|
|
|
|
2021-05-09 02:31:42 +00:00
|
|
|
/// For heltecs with no battery connected, the measured voltage is 2204, so raising to 2230 from 2100
|
2022-08-10 11:26:43 +00:00
|
|
|
const float fullVolt = BAT_FULLVOLT, emptyVolt = BAT_EMPTYVOLT, chargingVolt = BAT_CHARGINGVOLT, noBatVolt = BAT_NOBATVOLT;
|
2021-03-15 02:00:20 +00:00
|
|
|
float last_read_value = 0.0;
|
|
|
|
uint32_t last_read_time_ms = 0;
|
2021-07-24 17:44:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
AnalogBatteryLevel analogLevel;
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2022-05-07 10:31:21 +00:00
|
|
|
Power::Power() : OSThread("Power")
|
|
|
|
{
|
2022-01-24 07:00:14 +00:00
|
|
|
statusHandler = {};
|
|
|
|
low_voltage_counter = 0;
|
2022-12-16 19:46:43 +00:00
|
|
|
#ifdef DEBUG_HEAP
|
2023-02-17 11:31:51 +00:00
|
|
|
lastheap = memGet.getFreeHeap();
|
2022-12-16 19:46:43 +00:00
|
|
|
#endif
|
2022-01-24 07:00:14 +00:00
|
|
|
}
|
2020-10-09 06:16:51 +00:00
|
|
|
|
2020-08-13 00:03:36 +00:00
|
|
|
bool Power::analogInit()
|
|
|
|
{
|
2023-03-31 11:42:50 +00:00
|
|
|
#ifdef EXT_PWR_DETECT
|
|
|
|
pinMode(EXT_PWR_DETECT, INPUT);
|
|
|
|
#endif
|
|
|
|
|
2020-08-13 00:03:36 +00:00
|
|
|
#ifdef BATTERY_PIN
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("Using analog input %d for battery level\n", BATTERY_PIN);
|
2020-10-16 09:00:27 +00:00
|
|
|
|
|
|
|
// disable any internal pullups
|
|
|
|
pinMode(BATTERY_PIN, INPUT);
|
|
|
|
|
2022-07-31 12:11:47 +00:00
|
|
|
#ifdef ARCH_ESP32
|
2020-09-27 01:13:16 +00:00
|
|
|
// ESP32 needs special analog stuff
|
2020-08-13 00:03:36 +00:00
|
|
|
adcAttachPin(BATTERY_PIN);
|
2020-09-27 01:13:16 +00:00
|
|
|
#endif
|
2022-07-31 12:11:47 +00:00
|
|
|
#ifdef ARCH_NRF52
|
2021-07-24 17:44:27 +00:00
|
|
|
#ifdef VBAT_AR_INTERNAL
|
2022-05-07 10:31:21 +00:00
|
|
|
analogReference(VBAT_AR_INTERNAL);
|
2021-07-24 17:44:27 +00:00
|
|
|
#else
|
2020-10-16 09:00:27 +00:00
|
|
|
analogReference(AR_INTERNAL); // 3.6V
|
|
|
|
#endif
|
2021-07-24 17:44:27 +00:00
|
|
|
#endif
|
2020-10-16 09:00:27 +00:00
|
|
|
|
2021-07-24 17:44:27 +00:00
|
|
|
#ifndef BATTERY_SENSE_RESOLUTION_BITS
|
|
|
|
#define BATTERY_SENSE_RESOLUTION_BITS 10
|
|
|
|
#endif
|
2022-05-07 10:31:21 +00:00
|
|
|
|
2020-08-13 00:03:36 +00:00
|
|
|
// adcStart(BATTERY_PIN);
|
2022-05-07 10:31:21 +00:00
|
|
|
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); // Default of 12 is not very linear. Recommended to use 10 or 11
|
|
|
|
// depending on needed resolution.
|
2020-08-13 00:03:36 +00:00
|
|
|
batteryLevel = &analogLevel;
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Power::setup()
|
|
|
|
{
|
2022-09-06 07:58:33 +00:00
|
|
|
bool found = axpChipInit();
|
2020-08-13 00:03:36 +00:00
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
found = analogInit();
|
|
|
|
}
|
2020-10-09 06:16:51 +00:00
|
|
|
enabled = found;
|
2021-09-19 13:03:37 +00:00
|
|
|
low_voltage_counter = 0;
|
2020-08-13 00:03:36 +00:00
|
|
|
|
|
|
|
return found;
|
2020-06-28 04:19:49 +00:00
|
|
|
}
|
|
|
|
|
2020-11-23 03:01:48 +00:00
|
|
|
void Power::shutdown()
|
|
|
|
{
|
2022-10-31 01:40:30 +00:00
|
|
|
screen->setOn(false);
|
2022-10-28 00:59:53 +00:00
|
|
|
#if defined(USE_EINK) && defined(PIN_EINK_EN)
|
2023-01-21 13:34:29 +00:00
|
|
|
digitalWrite(PIN_EINK_EN, LOW); // power off backlight first
|
2022-10-27 18:03:27 +00:00
|
|
|
#endif
|
2022-09-06 07:58:33 +00:00
|
|
|
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("Shutting down\n");
|
2023-03-11 21:40:33 +00:00
|
|
|
|
|
|
|
#ifdef HAS_PMU
|
2023-04-11 10:36:44 +00:00
|
|
|
if (pmu_found == true) {
|
2022-09-06 07:58:33 +00:00
|
|
|
PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF);
|
2023-04-11 10:36:44 +00:00
|
|
|
PMU->shutdown();
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
2023-04-11 10:36:44 +00:00
|
|
|
#elif defined(ARCH_NRF52) || defined(ARCH_ESP32)
|
2023-03-11 21:40:33 +00:00
|
|
|
#ifdef PIN_LED1
|
2022-06-06 16:48:22 +00:00
|
|
|
ledOff(PIN_LED1);
|
2023-03-11 21:40:33 +00:00
|
|
|
#endif
|
|
|
|
#ifdef PIN_LED2
|
2022-06-06 16:48:22 +00:00
|
|
|
ledOff(PIN_LED2);
|
2023-03-11 21:40:33 +00:00
|
|
|
#endif
|
|
|
|
#ifdef PIN_LED3
|
|
|
|
ledOff(PIN_LED2);
|
|
|
|
#endif
|
2021-03-15 02:00:20 +00:00
|
|
|
doDeepSleep(DELAY_FOREVER);
|
2020-11-23 03:01:48 +00:00
|
|
|
#endif
|
2020-11-23 02:50:14 +00:00
|
|
|
}
|
|
|
|
|
2020-06-28 04:19:49 +00:00
|
|
|
/// Reads power status to powerStatus singleton.
|
|
|
|
//
|
|
|
|
// TODO(girts): move this and other axp stuff to power.h/power.cpp.
|
|
|
|
void Power::readPowerStatus()
|
|
|
|
{
|
2020-08-13 00:03:36 +00:00
|
|
|
if (batteryLevel) {
|
|
|
|
bool hasBattery = batteryLevel->isBatteryConnect();
|
|
|
|
int batteryVoltageMv = 0;
|
2020-08-25 19:48:47 +00:00
|
|
|
int8_t batteryChargePercent = 0;
|
2020-08-13 00:03:36 +00:00
|
|
|
if (hasBattery) {
|
|
|
|
batteryVoltageMv = batteryLevel->getBattVoltage();
|
|
|
|
// If the AXP192 returns a valid battery percentage, use it
|
2022-09-06 07:58:33 +00:00
|
|
|
if (batteryLevel->getBatteryPercent() >= 0) {
|
|
|
|
batteryChargePercent = batteryLevel->getBatteryPercent();
|
2020-08-13 00:03:36 +00:00
|
|
|
} 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
|
|
|
|
batteryChargePercent =
|
|
|
|
clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)),
|
|
|
|
0, 100);
|
|
|
|
}
|
2020-06-28 04:19:49 +00:00
|
|
|
}
|
2020-06-29 01:17:52 +00:00
|
|
|
|
2020-08-13 00:03:36 +00:00
|
|
|
// Notify any status instances that are observing us
|
2022-01-24 18:39:17 +00:00
|
|
|
const PowerStatus powerStatus2 =
|
2022-09-06 07:58:33 +00:00
|
|
|
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVbusIn() ? OptTrue : OptFalse,
|
|
|
|
batteryLevel->isCharging() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
|
2022-01-24 18:39:17 +00:00
|
|
|
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
|
|
|
|
newStatus.notifyObservers(&powerStatus2);
|
2022-11-30 08:52:28 +00:00
|
|
|
#ifdef DEBUG_HEAP
|
2023-02-17 11:31:51 +00:00
|
|
|
if (lastheap != memGet.getFreeHeap()) {
|
2022-12-30 19:18:19 +00:00
|
|
|
LOG_DEBUG("Threads running:");
|
2022-12-30 16:03:48 +00:00
|
|
|
int running = 0;
|
2023-01-21 13:34:29 +00:00
|
|
|
for (int i = 0; i < MAX_THREADS; i++) {
|
2022-12-30 16:03:48 +00:00
|
|
|
auto thread = concurrency::mainController.get(i);
|
2023-01-21 13:34:29 +00:00
|
|
|
if ((thread != nullptr) && (thread->enabled)) {
|
2022-12-30 19:18:19 +00:00
|
|
|
LOG_DEBUG(" %s", thread->ThreadName.c_str());
|
2022-12-30 16:03:48 +00:00
|
|
|
running++;
|
|
|
|
}
|
|
|
|
}
|
2022-12-30 19:18:19 +00:00
|
|
|
LOG_DEBUG("\n");
|
2023-02-17 11:31:51 +00:00
|
|
|
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads\n", memGet.getFreeHeap(), memGet.getHeapSize(),
|
|
|
|
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
|
|
|
|
lastheap = memGet.getFreeHeap();
|
2022-12-16 19:25:51 +00:00
|
|
|
}
|
2023-02-04 13:56:04 +00:00
|
|
|
#ifdef DEBUG_HEAP_MQTT
|
|
|
|
if (mqtt) {
|
|
|
|
// send MQTT-Packet with Heap-Size
|
|
|
|
uint8_t dmac[6];
|
|
|
|
getMacAddr(dmac); // Get our hardware ID
|
|
|
|
char mac[18];
|
|
|
|
sprintf(mac, "!%02x%02x%02x%02x", dmac[2], dmac[3], dmac[4], dmac[5]);
|
2023-04-13 21:50:21 +00:00
|
|
|
|
2023-02-17 11:31:51 +00:00
|
|
|
auto newHeap = memGet.getFreeHeap();
|
2023-04-13 20:20:49 +00:00
|
|
|
std::string heapTopic = (*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + "/2/heap/" + std::string(mac);
|
2023-02-04 13:56:04 +00:00
|
|
|
std::string heapString = std::to_string(newHeap);
|
|
|
|
mqtt->pubSub.publish(heapTopic.c_str(), heapString.c_str(), false);
|
2023-02-17 11:31:51 +00:00
|
|
|
// auto fragHeap = memGet.getHeapFragmentation();
|
2023-02-04 13:56:04 +00:00
|
|
|
auto wifiRSSI = WiFi.RSSI();
|
2023-04-13 20:20:49 +00:00
|
|
|
heapTopic = (*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + "/2/wifi/" + std::string(mac);
|
2023-02-04 13:56:04 +00:00
|
|
|
std::string wifiString = std::to_string(wifiRSSI);
|
|
|
|
mqtt->pubSub.publish(heapTopic.c_str(), wifiString.c_str(), false);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-11-30 08:52:28 +00:00
|
|
|
#endif
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2022-05-07 10:31:21 +00:00
|
|
|
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row
|
|
|
|
// Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
|
2022-07-31 12:11:47 +00:00
|
|
|
#ifdef ARCH_NRF52
|
2022-05-07 10:31:21 +00:00
|
|
|
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
|
|
|
|
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) {
|
2021-09-19 13:03:37 +00:00
|
|
|
low_voltage_counter++;
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("Warning RAK4631 Low voltage counter: %d/10\n", low_voltage_counter);
|
2022-12-14 09:13:23 +00:00
|
|
|
if (low_voltage_counter > 10) {
|
2022-12-14 08:36:25 +00:00
|
|
|
// We can't trigger deep sleep on NRF52, it's freezing the board
|
2023-01-21 13:34:29 +00:00
|
|
|
// powerFSM.trigger(EVENT_LOW_BATTERY);
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("Low voltage detected, but not triggering deep sleep\n");
|
2022-12-14 09:29:45 +00:00
|
|
|
}
|
2021-09-19 13:03:37 +00:00
|
|
|
} else {
|
|
|
|
low_voltage_counter = 0;
|
|
|
|
}
|
|
|
|
}
|
2022-05-07 10:31:21 +00:00
|
|
|
#else
|
2020-08-13 00:03:36 +00:00
|
|
|
// If we have a battery at all and it is less than 10% full, force deep sleep
|
2022-01-24 18:39:17 +00:00
|
|
|
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
|
2020-08-13 00:03:36 +00:00
|
|
|
powerFSM.trigger(EVENT_LOW_BATTERY);
|
2022-05-07 10:31:21 +00:00
|
|
|
#endif
|
2020-08-25 19:48:47 +00:00
|
|
|
} else {
|
|
|
|
// No power sensing on this board - tell everyone else we have no idea what is happening
|
2022-01-24 18:39:17 +00:00
|
|
|
const PowerStatus powerStatus3 = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
|
|
|
|
newStatus.notifyObservers(&powerStatus3);
|
2020-08-13 00:03:36 +00:00
|
|
|
}
|
2020-06-28 04:19:49 +00:00
|
|
|
}
|
|
|
|
|
2020-10-10 01:57:57 +00:00
|
|
|
int32_t Power::runOnce()
|
2020-06-28 04:19:49 +00:00
|
|
|
{
|
|
|
|
readPowerStatus();
|
2020-08-13 00:03:36 +00:00
|
|
|
|
2022-09-08 02:36:53 +00:00
|
|
|
#ifdef HAS_PMU
|
2020-10-12 01:27:07 +00:00
|
|
|
// WE no longer use the IRQ line to wake the CPU (due to false wakes from sleep), but we do poll
|
|
|
|
// the IRQ status by reading the registers over I2C
|
2023-01-21 13:34:29 +00:00
|
|
|
if (PMU) {
|
2020-10-09 06:16:51 +00:00
|
|
|
|
2022-09-06 07:58:33 +00:00
|
|
|
PMU->getIrqStatus();
|
2020-10-09 06:16:51 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
if (PMU->isVbusRemoveIrq()) {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("USB unplugged\n");
|
2022-09-06 07:58:33 +00:00
|
|
|
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PMU->isVbusInsertIrq()) {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("USB plugged In\n");
|
2022-09-06 07:58:33 +00:00
|
|
|
powerFSM.trigger(EVENT_POWER_CONNECTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Other things we could check if we cared...
|
|
|
|
|
|
|
|
if (PMU->isBatChagerStartIrq()) {
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("Battery start charging\n");
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isBatChagerDoneIrq()) {
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("Battery fully charged\n");
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isBatInsertIrq()) {
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("Battery inserted\n");
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isBatRemoveIrq()) {
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("Battery removed\n");
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
*/
|
2022-10-31 01:40:30 +00:00
|
|
|
if (PMU->isPekeyLongPressIrq()) {
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("PEK long button press\n");
|
2022-10-31 01:40:30 +00:00
|
|
|
screen->setOn(false);
|
|
|
|
}
|
2022-09-06 07:58:33 +00:00
|
|
|
|
|
|
|
PMU->clearIrqStatus();
|
2020-10-12 01:27:07 +00:00
|
|
|
}
|
2020-10-12 01:33:15 +00:00
|
|
|
#endif
|
2020-06-28 04:19:49 +00:00
|
|
|
// Only read once every 20 seconds once the power status for the app has been initialized
|
2020-10-10 01:57:57 +00:00
|
|
|
return (statusHandler && statusHandler->isInitialized()) ? (1000 * 20) : RUN_SAME;
|
2020-06-28 04:19:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Init the power manager chip
|
|
|
|
*
|
|
|
|
* axp192 power
|
|
|
|
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose comms to the axp192 because the OLED and the axp192
|
|
|
|
share the same i2c bus, instead use ssd1306 sleep mode DCDC2 -> unused DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this on!) LDO1
|
|
|
|
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
|
2023-01-21 13:34:29 +00:00
|
|
|
*
|
2020-06-28 04:19:49 +00:00
|
|
|
*/
|
2022-09-06 07:58:33 +00:00
|
|
|
bool Power::axpChipInit()
|
2020-06-28 04:19:49 +00:00
|
|
|
{
|
2021-01-17 07:10:08 +00:00
|
|
|
|
2022-09-08 02:36:53 +00:00
|
|
|
#ifdef HAS_PMU
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
TwoWire *w = NULL;
|
2022-10-07 11:57:55 +00:00
|
|
|
|
|
|
|
// Use macro to distinguish which wire is used by PMU
|
|
|
|
#ifdef PMU_USE_WIRE1
|
2023-01-21 13:34:29 +00:00
|
|
|
w = &Wire1;
|
2022-10-07 11:57:55 +00:00
|
|
|
#else
|
2023-01-21 13:34:29 +00:00
|
|
|
w = &Wire;
|
2022-10-07 11:57:55 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
2023-01-21 13:34:29 +00:00
|
|
|
* It is not necessary to specify the wire pin,
|
2022-10-07 11:57:55 +00:00
|
|
|
* just input the wire, because the wire has been initialized in main.cpp
|
|
|
|
*/
|
2022-09-06 07:58:33 +00:00
|
|
|
if (!PMU) {
|
2022-10-07 11:57:55 +00:00
|
|
|
PMU = new XPowersAXP2101(*w);
|
2022-09-06 07:58:33 +00:00
|
|
|
if (!PMU->init()) {
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_WARN("Failed to find AXP2101 power management\n");
|
2022-09-06 07:58:33 +00:00
|
|
|
delete PMU;
|
|
|
|
PMU = NULL;
|
|
|
|
} else {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("AXP2101 PMU init succeeded, using AXP2101 PMU\n");
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2022-09-06 07:58:33 +00:00
|
|
|
if (!PMU) {
|
2022-10-07 11:57:55 +00:00
|
|
|
PMU = new XPowersAXP192(*w);
|
2022-09-06 07:58:33 +00:00
|
|
|
if (!PMU->init()) {
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_WARN("Failed to find AXP192 power management\n");
|
2022-09-06 07:58:33 +00:00
|
|
|
delete PMU;
|
|
|
|
PMU = NULL;
|
2020-06-28 04:19:49 +00:00
|
|
|
} else {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("AXP192 PMU init succeeded, using AXP192 PMU\n");
|
2020-06-28 04:19:49 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-13 00:03:36 +00:00
|
|
|
|
2022-09-06 07:58:33 +00:00
|
|
|
if (!PMU) {
|
2023-01-21 13:34:29 +00:00
|
|
|
/*
|
|
|
|
* In XPowersLib, if the XPowersAXPxxx object is released, Wire.end() will be called at the same time.
|
|
|
|
* In order not to affect other devices, if the initialization of the PMU fails, Wire needs to be re-initialized once,
|
|
|
|
* if there are multiple devices sharing the bus.
|
|
|
|
* * */
|
2022-10-07 11:57:55 +00:00
|
|
|
#ifndef PMU_USE_WIRE1
|
|
|
|
w->begin(I2C_SDA, I2C_SCL);
|
|
|
|
#endif
|
2022-09-06 07:58:33 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
batteryLevel = PMU;
|
|
|
|
|
|
|
|
if (PMU->getChipModel() == XPOWERS_AXP192) {
|
2023-01-21 13:34:29 +00:00
|
|
|
|
2022-09-06 07:58:33 +00:00
|
|
|
// lora radio power channel
|
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300);
|
|
|
|
PMU->enablePowerOutput(XPOWERS_LDO2);
|
|
|
|
|
|
|
|
// oled module power channel,
|
2023-01-21 13:34:29 +00:00
|
|
|
// disable it will cause abnormal communication between boot and AXP power supply,
|
2022-09-06 07:58:33 +00:00
|
|
|
// do not turn it off
|
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
|
|
|
|
// enable oled power
|
|
|
|
PMU->enablePowerOutput(XPOWERS_DCDC1);
|
|
|
|
|
|
|
|
// gnss module power channel - now turned on in setGpsPower
|
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300);
|
|
|
|
// PMU->enablePowerOutput(XPOWERS_LDO3);
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// protected oled power source
|
2022-09-06 07:58:33 +00:00
|
|
|
PMU->setProtectedChannel(XPOWERS_DCDC1);
|
2023-01-21 13:34:29 +00:00
|
|
|
// protected esp32 power source
|
2022-09-06 07:58:33 +00:00
|
|
|
PMU->setProtectedChannel(XPOWERS_DCDC3);
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// disable not use channel
|
2022-09-06 07:58:33 +00:00
|
|
|
PMU->disablePowerOutput(XPOWERS_DCDC2);
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// disable all axp chip interrupt
|
2022-09-06 07:58:33 +00:00
|
|
|
PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
|
|
|
|
|
|
|
|
// Set constant current charging current
|
2022-09-09 19:49:54 +00:00
|
|
|
PMU->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_450MA);
|
2022-09-06 07:58:33 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// Set up the charging voltage
|
2022-12-06 15:56:38 +00:00
|
|
|
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
|
|
|
|
2022-09-06 07:58:33 +00:00
|
|
|
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
|
|
|
|
|
2023-03-27 08:50:17 +00:00
|
|
|
/*The alternative version of T-Beam 1.1 differs from T-Beam V1.1 in that it uses an AXP2101 power chip*/
|
2023-03-27 09:02:17 +00:00
|
|
|
#if (HW_VENDOR == meshtastic_HardwareModel_TBEAM)
|
2023-03-27 08:50:17 +00:00
|
|
|
// Unuse power channel
|
2023-03-27 02:33:26 +00:00
|
|
|
PMU->disablePowerOutput(XPOWERS_DCDC2);
|
|
|
|
PMU->disablePowerOutput(XPOWERS_DCDC3);
|
|
|
|
PMU->disablePowerOutput(XPOWERS_DCDC4);
|
|
|
|
PMU->disablePowerOutput(XPOWERS_DCDC5);
|
|
|
|
PMU->disablePowerOutput(XPOWERS_ALDO1);
|
|
|
|
PMU->disablePowerOutput(XPOWERS_ALDO4);
|
|
|
|
PMU->disablePowerOutput(XPOWERS_BLDO1);
|
|
|
|
PMU->disablePowerOutput(XPOWERS_BLDO2);
|
|
|
|
PMU->disablePowerOutput(XPOWERS_DLDO1);
|
|
|
|
PMU->disablePowerOutput(XPOWERS_DLDO2);
|
|
|
|
|
|
|
|
// GNSS RTC PowerVDD 3300mV
|
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
|
|
|
|
PMU->enablePowerOutput(XPOWERS_VBACKUP);
|
|
|
|
|
2023-03-27 08:50:17 +00:00
|
|
|
// ESP32 VDD 3300mV
|
|
|
|
// ! No need to set, automatically open , Don't close it
|
|
|
|
// PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
|
|
|
|
// PMU->setProtectedChannel(XPOWERS_DCDC1);
|
2023-03-27 02:33:26 +00:00
|
|
|
|
|
|
|
// LoRa VDD 3300mV
|
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
|
|
|
|
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
|
|
|
|
2023-03-27 08:50:17 +00:00
|
|
|
// GNSS VDD 3300mV
|
2023-03-27 02:33:26 +00:00
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
|
|
|
|
PMU->enablePowerOutput(XPOWERS_ALDO3);
|
2022-09-06 07:58:33 +00:00
|
|
|
|
2023-03-27 09:02:17 +00:00
|
|
|
#elif (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE)
|
2023-03-27 02:33:26 +00:00
|
|
|
// t-beam s3 core
|
2022-09-15 18:43:04 +00:00
|
|
|
/**
|
2023-01-21 13:34:29 +00:00
|
|
|
* gnss module power channel
|
2022-09-15 18:43:04 +00:00
|
|
|
* The default ALDO4 is off, you need to turn on the GNSS power first, otherwise it will be invalid during initialization
|
|
|
|
*/
|
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
|
|
|
|
PMU->enablePowerOutput(XPOWERS_ALDO4);
|
2022-09-06 07:58:33 +00:00
|
|
|
|
|
|
|
// lora radio power channel
|
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
|
|
|
|
PMU->enablePowerOutput(XPOWERS_ALDO3);
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// m.2 interface
|
2022-09-06 07:58:33 +00:00
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
|
|
|
|
PMU->enablePowerOutput(XPOWERS_DCDC3);
|
|
|
|
|
2022-10-07 11:57:55 +00:00
|
|
|
/**
|
2023-01-21 13:34:29 +00:00
|
|
|
* ALDO2 cannot be turned off.
|
|
|
|
* It is a necessary condition for sensor communication.
|
|
|
|
* It must be turned on to properly access the sensor and screen
|
|
|
|
* It is also responsible for the power supply of PCF8563
|
|
|
|
*/
|
2022-10-07 11:57:55 +00:00
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
|
|
|
|
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// 6-axis , magnetometer ,bme280 , oled screen power channel
|
2022-10-07 11:57:55 +00:00
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
|
|
|
|
PMU->enablePowerOutput(XPOWERS_ALDO1);
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// sdcard power channle
|
2022-10-07 11:57:55 +00:00
|
|
|
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
|
|
|
|
PMU->enablePowerOutput(XPOWERS_BLDO1);
|
2023-01-21 13:34:29 +00:00
|
|
|
|
2022-09-06 07:58:33 +00:00
|
|
|
// PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300);
|
|
|
|
// PMU->enablePowerOutput(XPOWERS_DCDC4);
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// not use channel
|
|
|
|
PMU->disablePowerOutput(XPOWERS_DCDC2); // not elicited
|
|
|
|
PMU->disablePowerOutput(XPOWERS_DCDC5); // not elicited
|
|
|
|
PMU->disablePowerOutput(XPOWERS_DLDO1); // Invalid power channel, it does not exist
|
|
|
|
PMU->disablePowerOutput(XPOWERS_DLDO2); // Invalid power channel, it does not exist
|
2022-09-06 07:58:33 +00:00
|
|
|
PMU->disablePowerOutput(XPOWERS_VBACKUP);
|
|
|
|
|
2023-03-27 02:33:26 +00:00
|
|
|
#endif
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// disable all axp chip interrupt
|
2022-09-06 07:58:33 +00:00
|
|
|
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// Set the constant current charging current of AXP2101, temporarily use 500mA by default
|
2022-09-06 07:58:33 +00:00
|
|
|
PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// Set up the charging voltage
|
2022-12-06 15:56:38 +00:00
|
|
|
PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PMU->clearIrqStatus();
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// TBeam1.1 /T-Beam S3-Core has no external TS detection,
|
2022-09-06 07:58:33 +00:00
|
|
|
// it needs to be disabled, otherwise it will cause abnormal charging
|
|
|
|
PMU->disableTSPinMeasure();
|
|
|
|
|
|
|
|
// PMU->enableSystemVoltageMeasure();
|
|
|
|
PMU->enableVbusVoltageMeasure();
|
|
|
|
PMU->enableBattVoltageMeasure();
|
|
|
|
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("=======================================================================\n");
|
2022-09-06 07:58:33 +00:00
|
|
|
if (PMU->isChannelAvailable(XPOWERS_DCDC1)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("DC1 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_DCDC1));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isChannelAvailable(XPOWERS_DCDC2)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("DC2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_DCDC2));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isChannelAvailable(XPOWERS_DCDC3)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("DC3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_DCDC3));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isChannelAvailable(XPOWERS_DCDC4)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("DC4 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_DCDC4));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isChannelAvailable(XPOWERS_LDO2)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("LDO2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_LDO2));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isChannelAvailable(XPOWERS_LDO3)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("LDO3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_LDO3));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isChannelAvailable(XPOWERS_ALDO1)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("ALDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_ALDO1));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isChannelAvailable(XPOWERS_ALDO2)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("ALDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_ALDO2));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isChannelAvailable(XPOWERS_ALDO3)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("ALDO3: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_ALDO3));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isChannelAvailable(XPOWERS_ALDO4)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("ALDO4: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_ALDO4));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isChannelAvailable(XPOWERS_BLDO1)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("BLDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_BLDO1));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (PMU->isChannelAvailable(XPOWERS_BLDO2)) {
|
2023-01-21 13:34:29 +00:00
|
|
|
LOG_DEBUG("BLDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-",
|
|
|
|
PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
|
2022-09-06 07:58:33 +00:00
|
|
|
}
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("=======================================================================\n");
|
2022-09-06 07:58:33 +00:00
|
|
|
|
2022-12-14 16:26:55 +00:00
|
|
|
// We can safely ignore this approach for most (or all) boards because MCU turned off
|
|
|
|
// earlier than battery discharged to 2.6V.
|
|
|
|
//
|
|
|
|
// Unfortanly for now we can't use this killswitch for RAK4630-based boards because they have a bug with
|
|
|
|
// battery voltage measurement. Probably it sometimes drops to low values.
|
|
|
|
#ifndef RAK4630
|
2022-09-06 07:58:33 +00:00
|
|
|
// Set PMU shutdown voltage at 2.6V to maximize battery utilization
|
|
|
|
PMU->setSysPowerDownVoltage(2600);
|
2022-12-14 13:36:15 +00:00
|
|
|
#endif
|
2022-09-06 07:58:33 +00:00
|
|
|
|
|
|
|
#ifdef PMU_IRQ
|
2023-01-21 13:34:29 +00:00
|
|
|
uint64_t pmuIrqMask = 0;
|
2022-09-06 07:58:33 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
if (PMU->getChipModel() == XPOWERS_AXP192) {
|
|
|
|
pmuIrqMask = XPOWERS_AXP192_VBUS_INSERT_IRQ | XPOWERS_AXP192_BAT_INSERT_IRQ | XPOWERS_AXP192_PKEY_SHORT_IRQ;
|
|
|
|
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
|
|
|
|
pmuIrqMask = XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_PKEY_SHORT_IRQ;
|
|
|
|
}
|
2022-09-06 07:58:33 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
pinMode(PMU_IRQ, INPUT);
|
|
|
|
attachInterrupt(
|
|
|
|
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
|
2022-09-06 07:58:33 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
// we do not look for AXPXXX_CHARGING_FINISHED_IRQ & AXPXXX_CHARGING_IRQ because it occurs repeatedly while there is
|
|
|
|
// no battery also it could cause inadvertent waking from light sleep just because the battery filled
|
|
|
|
// we don't look for AXPXXX_BATT_REMOVED_IRQ because it occurs repeatedly while no battery installed
|
|
|
|
// we don't look at AXPXXX_VBUS_REMOVED_IRQ because we don't have anything hooked to vbus
|
|
|
|
PMU->enableIRQ(pmuIrqMask);
|
2022-09-06 07:58:33 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
PMU->clearIrqStatus();
|
2022-09-06 07:58:33 +00:00
|
|
|
#endif /*PMU_IRQ*/
|
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
readPowerStatus();
|
2022-09-06 07:58:33 +00:00
|
|
|
|
2022-09-08 02:32:12 +00:00
|
|
|
pmu_found = true;
|
2022-09-06 07:58:33 +00:00
|
|
|
|
2022-09-08 02:32:12 +00:00
|
|
|
return pmu_found;
|
2022-09-06 07:58:33 +00:00
|
|
|
|
2020-08-13 00:03:36 +00:00
|
|
|
#else
|
|
|
|
return false;
|
2020-06-28 04:19:49 +00:00
|
|
|
#endif
|
2020-08-13 00:03:36 +00:00
|
|
|
}
|