nRF52 Power Management

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

Voltage Wake (LPCOMP + VBUS)

Early Boot Register Capture

Shutdown Reason Tracking

Shutdown reason codes (stored in GPREGRET2):

CodeNameDescription
0x00NONENormal boot / no previous shutdown
0x4CLOW_VOLTAGERuntime low voltage threshold reached
0x55USERUser requested powerOff()
0x42BOOT_PROTECTBoot voltage protection triggered

Supported Boards

BoardImplementedLPCOMP wakeVBUS wake
Seeed Studio XIAO nRF52840 (xiao_nrf52)YesYesYes
RAK4631 (rak4631)YesYesYes
Heltec T114 (heltec_t114)YesYesYes
Promicro nRF52840NoNoNo
RAK WisMesh TagNoNoNo
Heltec Mesh SolarNoNoNo
LilyGo T-Echo / T-Echo LiteNoNoNo
SenseCAP SolarYesYesYes
WIO Tracker L1 / L1 E-InkNoNoNo
WIO WM1110NoNoNo
Mesh PocketNoNoNo
Nano G2 UltraNoNoNo
ThinkNode M1/M3/M6NoNoNo
T1000-ENoNoNo
Ikoka Nano/Stick/Handheld (nRF)NoNoNo
Keepteen LT1NoNoNo
Minewsemi ME25LS01NoNoNo

Notes:

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:

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

```

  1. 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)

```

  1. 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).

  1. 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:

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):

REFSELFractionVBAT @ 1M/1M divider (VDD=3.0-3.3)VBAT @ 1.5M/1M divider (VDD=3.0-3.3)
01/80.75-0.82 V0.94-1.03 V
12/81.50-1.65 V1.88-2.06 V
23/82.25-2.47 V2.81-3.09 V
34/83.00-3.30 V3.75-4.12 V
45/83.75-4.12 V4.69-5.16 V
56/84.50-4.95 V5.62-6.19 V
67/85.25-5.77 V6.56-7.22 V
7ARef--
81/160.38-0.41 V0.47-0.52 V
93/161.12-1.24 V1.41-1.55 V
105/161.88-2.06 V2.34-2.58 V
117/162.62-2.89 V3.28-3.61 V
129/163.38-3.71 V4.22-4.64 V
1311/164.12-4.54 V5.16-5.67 V
1413/164.88-5.36 V6.09-6.70 V
1515/165.62-6.19 V7.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:

This ensures compatibility regardless of BLE stack state.

CLI Commands

Power management status can be queried via the CLI:

CommandDescription
get pwrmgt.supportReturns "supported" or "unsupported"
get pwrmgt.sourceReturns current power source - "battery" or "external" (5V/USB power)
get pwrmgt.bootreasonReturns reset and shutdown reason strings
get pwrmgt.bootmvReturns 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)

References


Revision #3
Created 2026-05-03 05:05:11 UTC by Mesh America Admin
Updated 2026-06-09 14:27:37 UTC by Mesh America Admin