From d908a3e954fdfd5575fa103b10f818eb116fbf46 Mon Sep 17 00:00:00 2001 From: Mattias Fornander Date: Tue, 1 Sep 2026 14:15:54 -0600 Subject: [PATCH 1/2] Allow overriding battery sense on RAK4631/RAK3401 for external packs Wrap PIN_VBAT_READ / ADC_MULTIPLIER and the PWRMGT_* defines in #ifndef guards so build flags can redirect battery telemetry to another analog pin, e.g. a Voltaic V25/V50/V75 pack's USB-C SBU output (1/2 cell voltage) wired to the base board J11 AIN1 pin. Remove the unused Meshtastic-leftover battery defines from the rak3401 variant.h: nothing in the MeshCore, framework, or library compile closure references them, and the unconditional ADC_MULTIPLIER there would defeat both the new #ifndef default and any -D build flag (variant.h is included via Arduino.h before the board headers). Add a documented RAK_3401_repeater_voltaic example env that reports the pack's true cell voltage and keeps nRF52 power management active with LPCOMP wake rerouted to the SBU pin: sleep below 3.4V cell, wake once the pack recharges past ~3.7V. The rak4631 hunks are byte-identical to PR #3328 by @andyshinn, which this change incorporates and extends. Co-Authored-By: Claude Fable 5 --- variants/rak3401/RAK3401Board.h | 15 +++++++++++++-- variants/rak3401/platformio.ini | 18 ++++++++++++++++++ variants/rak3401/variant.h | 31 +++++++++++++++++-------------- variants/rak4631/RAK4631Board.h | 8 ++++++-- variants/rak4631/variant.h | 20 +++++++++++++++++--- 5 files changed, 71 insertions(+), 21 deletions(-) diff --git a/variants/rak3401/RAK3401Board.h b/variants/rak3401/RAK3401Board.h index 3a080d5e2c..ff19549af4 100644 --- a/variants/rak3401/RAK3401Board.h +++ b/variants/rak3401/RAK3401Board.h @@ -5,8 +5,19 @@ #include // 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 diff --git a/variants/rak3401/platformio.ini b/variants/rak3401/platformio.ini index c285e3ec50..a286ccca6c 100644 --- a/variants/rak3401/platformio.ini +++ b/variants/rak3401/platformio.ini @@ -41,6 +41,24 @@ build_src_filter = ${rak3401.build_src_filter} + +<../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 = diff --git a/variants/rak3401/variant.h b/variants/rak3401/variant.h index e0c24759b8..887f0de5fc 100644 --- a/variants/rak3401/variant.h +++ b/variants/rak3401/variant.h @@ -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 @@ -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 diff --git a/variants/rak4631/RAK4631Board.h b/variants/rak4631/RAK4631Board.h index 7e67165b19..fb13c21bea 100644 --- a/variants/rak4631/RAK4631Board.h +++ b/variants/rak4631/RAK4631Board.h @@ -5,8 +5,12 @@ #include // 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: diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h index 38cc88685c..0e2011ad0a 100644 --- a/variants/rak4631/variant.h +++ b/variants/rak4631/variant.h @@ -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) From 26586df28395ea974104e6f94130778981b4d670 Mon Sep 17 00:00:00 2001 From: Mattias Fornander Date: Tue, 29 Sep 2026 00:12:26 -0600 Subject: [PATCH 2/2] docs: document RAK3401 power management and build-flag overrides Add the RAK3401 to the supported boards table and document the #ifndef-guarded battery sense and power management defines on rak4631/rak3401, with the Voltaic SBU env as a worked example. --- docs/nrf52_power_management.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/nrf52_power_management.md b/docs/nrf52_power_management.md index 417ee6dd63..8996968bf4 100644 --- a/docs/nrf52_power_management.md +++ b/docs/nrf52_power_management.md @@ -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 | @@ -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: