diff --git a/src/Power.cpp b/src/Power.cpp index 1f4c341f0..a911057ba 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -194,7 +194,7 @@ static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level se #ifdef BATTERY_PIN -static void adcEnable() +void battery_adcEnable() { #ifdef ADC_CTRL // enable adc voltage divider when we need to read #ifdef ADC_USE_PULLUP @@ -214,7 +214,7 @@ static void adcEnable() #endif } -static void adcDisable() +static void battery_adcDisable() { #ifdef ADC_CTRL // disable adc voltage divider when we need to read #ifdef ADC_USE_PULLUP @@ -320,7 +320,7 @@ class AnalogBatteryLevel : public HasBatteryLevel uint32_t raw = 0; float scaled = 0; - adcEnable(); + battery_adcEnable(); #ifdef ARCH_ESP32 // ADC block for espressif platforms raw = espAdcRead(); scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs); @@ -332,7 +332,7 @@ class AnalogBatteryLevel : public HasBatteryLevel raw = raw / BATTERY_SENSE_SAMPLES; scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw; #endif - adcDisable(); + battery_adcDisable(); if (!initial_read_done) { // Flush the smoothing filter with an ADC reading, if the reading is plausibly correct @@ -903,13 +903,8 @@ void Power::readPowerStatus() low_voltage_counter++; LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter); if (low_voltage_counter > 10) { -#ifdef ARCH_NRF52 - // We can't trigger deep sleep on NRF52, it's freezing the board - LOG_DEBUG("Low voltage detected, but not trigger deep sleep"); -#else LOG_INFO("Low voltage detected, trigger deep sleep"); powerFSM.trigger(EVENT_LOW_BATTERY); -#endif } } else { low_voltage_counter = 0; @@ -1549,4 +1544,4 @@ bool Power::meshSolarInit() { return false; } -#endif \ No newline at end of file +#endif diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 8ce74d5f7..e3339a04a 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -13,8 +13,11 @@ #include "PowerMon.h" #include "error.h" #include "main.h" +#include "power.h" #include "meshUtils.h" +#include + #ifdef BQ25703A_ADDR #include "BQ25713.h" #endif @@ -389,6 +392,22 @@ void cpuDeepSleep(uint32_t msecToWake) nrf_gpio_cfg_sense_set(BUTTON_PIN, sense); // Apply SENSE to wake up the device from the deep sleep #endif +#ifdef BATTERY_LPCOMP_INPUT + // Wake up if power rises again + nrf_lpcomp_config_t c; + c.reference = BATTERY_LPCOMP_THRESHOLD; + c.detection = NRF_LPCOMP_DETECT_UP; + c.hyst = NRF_LPCOMP_HYST_NOHYST; + nrf_lpcomp_configure(NRF_LPCOMP, &c); + nrf_lpcomp_input_select(NRF_LPCOMP, BATTERY_LPCOMP_INPUT); + nrf_lpcomp_enable(NRF_LPCOMP); + + battery_adcEnable(); + + nrf_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_START); + while(!nrf_lpcomp_event_check(NRF_LPCOMP, NRF_LPCOMP_EVENT_READY)); +#endif + auto ok = sd_power_system_off(); if (ok != NRF_SUCCESS) { LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!"); @@ -420,4 +439,4 @@ void enterDfuMode() #else enterUf2Dfu(); #endif -} \ No newline at end of file +} diff --git a/src/power.h b/src/power.h index 23eb95064..75385e07b 100644 --- a/src/power.h +++ b/src/power.h @@ -143,4 +143,6 @@ class Power : private concurrency::OSThread #endif }; +void battery_adcEnable(); + extern Power *power; diff --git a/variants/nrf52840/heltec_mesh_node_t114/variant.h b/variants/nrf52840/heltec_mesh_node_t114/variant.h index 7e82733aa..b6082fdc6 100644 --- a/variants/nrf52840/heltec_mesh_node_t114/variant.h +++ b/variants/nrf52840/heltec_mesh_node_t114/variant.h @@ -210,6 +210,16 @@ No longer populated on PCB #define VBAT_AR_INTERNAL AR_INTERNAL_3_0 #define ADC_MULTIPLIER (4.916F) +// rf52840 AIN2 = Pin 4 +#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_2 + +// We have AIN2 with a VBAT divider so AIN2 = VBAT * (100/490) +// We have the device going deep sleep under 3.1V, which is AIN2 = 0.63V +// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN2 = 0.67V +// Ratio 0.67/3.3 = 0.20, so we can pick a bit higher, 2/8 VDD, which means +// VBAT=4.04V +#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_2_8 + #define HAS_RTC 0 #ifdef __cplusplus } diff --git a/variants/nrf52840/rak4631/variant.h b/variants/nrf52840/rak4631/variant.h index f5ec11ef2..302e531d5 100644 --- a/variants/nrf52840/rak4631/variant.h +++ b/variants/nrf52840/rak4631/variant.h @@ -267,6 +267,20 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG #define VBAT_AR_INTERNAL AR_INTERNAL_3_0 #define ADC_MULTIPLIER 1.73 +// RAK4630 AIN0 = nrf52840 AIN3 = Pin 5 +#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_3 + +// We have AIN3 with a VBAT divider so AIN3 = VBAT * (1.5/2.5) +// We have the device going deep sleep under 3.1V, which is AIN3 = 1.86V +// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN3 = 1.98V +// 1.98/3.3 = 6/10, but that's close to the VBAT divider, so we +// pick 6/8VDD, which means VBAT=4.1V. +// Reference: +// VDD=3.3V AIN3=5/8*VDD=2.06V VBAT=1.66*AIN3=3.41V +// VDD=3.3V AIN3=11/16*VDD=2.26V VBAT=1.66*AIN3=3.76V +// VDD=3.3V AIN3=6/8*VDD=2.47V VBAT=1.66*AIN3=4.1V +#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_11_16 + #define HAS_RTC 1 #define HAS_ETHERNET 1