mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-09-01 22:48:17 +00:00
Harden nRF52 shutdown and radio recovery
This commit is contained in:
@@ -16,6 +16,9 @@ The nRF52 Power Management module provides battery protection features to preven
|
||||
- Configures the nRF52's Low Power Comparator (LPCOMP) before entering SYSTEMOFF
|
||||
- Enables USB VBUS detection so external power can wake the device
|
||||
- Device automatically wakes when battery voltage rises above recovery threshold or when VBUS is detected
|
||||
- Uses no LPCOMP hysteresis; on divided battery inputs the additional 50 mV
|
||||
comparator hysteresis can move the effective battery wake point by several
|
||||
hundred millivolts and strand an otherwise charged node
|
||||
|
||||
### Early Boot Register Capture
|
||||
- Captures RESETREAS (reset reason) and GPREGRET2 (shutdown reason) before SystemInit() clears them
|
||||
@@ -34,31 +37,32 @@ Shutdown reason codes (stored in GPREGRET2):
|
||||
|
||||
## Supported Boards
|
||||
|
||||
|
||||
| Board | Implemented | LPCOMP wake | VBUS wake |
|
||||
|-------------------------------------------|-------------|-------------|-----------|
|
||||
| Seeed Studio XIAO nRF52840 (`xiao_nrf52`) | Yes | Yes | Yes |
|
||||
| RAK4631 (`rak4631`) | Yes | Yes | Yes |
|
||||
| Heltec T114 (`heltec_t114`) | Yes | Yes | Yes |
|
||||
| GAT562 Mesh Watch13 | Yes | Yes | Yes |
|
||||
| Promicro nRF52840 | No | No | No |
|
||||
| RAK WisMesh Tag | No | No | No |
|
||||
| Heltec Mesh Solar | No | No | No |
|
||||
| LilyGo T-Echo / T-Echo Lite | No | No | No |
|
||||
| SenseCAP Solar | Yes | Yes | Yes |
|
||||
| WIO Tracker L1 / L1 E-Ink | No | No | No |
|
||||
| WIO WM1110 | No | No | No |
|
||||
| Mesh Pocket | No | No | No |
|
||||
| Nano G2 Ultra | No | No | No |
|
||||
| ThinkNode M1/M3/M6 | No | No | No |
|
||||
| T1000-E | No | No | No |
|
||||
| Ikoka Nano/Stick/Handheld (nRF) | No | No | No |
|
||||
| Keepteen LT1 | No | No | No |
|
||||
| Minewsemi ME25LS01 | No | No | No |
|
||||
| Board family | Implemented | LPCOMP wake | VBUS wake |
|
||||
|---------------------------------------------------|-------------|-------------|-----------|
|
||||
| Seeed Studio XIAO nRF52840 (`xiao_nrf52`) | Yes | Yes | Yes |
|
||||
| SenseCAP Solar | Yes | Yes | Yes |
|
||||
| RAK4631 / RAK3401 | Yes | Yes | Yes |
|
||||
| GAT562 30S / EVB Pro / Tracker Pro / Watch13 | Yes | Yes | Yes |
|
||||
| Heltec T096 / T114 / T1 / Tower V2 | Yes | Yes | Yes |
|
||||
| Muzi Works R1 Neo | Partial | Inactive | Inactive |
|
||||
| Promicro nRF52840 | No | No | No |
|
||||
| RAK WisMesh Tag | No | No | No |
|
||||
| Heltec Mesh Solar | No | No | No |
|
||||
| LilyGo T-Echo / T-Echo Lite / T-Impulse Plus | No | No | No |
|
||||
| WIO Tracker L1 / L1 E-Ink / WM1110 | No | No | No |
|
||||
| Mesh Pocket / Meshtiny / Nano G2 Ultra | No | No | No |
|
||||
| ThinkNode M1 / M3 / M6 | No | No | No |
|
||||
| T1000-E | No | No | No |
|
||||
| Ikoka Nano / Stick / Handheld (nRF) | No | No | No |
|
||||
| Keepteen LT1 / Minewsemi ME25LS01 | No | No | No |
|
||||
|
||||
Notes:
|
||||
- "Implemented" reflects Phase 1 (boot lockout + shutdown reason capture).
|
||||
- User power-off on Heltec T114 does not enable LPCOMP wake.
|
||||
- R1 Neo has the integration compiled, but its board configuration deliberately
|
||||
sets `PWRMGT_VOLTAGE_BOOTLOCK` to `0`; automatic protective shutdown and its
|
||||
voltage/VBUS recovery wake are therefore inactive.
|
||||
- User power-off does not enable LPCOMP wake; voltage recovery is armed only
|
||||
for boot protection and automated low-voltage shutdown.
|
||||
- VBUS detection is used to skip boot lockout on external power, and VBUS wake is configured alongside LPCOMP when supported hardware exposes VBUS to the nRF52.
|
||||
|
||||
## Technical Details
|
||||
@@ -138,7 +142,7 @@ The LPCOMP (Low Power Comparator) is configured to:
|
||||
- Monitor the specified AIN channel (0-7 corresponding to P0.02-P0.05, P0.28-P0.31)
|
||||
- Compare against VDD fraction reference (REFSEL: 0-6=1/8..7/8, 7=ARef, 8-15=1/16..15/16)
|
||||
- Detect UP events (voltage rising above threshold)
|
||||
- Use 50mV hysteresis for noise immunity
|
||||
- Use no hysteresis so the configured recovery threshold is not widened by the battery divider
|
||||
- Wake the device from SYSTEMOFF when triggered
|
||||
|
||||
VBUS wake is enabled via the POWER peripheral USBDETECTED event whenever `configureVoltageWake()` is used. This requires USB VBUS to be routed to the nRF52 (typical on nRF52840 boards with native USB).
|
||||
|
||||
@@ -254,7 +254,16 @@ void setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!radio_init()) { halt(); }
|
||||
int radioinit_attempts = 0;
|
||||
while (!radio_init()) {
|
||||
++radioinit_attempts;
|
||||
MESH_DEBUG_PRINTLN("Radio init failed! (attempt %d)", radioinit_attempts);
|
||||
if (radioinit_attempts >= 3) {
|
||||
MESH_DEBUG_PRINTLN("Radio init failed 3x - rebooting");
|
||||
board.reboot();
|
||||
}
|
||||
delay(500);
|
||||
}
|
||||
|
||||
fast_rng.begin(radio_driver.getRngSeed());
|
||||
|
||||
|
||||
@@ -78,8 +78,15 @@ void onGetStats(uint32_t* rx, uint32_t* tx, uint32_t* errors) {
|
||||
void setup() {
|
||||
board.begin();
|
||||
|
||||
if (!radio_init()) {
|
||||
halt();
|
||||
int radioinit_attempts = 0;
|
||||
while (!radio_init()) {
|
||||
++radioinit_attempts;
|
||||
MESH_DEBUG_PRINTLN("Radio init failed! (attempt %d)", radioinit_attempts);
|
||||
if (radioinit_attempts >= 3) {
|
||||
MESH_DEBUG_PRINTLN("Radio init failed 3x - rebooting");
|
||||
board.reboot();
|
||||
}
|
||||
delay(500);
|
||||
}
|
||||
|
||||
radio_driver.begin();
|
||||
|
||||
@@ -80,9 +80,15 @@ void setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!radio_init()) {
|
||||
MESH_DEBUG_PRINTLN("Radio init failed!");
|
||||
halt();
|
||||
int radioinit_attempts = 0;
|
||||
while (!radio_init()) {
|
||||
++radioinit_attempts;
|
||||
MESH_DEBUG_PRINTLN("Radio init failed! (attempt %d)", radioinit_attempts);
|
||||
if (radioinit_attempts >= 3) {
|
||||
MESH_DEBUG_PRINTLN("Radio init failed 3x - rebooting");
|
||||
board.reboot();
|
||||
}
|
||||
delay(500);
|
||||
}
|
||||
|
||||
fast_rng.begin(radio_driver.getRngSeed());
|
||||
|
||||
@@ -48,7 +48,16 @@ void setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!radio_init()) { halt(); }
|
||||
int radioinit_attempts = 0;
|
||||
while (!radio_init()) {
|
||||
++radioinit_attempts;
|
||||
MESH_DEBUG_PRINTLN("Radio init failed! (attempt %d)", radioinit_attempts);
|
||||
if (radioinit_attempts >= 3) {
|
||||
MESH_DEBUG_PRINTLN("Radio init failed 3x - rebooting");
|
||||
board.reboot();
|
||||
}
|
||||
delay(500);
|
||||
}
|
||||
|
||||
fast_rng.begin(radio_driver.getRngSeed());
|
||||
|
||||
|
||||
@@ -568,7 +568,16 @@ void setup() {
|
||||
external_watchdog.begin();
|
||||
#endif
|
||||
|
||||
if (!radio_init()) { halt(); }
|
||||
int radioinit_attempts = 0;
|
||||
while (!radio_init()) {
|
||||
++radioinit_attempts;
|
||||
MESH_DEBUG_PRINTLN("Radio init failed! (attempt %d)", radioinit_attempts);
|
||||
if (radioinit_attempts >= 3) {
|
||||
MESH_DEBUG_PRINTLN("Radio init failed 3x - rebooting");
|
||||
board.reboot();
|
||||
}
|
||||
delay(500);
|
||||
}
|
||||
|
||||
fast_rng.begin(radio_driver.getRngSeed());
|
||||
|
||||
|
||||
@@ -70,7 +70,16 @@ void setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!radio_init()) { halt(); }
|
||||
int radioinit_attempts = 0;
|
||||
while (!radio_init()) {
|
||||
++radioinit_attempts;
|
||||
MESH_DEBUG_PRINTLN("Radio init failed! (attempt %d)", radioinit_attempts);
|
||||
if (radioinit_attempts >= 3) {
|
||||
MESH_DEBUG_PRINTLN("Radio init failed 3x - rebooting");
|
||||
board.reboot();
|
||||
}
|
||||
delay(500);
|
||||
}
|
||||
|
||||
fast_rng.begin(radio_driver.getRngSeed());
|
||||
|
||||
|
||||
@@ -467,6 +467,16 @@ void NRF52Board::shutdownPeripherals() {
|
||||
// Power off LoRa
|
||||
radio_driver.powerOff();
|
||||
|
||||
// RadioLib's IRQ setup can leave DIO1 as a GPIO wake source. Once the radio
|
||||
// is asleep that line may float or remain asserted, immediately waking an
|
||||
// nRF52 that is trying to enter SYSTEMOFF. Release the interrupt channel and
|
||||
// explicitly disable pin sensing; board-specific code can then arm only its
|
||||
// intended wake source (for example, the SenseCAP user button or LPCOMP).
|
||||
#ifdef P_LORA_DIO_1
|
||||
detachInterrupt(P_LORA_DIO_1);
|
||||
pinMode(P_LORA_DIO_1, INPUT);
|
||||
#endif
|
||||
|
||||
// Keep LoRa inactive during deepsleep
|
||||
#ifdef P_LORA_NSS
|
||||
digitalWrite(P_LORA_NSS, HIGH);
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
}
|
||||
uint8_t getSpreadingFactor() const override { return ((CustomSX1262 *)_radio)->spreadingFactor; }
|
||||
virtual void powerOff() override {
|
||||
((CustomSX1262 *)_radio)->standby();
|
||||
((CustomSX1262 *)_radio)->sleep(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ public:
|
||||
}
|
||||
|
||||
void begin() override;
|
||||
virtual void powerOff() { _radio->sleep(); }
|
||||
virtual void powerOff() { _radio->standby(); _radio->sleep(); }
|
||||
int recvRaw(uint8_t* bytes, int sz) override;
|
||||
uint32_t getEstAirtimeFor(int len_bytes) override;
|
||||
bool startSendRaw(const uint8_t* bytes, int len) override;
|
||||
|
||||
@@ -8,7 +8,7 @@ build_flags = ${rak4631_hw.build_flags}
|
||||
-I variants/gat562_30s_mesh_kit
|
||||
-D RAK_4631
|
||||
-D RAK_BOARD
|
||||
; -D NRF52_POWER_MANAGEMENT
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
-D PIN_BOARD_SCL=14
|
||||
-D PIN_BOARD_SDA=13
|
||||
-D PIN_OLED_RESET=-1
|
||||
|
||||
@@ -5,7 +5,7 @@ board_check = true
|
||||
build_flags = ${rak4631_hw.build_flags}
|
||||
${sensor_base.build_flags}
|
||||
-I variants/gat562_mesh_evb_pro
|
||||
; -D NRF52_POWER_MANAGEMENT
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
-D PIN_BOARD_SCL=14
|
||||
-D PIN_BOARD_SDA=13
|
||||
-D RADIO_CLASS=CustomSX1262
|
||||
|
||||
@@ -6,7 +6,7 @@ board_build.ldscript = boards/nrf52840_s140_v6.ld
|
||||
build_flags = ${rak4631_hw.build_flags}
|
||||
${sensor_base.build_flags}
|
||||
-I variants/gat562_mesh_tracker_pro
|
||||
; -D NRF52_POWER_MANAGEMENT
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
-D PIN_BOARD_SCL=14
|
||||
-D PIN_BOARD_SDA=13
|
||||
-D PIN_OLED_RESET=-1
|
||||
|
||||
@@ -8,7 +8,7 @@ build_flags = ${rak4631_hw.build_flags}
|
||||
-I variants/gat562_mesh_watch13
|
||||
-D RAK_4631
|
||||
-D RAK_BOARD
|
||||
; -D NRF52_POWER_MANAGEMENT
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
-D PIN_BOARD_SCL=14
|
||||
-D PIN_BOARD_SDA=13
|
||||
-D PIN_OLED_RESET=-1
|
||||
|
||||
@@ -14,7 +14,7 @@ build_flags = ${rak4631_hw.build_flags}
|
||||
-I variants/heltec_t096
|
||||
-I src/helpers/ui
|
||||
-D HELTEC_T096
|
||||
; -D NRF52_POWER_MANAGEMENT
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
-D P_LORA_DIO_1=21
|
||||
-D P_LORA_NSS=5
|
||||
-D P_LORA_RESET=16
|
||||
|
||||
@@ -13,7 +13,7 @@ build_flags = ${rak4631_hw.build_flags}
|
||||
-I variants/heltec_t114
|
||||
-I src/helpers/ui
|
||||
-D HELTEC_T114
|
||||
; -D NRF52_POWER_MANAGEMENT
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
-D P_LORA_DIO_1=20
|
||||
-D P_LORA_NSS=24
|
||||
-D P_LORA_RESET=25
|
||||
|
||||
@@ -7,7 +7,7 @@ build_flags = ${nrf52_base.build_flags}
|
||||
${sensor_base.build_flags}
|
||||
-I variants/rak3401
|
||||
-D RAK_3401
|
||||
; -D NRF52_POWER_MANAGEMENT
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
-D RADIO_CLASS=CustomSX1262
|
||||
-D WRAPPER_CLASS=CustomSX1262Wrapper
|
||||
-D LORA_TX_POWER=22
|
||||
|
||||
@@ -11,7 +11,7 @@ build_flags = ${nrf52_base.build_flags}
|
||||
-I variants/rak4631
|
||||
-D RAK_4631
|
||||
-D RAK_BOARD
|
||||
; -D NRF52_POWER_MANAGEMENT
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
-D MOTA_HW_ID='"RAK4631"' ; OTA hardware tag (apply refuses a .mota for different hw)
|
||||
-D PIN_BOARD_SCL=14
|
||||
-D PIN_BOARD_SDA=13
|
||||
|
||||
@@ -10,7 +10,7 @@ build_flags = ${nrf52_base.build_flags}
|
||||
-I src/helpers/nrf52
|
||||
-D NRF52_PLATFORM=1
|
||||
-D USE_SX1262
|
||||
; -D NRF52_POWER_MANAGEMENT
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
-D RADIO_CLASS=CustomSX1262
|
||||
-D WRAPPER_CLASS=CustomSX1262Wrapper
|
||||
-D P_LORA_TX_LED=12
|
||||
|
||||
@@ -9,7 +9,7 @@ build_flags = ${rak4631_hw.build_flags}
|
||||
-I variants/xiao_nrf52
|
||||
-UENV_INCLUDE_GPS
|
||||
-D NRF52_PLATFORM
|
||||
; -D NRF52_POWER_MANAGEMENT
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
-D XIAO_NRF52
|
||||
-D USE_SX1262
|
||||
-D RADIO_CLASS=CustomSX1262
|
||||
|
||||
Reference in New Issue
Block a user