From afd4c333587a7714731dea9b18cea81bea21660a Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Mon, 2 Mar 2026 15:10:43 +0100 Subject: [PATCH] Fix RAK4631 boot issue Wait 50ms after boot before actually shutting down on low voltage Also fix deadlock issue where only USB can wake the device --- src/helpers/NRF52Board.cpp | 25 +++++++++++++++++++++---- src/helpers/NRF52Board.h | 2 +- variants/heltec_t114/T114Board.cpp | 4 +++- variants/rak4631/RAK4631Board.cpp | 4 +++- variants/xiao_nrf52/XiaoNrf52Board.cpp | 4 +++- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/helpers/NRF52Board.cpp b/src/helpers/NRF52Board.cpp index 23f7cafc..0a629d22 100644 --- a/src/helpers/NRF52Board.cpp +++ b/src/helpers/NRF52Board.cpp @@ -117,10 +117,17 @@ bool NRF52Board::checkBootVoltage(const PowerMgtConfig* config) { // Only trigger shutdown if reading is valid (>1000mV) AND below threshold // This prevents spurious shutdowns on ADC glitches or uninitialized reads if (boot_voltage_mv > 1000 && boot_voltage_mv < config->voltage_bootlock) { - MESH_DEBUG_PRINTLN("PWRMGT: Boot voltage too low - entering protective shutdown"); + // First reading below threshold - wait for DCDC to stabilize and re-read + delay(50); + boot_voltage_mv = getBattMilliVolts(); + MESH_DEBUG_PRINTLN("PWRMGT: Boot voltage (confirmed) = %u mV (threshold = %u mV)", + boot_voltage_mv, config->voltage_bootlock); - initiateShutdown(SHUTDOWN_REASON_BOOT_PROTECT); - return false; // Should never reach this + if (boot_voltage_mv > 1000 && boot_voltage_mv < config->voltage_bootlock) { + MESH_DEBUG_PRINTLN("PWRMGT: Boot voltage too low - entering protective shutdown"); + initiateShutdown(SHUTDOWN_REASON_BOOT_PROTECT); + return false; // Should never reach this + } } return true; @@ -164,7 +171,7 @@ void NRF52Board::enterSystemOff(uint8_t reason) { NVIC_SystemReset(); } -void NRF52Board::configureVoltageWake(uint8_t ain_channel, uint8_t refsel) { +bool NRF52Board::configureVoltageWake(uint8_t ain_channel, uint8_t refsel) { // LPCOMP is not managed by SoftDevice - direct register access required // Halt and disable before reconfiguration NRF_LPCOMP->TASKS_STOP = 1; @@ -200,6 +207,14 @@ void NRF52Board::configureVoltageWake(uint8_t ain_channel, uint8_t refsel) { delayMicroseconds(50); } + // Safety: if voltage is already above threshold, UP detection will never fire + if (NRF_LPCOMP->RESULT & LPCOMP_RESULT_RESULT_Msk) { + MESH_DEBUG_PRINTLN("PWRMGT: LPCOMP shows voltage above threshold - unsafe for SYSTEMOFF"); + NRF_LPCOMP->TASKS_STOP = 1; + NRF_LPCOMP->ENABLE = LPCOMP_ENABLE_ENABLE_Disabled; + return false; + } + if (refsel == 7) { MESH_DEBUG_PRINTLN("PWRMGT: LPCOMP wake configured (AIN%d, ref=ARef)", ain_channel); } else if (refsel <= 6) { @@ -222,6 +237,8 @@ void NRF52Board::configureVoltageWake(uint8_t ain_channel, uint8_t refsel) { } MESH_DEBUG_PRINTLN("PWRMGT: VBUS wake configured"); + + return true; } #endif diff --git a/src/helpers/NRF52Board.h b/src/helpers/NRF52Board.h index dba15f97..089e1dad 100644 --- a/src/helpers/NRF52Board.h +++ b/src/helpers/NRF52Board.h @@ -40,7 +40,7 @@ protected: bool checkBootVoltage(const PowerMgtConfig* config); void enterSystemOff(uint8_t reason); - void configureVoltageWake(uint8_t ain_channel, uint8_t refsel); + bool configureVoltageWake(uint8_t ain_channel, uint8_t refsel); virtual void initiateShutdown(uint8_t reason); #endif diff --git a/variants/heltec_t114/T114Board.cpp b/variants/heltec_t114/T114Board.cpp index 51db72fc..8eeb90a2 100644 --- a/variants/heltec_t114/T114Board.cpp +++ b/variants/heltec_t114/T114Board.cpp @@ -25,7 +25,9 @@ void T114Board::initiateShutdown(uint8_t reason) { digitalWrite(PIN_BAT_CTL, enable_lpcomp ? HIGH : LOW); if (enable_lpcomp) { - configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel); + if (!configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel)) { + NVIC_SystemReset(); + } } enterSystemOff(reason); diff --git a/variants/rak4631/RAK4631Board.cpp b/variants/rak4631/RAK4631Board.cpp index 1b5698d0..21fcbce2 100644 --- a/variants/rak4631/RAK4631Board.cpp +++ b/variants/rak4631/RAK4631Board.cpp @@ -31,7 +31,9 @@ void RAK4631Board::initiateShutdown(uint8_t reason) { if (reason == SHUTDOWN_REASON_LOW_VOLTAGE || reason == SHUTDOWN_REASON_BOOT_PROTECT) { - configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel); + if (!configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel)) { + NVIC_SystemReset(); + } } enterSystemOff(reason); diff --git a/variants/xiao_nrf52/XiaoNrf52Board.cpp b/variants/xiao_nrf52/XiaoNrf52Board.cpp index 42ee6a87..85e02627 100644 --- a/variants/xiao_nrf52/XiaoNrf52Board.cpp +++ b/variants/xiao_nrf52/XiaoNrf52Board.cpp @@ -22,7 +22,9 @@ void XiaoNrf52Board::initiateShutdown(uint8_t reason) { digitalWrite(VBAT_ENABLE, enable_lpcomp ? LOW : HIGH); if (enable_lpcomp) { - configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel); + if (!configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel)) { + NVIC_SystemReset(); + } } enterSystemOff(reason);