Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions docs/nrf52_power_management.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Shutdown reason codes (stored in GPREGRET2):
|-------------------------------------------|-------------|-------------|-----------|
| Seeed Studio XIAO nRF52840 (`xiao_nrf52`) | Yes | Yes | Yes |
| RAK4631 (`rak4631`) | Yes | Yes | Yes |
| RAK3401 (`rak3401`) | Yes | Yes | Yes |
| Heltec T114 (`heltec_t114`) | Yes | Yes | Yes |
| GAT562 Mesh Watch13 | Yes | Yes | Yes |
| Promicro nRF52840 | No | No | No |
Expand Down Expand Up @@ -167,6 +168,32 @@ VBUS wake is enabled via the POWER peripheral USBDETECTED event whenever `config
**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).

### Build-Flag Overrides (RAK4631, RAK3401)

On the `rak4631` and `rak3401` variants the battery sense and power management defines are `#ifndef`-guarded, so a PlatformIO environment can move battery sensing to another analog pin with build flags instead of editing the variant:

| Define | Default | Meaning |
|---------------------------|--------------------------------|------------------------------------------------------------------------------------|
| `PIN_VBAT_READ` | `5` (P0.05 / AIN3) | Pin read by `getBattMilliVolts()`; the default is the WisBlock base board divider |
| `ADC_MULTIPLIER` | `(3 * 1.73 * 1.187 * 1000)` | Reported millivolts at ADC full scale (3.6 V); `3600` reports the pin voltage as is |
| `PWRMGT_VOLTAGE_BOOTLOCK` | `3300` | Boot lock threshold in reported millivolts; `0` disables boot protection |
| `PWRMGT_LPCOMP_AIN` | `3` | LPCOMP wake channel; must be the AIN channel of `PIN_VBAT_READ` |
| `PWRMGT_LPCOMP_REFSEL` | `4` | LPCOMP wake threshold (see the table above) |

When moving `PIN_VBAT_READ`, move `PWRMGT_LPCOMP_AIN` with it: `configureVoltageWake()` selects the comparator input from `PWRMGT_LPCOMP_AIN`, so a stale value leaves LPCOMP watching the old pin.

Example: `RAK_3401_repeater_voltaic` in `variants/rak3401/platformio.ini` reads a Voltaic V25/V50/V75 battery pack, which reports its charge on the USB-C SBU pins as 1/2 of its cell voltage, wired to the RAK19007 J11 header pin 1 (AIN1 = P0.31 = AIN7):

```ini
-D PIN_VBAT_READ=31 ; P0.31 = AIN7 = RAK19007 J11 pin 1
-D ADC_MULTIPLIER=7200 ; SBU = 1/2 cell voltage -> report cell mV
-D PWRMGT_VOLTAGE_BOOTLOCK=3400 ; boot lock below 3.4 V cell
-D PWRMGT_LPCOMP_AIN=7 ; wake comparator on the SBU input
-D PWRMGT_LPCOMP_REFSEL=12 ; 9/16 VDD ≈ 1.86 V at the pin ≈ 3.7 V cell
```

Because the SBU pin is a 1/2-scale source, the 1M/1M column of the reference table applies to it: REFSEL 12 wakes the node once the pack recovers to about 3.7 V cell.

### SoftDevice Compatibility

The power management code checks whether SoftDevice is enabled and uses the appropriate API:
Expand Down
15 changes: 13 additions & 2 deletions variants/rak3401/RAK3401Board.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,19 @@
#include <helpers/NRF52Board.h>

// built-ins
#define PIN_VBAT_READ 5
#define ADC_MULTIPLIER (3 * 1.73 * 1.187 * 1000)
// Battery sense defaults to the WisBlock base board divider (VBAT -> 1M/1.5M -> AIN0/P0.05).
// Both defines can be overridden from build flags to read an externally supplied battery
// voltage on another analog pin, e.g. the USB-C SBU pin of a Voltaic V25/V50/V75 pack
// (1/2 of its cell voltage) wired to the base board J11 AIN1 pin:
// -D PIN_VBAT_READ=31 -D ADC_MULTIPLIER=7200
// ADC_MULTIPLIER is the reported millivolts at ADC full scale (3.6V): 3600 reports the
// pin voltage as-is, 7200 doubles it (for 1/2-scale sources like the V25 SBU pin).
#ifndef PIN_VBAT_READ
#define PIN_VBAT_READ 5
#endif
#ifndef ADC_MULTIPLIER
#define ADC_MULTIPLIER (3 * 1.73 * 1.187 * 1000)
#endif

#define PIN_3V3_EN (34)
#define WB_IO2 PIN_3V3_EN
Expand Down
18 changes: 18 additions & 0 deletions variants/rak3401/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ build_src_filter = ${rak3401.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_repeater>

; Repeater powered by a USB PD battery pack that reports its charge level on the USB-C
; SBU pins as 1/2 cell voltage (e.g. Voltaic V25/V50/V75 with Always-On firmware).
; Wire the pack's SBU pin to J11 pin 1 (AIN1/P0.31) on the RAK19007; the node then
; reports the pack's true cell voltage (~3.2V empty to ~4.2V full) as its battery.
; Power management stays enabled but is rerouted to the SBU input: below 3.4V pack cell
; voltage (PWRMGT_VOLTAGE_BOOTLOCK) the node sleeps in SYSTEMOFF instead of boot-flapping
; on a drained pack, and LPCOMP wakes it once the pack recharges past ~3.7V cell.
; See docs/nrf52_power_management.md.
[env:RAK_3401_repeater_voltaic]
extends = env:RAK_3401_repeater
build_flags =
${env:RAK_3401_repeater.build_flags}
-D PIN_VBAT_READ=31 ; P0.31 = WisBlock AIN1 = RAK19007 J11 pin 1
-D ADC_MULTIPLIER=7200 ; SBU = 1/2 cell voltage -> report full cell mV
-D PWRMGT_VOLTAGE_BOOTLOCK=3400 ; sleep below 3.4V pack cell (variant.h default is 3300)
-D PWRMGT_LPCOMP_AIN=7 ; LPCOMP watches AIN7 = P0.31 (the SBU input), not AIN0's divider
-D PWRMGT_LPCOMP_REFSEL=12 ; wake at 9/16 VDD = ~1.86V at pin = ~3.7V pack cell

[env:RAK_3401_room_server]
extends = rak3401
build_flags =
Expand Down
31 changes: 17 additions & 14 deletions variants/rak3401/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,25 @@ extern "C"

// Power management boot protection threshold (millivolts)
// Set to 0 to disable boot protection
#define PWRMGT_VOLTAGE_BOOTLOCK 3300 // Won't boot below this voltage (mV)
#ifndef PWRMGT_VOLTAGE_BOOTLOCK
#define PWRMGT_VOLTAGE_BOOTLOCK 3300 // Won't boot below this voltage (mV)
#endif
// LPCOMP wake configuration (voltage recovery from SYSTEMOFF)
// AIN3 = P0.05 = PIN_A0 / PIN_VBAT_READ
#define PWRMGT_LPCOMP_AIN 3
#define PWRMGT_LPCOMP_REFSEL 4 // 5/8 VDD (~3.13-3.44V)
#ifndef PWRMGT_LPCOMP_AIN
#define PWRMGT_LPCOMP_AIN 3
#endif
// PWRMGT_LPCOMP_REFSEL sets the LPCOMP wake threshold as a fraction of VDD (3.3V rail).
// Valid values are the nRF52840 LPCOMP REFSEL register codes (see the nRF52840 Product
// Specification, LPCOMP chapter, and NRF52Board::configureVoltageWake):
// 0-6 = 1/8, 2/8, ... 7/8 of VDD
// 7 = external reference on the AREF pin
// 8-15 = 1/16, 3/16, 5/16, ... 15/16 of VDD
// Default 4 = 5/8 VDD = ~2.06V at the pin; through the base board's 1M/1.5M battery
// divider (0.6 ratio) that is VBAT ~3.44V (~3.13V if the VDD rail is at 3.0V).
#ifndef PWRMGT_LPCOMP_REFSEL
#define PWRMGT_LPCOMP_REFSEL 4
#endif

// Other pins
#define WB_I2C1_SDA (13) // SENSOR_SLOT IO_SLOT
Expand Down Expand Up @@ -195,17 +209,6 @@ static const uint8_t AREF = PIN_AREF;
#define GPS_BAUD_RATE 9600
#define GPS_ADDRESS 0x42 //i2c address for GPS

// Battery
// The battery sense is hooked to pin A0 (5)
#define BATTERY_PIN PIN_A0
// and has 12 bit resolution
#define BATTERY_SENSE_RESOLUTION_BITS 12
#define BATTERY_SENSE_RESOLUTION 4096.0
#undef AREF_VOLTAGE
#define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER 1.73

#define HAS_RTC 1

#define RAK_4631 1
Expand Down
8 changes: 6 additions & 2 deletions variants/rak4631/RAK4631Board.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
#include <helpers/NRF52Board.h>

// built-ins
#define PIN_VBAT_READ 5
#define ADC_MULTIPLIER (3 * 1.73 * 1.187 * 1000)
#ifndef PIN_VBAT_READ
#define PIN_VBAT_READ 5
#endif
#ifndef ADC_MULTIPLIER
#define ADC_MULTIPLIER (3 * 1.73 * 1.187 * 1000)
#endif

class RAK4631Board : public NRF52BoardDCDC {
protected:
Expand Down
20 changes: 17 additions & 3 deletions variants/rak4631/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,25 @@ extern "C"

// Power management boot protection threshold (millivolts)
// Set to 0 to disable boot protection
#define PWRMGT_VOLTAGE_BOOTLOCK 3300 // Won't boot below this voltage (mV)
#ifndef PWRMGT_VOLTAGE_BOOTLOCK
#define PWRMGT_VOLTAGE_BOOTLOCK 3300 // Won't boot below this voltage (mV)
#endif
// LPCOMP wake configuration (voltage recovery from SYSTEMOFF)
// AIN3 = P0.05 = PIN_A0 / PIN_VBAT_READ
#define PWRMGT_LPCOMP_AIN 3
#define PWRMGT_LPCOMP_REFSEL 4 // 5/8 VDD (~3.13-3.44V)
#ifndef PWRMGT_LPCOMP_AIN
#define PWRMGT_LPCOMP_AIN 3
#endif
// PWRMGT_LPCOMP_REFSEL sets the LPCOMP wake threshold as a fraction of VDD (3.3V rail).
// Valid values are the nRF52840 LPCOMP REFSEL register codes (see the nRF52840 Product
// Specification, LPCOMP chapter, and NRF52Board::configureVoltageWake):
// 0-6 = 1/8, 2/8, ... 7/8 of VDD
// 7 = external reference on the AREF pin
// 8-15 = 1/16, 3/16, 5/16, ... 15/16 of VDD
// Default 4 = 5/8 VDD = ~2.06V at the pin; through the base board's 1M/1.5M battery
// divider (0.6 ratio) that is VBAT ~3.44V (~3.13V if the VDD rail is at 3.0V).
#ifndef PWRMGT_LPCOMP_REFSEL
#define PWRMGT_LPCOMP_REFSEL 4
#endif

// Other pins
#define PIN_AREF (2)
Expand Down