mirror of https://github.com/meshcore-dev/MeshCore
committed by
GitHub
17 changed files with 667 additions and 24 deletions
@ -0,0 +1,213 @@ |
|||||
|
# nRF52 Power Management |
||||
|
|
||||
|
## Overview |
||||
|
|
||||
|
The nRF52 Power Management module provides battery protection features to prevent over-discharge, minimise likelihood of brownout and flash corruption conditions existing, and enable safe voltage-based recovery. |
||||
|
|
||||
|
## Features |
||||
|
|
||||
|
### Boot Voltage Protection |
||||
|
- Checks battery voltage immediately after boot and before mesh operations commence |
||||
|
- If voltage is below a configurable threshold (e.g., 3300mV), the device configures voltage wake (LPCOMP + VBUS) and enters protective shutdown (SYSTEMOFF) |
||||
|
- Prevents boot loops when battery is critically low |
||||
|
- Skipped when external power (USB VBUS) is detected |
||||
|
|
||||
|
### Voltage Wake (LPCOMP + VBUS) |
||||
|
- 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 |
||||
|
|
||||
|
### Early Boot Register Capture |
||||
|
- Captures RESETREAS (reset reason) and GPREGRET2 (shutdown reason) before SystemInit() clears them |
||||
|
- Allows firmware to determine why it booted (cold boot, watchdog, LPCOMP wake, etc.) |
||||
|
- Allows firmware to determine why it last shut down (user request, low voltage, boot protection) |
||||
|
|
||||
|
### Shutdown Reason Tracking |
||||
|
Shutdown reason codes (stored in GPREGRET2): |
||||
|
| Code | Name | Description | |
||||
|
|------|------|-------------| |
||||
|
| 0x00 | NONE | Normal boot / no previous shutdown | |
||||
|
| 0x4C | LOW_VOLTAGE | Runtime low voltage threshold reached | |
||||
|
| 0x55 | USER | User requested powerOff() | |
||||
|
| 0x42 | BOOT_PROTECT | Boot voltage protection triggered | |
||||
|
|
||||
|
## 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 | |
||||
|
| 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 | No | No | No | |
||||
|
| 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 | |
||||
|
|
||||
|
Notes: |
||||
|
- "Implemented" reflects Phase 1 (boot lockout + shutdown reason capture). |
||||
|
- User power-off on Heltec T114 does not enable LPCOMP wake. |
||||
|
- 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 |
||||
|
|
||||
|
### Architecture |
||||
|
|
||||
|
The power management functionality is integrated into the `NRF52Board` base class in `src/helpers/NRF52Board.cpp`. Board variants provide hardware-specific configuration via a `PowerMgtConfig` struct and override `initiateShutdown(uint8_t reason)` to perform board-specific power-down work and conditionally enable voltage wake (LPCOMP + VBUS). |
||||
|
|
||||
|
### Early Boot Capture |
||||
|
|
||||
|
A static constructor with priority 101 in `NRF52Board.cpp` captures the RESETREAS and GPREGRET2 registers before: |
||||
|
- SystemInit() (priority 102) - which clears RESETREAS |
||||
|
- Static C++ constructors (default priority 65535) |
||||
|
|
||||
|
This ensures we capture the true reset reason before any initialisation code runs. |
||||
|
|
||||
|
### Board Implementation |
||||
|
|
||||
|
To enable power management on a board variant: |
||||
|
|
||||
|
1. **Enable in platformio.ini**: |
||||
|
```ini |
||||
|
-D NRF52_POWER_MANAGEMENT |
||||
|
``` |
||||
|
|
||||
|
2. **Define configuration in variant.h**: |
||||
|
```c |
||||
|
#define PWRMGT_VOLTAGE_BOOTLOCK 3300 // Won't boot below this voltage (mV) |
||||
|
#define PWRMGT_LPCOMP_AIN 7 // AIN channel for voltage sensing |
||||
|
#define PWRMGT_LPCOMP_REFSEL 2 // REFSEL (0-6=1/8..7/8, 7=ARef, 8-15=1/16..15/16) |
||||
|
``` |
||||
|
|
||||
|
3. **Implement in board .cpp file**: |
||||
|
```cpp |
||||
|
#ifdef NRF52_POWER_MANAGEMENT |
||||
|
const PowerMgtConfig power_config = { |
||||
|
.lpcomp_ain_channel = PWRMGT_LPCOMP_AIN, |
||||
|
.lpcomp_refsel = PWRMGT_LPCOMP_REFSEL, |
||||
|
.voltage_bootlock = PWRMGT_VOLTAGE_BOOTLOCK |
||||
|
}; |
||||
|
|
||||
|
void MyBoard::initiateShutdown(uint8_t reason) { |
||||
|
// Board-specific shutdown preparation (e.g., disable peripherals) |
||||
|
bool enable_lpcomp = (reason == SHUTDOWN_REASON_LOW_VOLTAGE || |
||||
|
reason == SHUTDOWN_REASON_BOOT_PROTECT); |
||||
|
|
||||
|
if (enable_lpcomp) { |
||||
|
configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel); |
||||
|
} |
||||
|
|
||||
|
enterSystemOff(reason); |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
void MyBoard::begin() { |
||||
|
NRF52Board::begin(); // or NRF52BoardDCDC::begin() |
||||
|
// ... board setup ... |
||||
|
|
||||
|
#ifdef NRF52_POWER_MANAGEMENT |
||||
|
checkBootVoltage(&power_config); |
||||
|
#endif |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
For user-initiated shutdowns, `powerOff()` remains board-specific. Power management only arms LPCOMP for automated shutdown reasons (boot protection/low voltage). |
||||
|
|
||||
|
4. **Declare override in board .h file**: |
||||
|
```cpp |
||||
|
#ifdef NRF52_POWER_MANAGEMENT |
||||
|
void initiateShutdown(uint8_t reason) override; |
||||
|
#endif |
||||
|
``` |
||||
|
|
||||
|
### Voltage Wake Configuration |
||||
|
|
||||
|
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 |
||||
|
- 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). |
||||
|
|
||||
|
**LPCOMP Reference Selection (PWRMGT_LPCOMP_REFSEL)**: |
||||
|
| REFSEL | Fraction | VBAT @ 1M/1M divider (VDD=3.0-3.3) | VBAT @ 1.5M/1M divider (VDD=3.0-3.3) | |
||||
|
|--------|----------|------------------------------------|--------------------------------------| |
||||
|
| 0 | 1/8 | 0.75-0.82 V | 0.94-1.03 V | |
||||
|
| 1 | 2/8 | 1.50-1.65 V | 1.88-2.06 V | |
||||
|
| 2 | 3/8 | 2.25-2.47 V | 2.81-3.09 V | |
||||
|
| 3 | 4/8 | 3.00-3.30 V | 3.75-4.12 V | |
||||
|
| 4 | 5/8 | 3.75-4.12 V | 4.69-5.16 V | |
||||
|
| 5 | 6/8 | 4.50-4.95 V | 5.62-6.19 V | |
||||
|
| 6 | 7/8 | 5.25-5.77 V | 6.56-7.22 V | |
||||
|
| 7 | ARef | - | - | |
||||
|
| 8 | 1/16 | 0.38-0.41 V | 0.47-0.52 V | |
||||
|
| 9 | 3/16 | 1.12-1.24 V | 1.41-1.55 V | |
||||
|
| 10 | 5/16 | 1.88-2.06 V | 2.34-2.58 V | |
||||
|
| 11 | 7/16 | 2.62-2.89 V | 3.28-3.61 V | |
||||
|
| 12 | 9/16 | 3.38-3.71 V | 4.22-4.64 V | |
||||
|
| 13 | 11/16 | 4.12-4.54 V | 5.16-5.67 V | |
||||
|
| 14 | 13/16 | 4.88-5.36 V | 6.09-6.70 V | |
||||
|
| 15 | 15/16 | 5.62-6.19 V | 7.03-7.73 V | |
||||
|
|
||||
|
**Important**: For boards with a voltage divider on the battery sense pin, LPCOMP measures the divided voltage. Use: |
||||
|
`VBAT_threshold ≈ (VDD * fraction) * divider_scale`, where `divider_scale = (Rtop + Rbottom) / Rbottom` (e.g., 2.0 for 1M/1M, 2.5 for 1.5M/1M, 3.0 for XIAO). |
||||
|
|
||||
|
### SoftDevice Compatibility |
||||
|
|
||||
|
The power management code checks whether SoftDevice is enabled and uses the appropriate API: |
||||
|
- When SD enabled: `sd_power_*` functions |
||||
|
- When SD disabled: Direct register access (NRF_POWER->*) |
||||
|
|
||||
|
This ensures compatibility regardless of BLE stack state. |
||||
|
|
||||
|
## CLI Commands |
||||
|
|
||||
|
Power management status can be queried via the CLI: |
||||
|
|
||||
|
| Command | Description | |
||||
|
|---------|-------------| |
||||
|
| `get pwrmgt.support` | Returns "supported" or "unsupported" | |
||||
|
| `get pwrmgt.source` | Returns current power source - "battery" or "external" (5V/USB power) | |
||||
|
| `get pwrmgt.bootreason` | Returns reset and shutdown reason strings | |
||||
|
| `get pwrmgt.bootmv` | Returns boot voltage in millivolts | |
||||
|
|
||||
|
On boards without power management enabled, all commands except `get pwrmgt.support` return: |
||||
|
``` |
||||
|
ERROR: Power management not supported |
||||
|
``` |
||||
|
|
||||
|
## Debug Output |
||||
|
|
||||
|
When `MESH_DEBUG=1` is enabled, the power management module outputs: |
||||
|
``` |
||||
|
DEBUG: PWRMGT: Reset = Wake from LPCOMP (0x20000); Shutdown = Low Voltage (0x4C) |
||||
|
DEBUG: PWRMGT: Boot voltage = 3450 mV (threshold = 3300 mV) |
||||
|
DEBUG: PWRMGT: LPCOMP wake configured (AIN7, ref=3/8 VDD) |
||||
|
``` |
||||
|
|
||||
|
## Phase 2 (Planned) |
||||
|
|
||||
|
- Runtime voltage monitoring |
||||
|
- Voltage state machine (Normal -> Warning -> Critical -> Shutdown) |
||||
|
- Configurable thresholds |
||||
|
- Load shedding callbacks for power reduction |
||||
|
- Deep sleep integration |
||||
|
- Scheduled wake-up |
||||
|
- Extended sleep with periodic monitoring |
||||
|
|
||||
|
## References |
||||
|
|
||||
|
- [nRF52840 Product Specification - POWER](https://infocenter.nordicsemi.com/topic/ps_nrf52840/power.html) |
||||
|
- [nRF52840 Product Specification - LPCOMP](https://infocenter.nordicsemi.com/topic/ps_nrf52840/lpcomp.html) |
||||
|
- [SoftDevice S140 API - Power Management](https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/group__nrf__sdm__api.html) |
||||
Loading…
Reference in new issue