Add RAK WisMesh Repeater Mini V2 and HP variants (#10918)

* fix(esp32): skip RTC timer wake on user shutdown

Do not arm esp_sleep_enable_timer_wakeup when msecToWake is portMAX_DELAY (UI shutdown), matching nRF52 system_off semantics.

fix(rak_wismesh_tap_v2): Tag OCV curve and 16MB partition

Add OCV_ARRAY matching WisMesh Tag for accurate SOC. Use 16MB flash partition scheme for TAP V2 hardware.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Trunkt

* Add RAK WisMesh Repeater Mini V2 and HP variants
Introduce rak_wismesh_repeater_mini (RAK4631) and
rak_wismesh_repeater_mini_hp (RAK3401) with low-VDD System OFF.
Skip LPCOMP battery wake on user-initiated shutdown to avoid
immediate reboot near the LPCOMP threshold; keep LPCOMP for
brownout-driven shutdown via variant_enableBatteryLpcompWake.

* docs(variants): update RAK BOM numbers for Repeater Mini V2 & HP

* chore: run trunk fmt

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
Ethac.chen
2026-07-15 06:27:04 -05:00
committed by GitHub
co-authored by Cursor Ben Meadors
parent 952c825167
commit 834357e94c
6 changed files with 151 additions and 12 deletions
+24 -12
View File
@@ -58,6 +58,15 @@ void variant_shutdown() {}
void variant_nrf52LoopHook(void) __attribute__((weak)); void variant_nrf52LoopHook(void) __attribute__((weak));
void variant_nrf52LoopHook(void) {} void variant_nrf52LoopHook(void) {}
// Return false to skip LPCOMP wake when entering System OFF (e.g. user CLI shutdown).
// noinline: weak default and call site are in this file; without it GCC may inline the
// weak body and never link the strong override from variant.cpp.
__attribute__((noinline)) bool variant_enableBatteryLpcompWake() __attribute__((weak));
__attribute__((noinline)) bool variant_enableBatteryLpcompWake()
{
return true;
}
static nrfx_wdt_t nrfx_wdt = NRFX_WDT_INSTANCE(0); static nrfx_wdt_t nrfx_wdt = NRFX_WDT_INSTANCE(0);
static nrfx_wdt_channel_id nrfx_wdt_channel_id_nrf52_main; static nrfx_wdt_channel_id nrfx_wdt_channel_id_nrf52_main;
@@ -496,20 +505,23 @@ void cpuDeepSleep(uint32_t msecToWake)
// https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled // https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled
#ifdef BATTERY_LPCOMP_INPUT #ifdef BATTERY_LPCOMP_INPUT
// Wake up if power rises again // Only enable LPCOMP wake if the variant allows it
nrf_lpcomp_config_t c; if (variant_enableBatteryLpcompWake()) {
c.reference = BATTERY_LPCOMP_THRESHOLD; // Wake up if power rises again
c.detection = NRF_LPCOMP_DETECT_UP; nrf_lpcomp_config_t c;
c.hyst = NRF_LPCOMP_HYST_NOHYST; c.reference = BATTERY_LPCOMP_THRESHOLD;
nrf_lpcomp_configure(NRF_LPCOMP, &c); c.detection = NRF_LPCOMP_DETECT_UP;
nrf_lpcomp_input_select(NRF_LPCOMP, BATTERY_LPCOMP_INPUT); c.hyst = NRF_LPCOMP_HYST_NOHYST;
nrf_lpcomp_enable(NRF_LPCOMP); nrf_lpcomp_configure(NRF_LPCOMP, &c);
nrf_lpcomp_input_select(NRF_LPCOMP, BATTERY_LPCOMP_INPUT);
nrf_lpcomp_enable(NRF_LPCOMP);
battery_adcEnable(); battery_adcEnable();
nrf_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_START); nrf_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_START);
while (!nrf_lpcomp_event_check(NRF_LPCOMP, NRF_LPCOMP_EVENT_READY)) while (!nrf_lpcomp_event_check(NRF_LPCOMP, NRF_LPCOMP_EVENT_READY))
; ;
}
#endif #endif
auto ok = sd_power_system_off(); auto ok = sd_power_system_off();
@@ -36,6 +36,19 @@ lib_deps =
# renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main # renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main
https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip
; RAK10729 WisMesh Repeater Mini V2 HP (RAK3401 + RAK19007 + RAK13302 + solar battery)
[env:rak_wismesh_repeater_mini_hp]
extends = env:rak3401-1watt
custom_meshtastic_display_name = RAK WisMesh Repeater Mini V2 HP
custom_meshtastic_images = rak3401.svg
build_flags =
${env:rak3401-1watt.build_flags}
-D WISMESH_REPEATER_MINI_HP
-DMESHTASTIC_EXCLUDE_GPS=1
-DLOW_VDD_SYSTEMOFF_DELAY_MS=5000
-DSAFE_VDD_VOLTAGE_THRESHOLD_MV=2900
-DSAFE_VDD_VOLTAGE_THRESHOLD_HYST_MV=100
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds ; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds
;upload_protocol = jlink ;upload_protocol = jlink
@@ -23,6 +23,13 @@
#include "wiring_constants.h" #include "wiring_constants.h"
#include "wiring_digital.h" #include "wiring_digital.h"
#ifdef LOW_VDD_SYSTEMOFF_DELAY_MS
#include "Arduino.h"
#include "FreeRTOS.h"
#include "power/PowerHAL.h"
#include "sleep.h"
#endif
const uint32_t g_ADigitalPinMap[] = { const uint32_t g_ADigitalPinMap[] = {
// P0 // P0
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
@@ -40,3 +47,39 @@ void initVariant()
pinMode(PIN_3V3_EN, OUTPUT); pinMode(PIN_3V3_EN, OUTPUT);
digitalWrite(PIN_3V3_EN, HIGH); digitalWrite(PIN_3V3_EN, HIGH);
} }
#ifdef LOW_VDD_SYSTEMOFF_DELAY_MS
void variant_nrf52LoopHook(void)
{
// If VDD stays unsafe for a while (brownout), force System OFF.
// Skip when VBUS present to allow recovery while USB-powered.
if (!powerHAL_isVBUSConnected()) {
// Rate-limit VDD safety checks: powerHAL_isPowerLevelSafe() calls getVDDVoltage() each time.
static constexpr uint32_t POWER_LEVEL_CHECK_INTERVAL_MS = 100;
static uint32_t last_vdd_check_ms = 0;
static bool last_power_level_safe = true;
const uint32_t now = millis();
if (last_vdd_check_ms == 0 || (uint32_t)(now - last_vdd_check_ms) >= POWER_LEVEL_CHECK_INTERVAL_MS) {
last_vdd_check_ms = now;
last_power_level_safe = powerHAL_isPowerLevelSafe();
}
// Do not use millis()==0 as a sentinel: at boot, millis() may be 0 while VDD is unsafe.
static bool low_vdd_timer_armed = false;
static uint32_t low_vdd_since_ms = 0;
if (!last_power_level_safe) {
if (!low_vdd_timer_armed) {
low_vdd_since_ms = now;
low_vdd_timer_armed = true;
}
if ((uint32_t)(now - low_vdd_since_ms) >= (uint32_t)LOW_VDD_SYSTEMOFF_DELAY_MS) {
cpuDeepSleep(portMAX_DELAY);
}
} else {
low_vdd_timer_armed = false;
}
}
}
#endif
@@ -209,6 +209,13 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define AREF_VOLTAGE 3.0 #define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 #define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER 1.73 #define ADC_MULTIPLIER 1.73
#if defined(LOW_VDD_SYSTEMOFF_DELAY_MS)
#if !defined(OCV_ARRAY)
#define OCV_ARRAY 4160, 4020, 3940, 3870, 3810, 3760, 3740, 3720, 3680, 3620, 2990
#endif
#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_3
#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_5_8 // VDD=3.3V AIN3=5/8*VDD=2.06V VBAT=1.66*AIN3=3.41V
#endif
#define RAK_4631 1 #define RAK_4631 1
+12
View File
@@ -44,6 +44,18 @@ lib_deps =
# renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main # renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main
https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip
; RAK10728 WisMesh Repeater Mini V2 (RAK4631 + RAK19003 + solar battery + GPS module)
[env:rak_wismesh_repeater_mini]
extends = env:rak4631
custom_meshtastic_display_name = RAK WisMesh Repeater Mini V2
custom_meshtastic_images = rak4631.svg
build_flags =
${env:rak4631.build_flags}
-D WISMESH_REPEATER_MINI
-DLOW_VDD_SYSTEMOFF_DELAY_MS=5000
-DSAFE_VDD_VOLTAGE_THRESHOLD_MV=2900
-DSAFE_VDD_VOLTAGE_THRESHOLD_HYST_MV=100
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds ; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds
;upload_protocol = jlink ;upload_protocol = jlink
+52
View File
@@ -23,6 +23,13 @@
#include "wiring_constants.h" #include "wiring_constants.h"
#include "wiring_digital.h" #include "wiring_digital.h"
#ifdef LOW_VDD_SYSTEMOFF_DELAY_MS
#include "Arduino.h"
#include "FreeRTOS.h"
#include "power/PowerHAL.h"
#include "sleep.h"
#endif
const uint32_t g_ADigitalPinMap[] = { const uint32_t g_ADigitalPinMap[] = {
// P0 // P0
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
@@ -40,3 +47,48 @@ void initVariant()
pinMode(PIN_3V3_EN, OUTPUT); pinMode(PIN_3V3_EN, OUTPUT);
digitalWrite(PIN_3V3_EN, HIGH); digitalWrite(PIN_3V3_EN, HIGH);
} }
#ifdef LOW_VDD_SYSTEMOFF_DELAY_MS
static bool lowVddSystemOff = false; // Set to true when VDD is unsafe for a while (brownout), forcing System OFF.
// Strong override; must be noinline (see main-nrf52.cpp weak default).
__attribute__((noinline)) bool variant_enableBatteryLpcompWake()
{
return lowVddSystemOff;
}
// Hook called each nrf52Loop(); e.g. for low-VDD System OFF.
void variant_nrf52LoopHook(void)
{
// If VDD stays unsafe for a while (brownout), force System OFF.
// Skip when VBUS present to allow recovery while USB-powered.
if (!powerHAL_isVBUSConnected()) {
// Rate-limit VDD safety checks: powerHAL_isPowerLevelSafe() calls getVDDVoltage() each time.
static constexpr uint32_t POWER_LEVEL_CHECK_INTERVAL_MS = 100;
static uint32_t last_vdd_check_ms = 0;
static bool last_power_level_safe = true;
const uint32_t now = millis();
if (last_vdd_check_ms == 0 || (uint32_t)(now - last_vdd_check_ms) >= POWER_LEVEL_CHECK_INTERVAL_MS) {
last_vdd_check_ms = now;
last_power_level_safe = powerHAL_isPowerLevelSafe();
}
// Do not use millis()==0 as a sentinel: at boot, millis() may be 0 while VDD is unsafe.
static bool low_vdd_timer_armed = false;
static uint32_t low_vdd_since_ms = 0;
if (!last_power_level_safe) {
if (!low_vdd_timer_armed) {
low_vdd_since_ms = now;
low_vdd_timer_armed = true;
}
if ((uint32_t)(now - low_vdd_since_ms) >= (uint32_t)LOW_VDD_SYSTEMOFF_DELAY_MS) {
lowVddSystemOff = true;
cpuDeepSleep(portMAX_DELAY);
}
} else {
low_vdd_timer_armed = false;
}
}
}
#endif