Skip to content

RAK3401: powerOff() override + AIN button LPCOMP wake from SYSTEMOFF#2642

Open
disq wants to merge 2 commits into
meshcore-dev:devfrom
disq:rak3401-ain1-wake
Open

RAK3401: powerOff() override + AIN button LPCOMP wake from SYSTEMOFF#2642
disq wants to merge 2 commits into
meshcore-dev:devfrom
disq:rak3401-ain1-wake

Conversation

@disq

@disq disq commented May 28, 2026

Copy link
Copy Markdown
Contributor

Two board-level pieces from @dorfman2's #2414 that are useful for any RAK3401 firmware, not just the repeater variant that PR targets.

What this changes

  1. RAK3401Board::powerOff() override (variants/rak3401/RAK3401Board.h) — routes _board->powerOff() through initiateShutdown(SHUTDOWN_REASON_USER) so the shutdown reason is properly tagged in GPREGRET2 instead of falling through to the base class default.

  2. AIN button wake-from-SYSTEMOFF via LPCOMP (variants/rak3401/RAK3401Board.cpp) — when an env defines PIN_USER_BTN_ANA, arm a wake source before entering SYSTEMOFF so pressing the button powers the board back on.

  3. NRF52Board::configureVoltageWake() gains a detect_down flag (src/helpers/NRF52Board.{h,cpp}) — defaults to false (the existing upward-crossing voltage-recovery behavior, so no other NRF52 board is affected), and true selects a downward crossing for the button wake.

Why LPCOMP and not GPIO SENSE

#2414's original code armed the pin with SENSE_Low. That works for the repeater, where the button is a digital normally-open switch to GND. It does not work on the companion_radio build, where the same pin (PIN_USER_BTN_ANA=31, P0.31 = AIN7) is wired as an analog button — MomentaryButton reads it as analogRead() < threshold.

Two failures, both reproduced and verified on hardware (companion_radio_ble, on USB and battery):

  • Shutdown hung. The release-wait used digitalRead() on this pin, but the SAADC leaves the digital input buffer disconnected, so digitalRead() always returns LOW. The loop never exited, SYSTEMOFF was never reached — screen off, but BLE/serial still alive.
  • Immediate self-wake. Even past that, GPIO SENSE_Low reads this line as LOW at the released idle level (analogRead reports ~VDD while NRF_GPIO->IN reads 0 and the SENSE latch re-asserts the instant it's cleared), so the chip woke the moment it entered SYSTEMOFF. RESETREAS = Wake from GPIO (0x10000), identical on USB and battery — ruling out VBUS.

The fix arms LPCOMP instead. It operates in the analog domain, so it sees the idle level correctly: a DOWN crossing at ~½ VDD wakes on a press (released idles near VDD = above threshold; a press pulls the pin to ~0V = below). The release-wait now uses analogRead and is bounded by a 5s timeout so a stuck reading can never wedge shutdown. LPCOMP is otherwise unused for a USER shutdown (voltage wake is only armed for the low-voltage / boot-protect reasons), so there is no conflict. The AIN channel and threshold are overridable build defines.

Testing

Verified on RAK3401 + RAK19007 + companion_radio_ble build, on both USB and battery:

  • _board->powerOff() from the companion UI menu enters SYSTEMOFF and the board stays off (USB/serial drop, BLE LED dark).
  • Pressing the AIN button wakes the board; RESETREAS = Wake from LPCOMP and the subsequent boot is normal.
  • RAK_3401_repeater (no PIN_USER_BTN_ANA) and RAK_3401_companion_radio_ble both build clean; the configureVoltageWake() signature change is backward-compatible via the defaulted parameter.

@disq disq changed the title RAK3401: powerOff() override + AIN1 SENSE LOW wake from SYSTEMOFF RAK3401: powerOff() override + AIN1 SENSE LOW wake from SYSTEMOFF 🤖🤖 May 28, 2026
@dorfman2

Copy link
Copy Markdown

Ah @disq I see what you meant now. I was too focused on the UI portion of the code. Would love to see this implemented!

@disq

disq commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

The other PR wakes immediately and I put it to draft while I investigate, so I need to test this again first.
Now tested successfully.

@disq disq changed the title RAK3401: powerOff() override + AIN1 SENSE LOW wake from SYSTEMOFF 🤖🤖 RAK3401: powerOff() override + AIN button LPCOMP wake from SYSTEMOFF Jun 1, 2026
@disq disq changed the title RAK3401: powerOff() override + AIN button LPCOMP wake from SYSTEMOFF RAK3401: powerOff() override + AIN button LPCOMP wake from SYSTEMOFF 🤖🤖 Jun 1, 2026
@disq

disq commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

@dorfman2 It wasn't working for me on the companion so had to burn more tokens and do the "right thing".

disq added a commit to disq/MeshCore that referenced this pull request Jun 1, 2026
Brings meshcore-dev#2642's RAK3401 board pieces into this branch so the AIN1 button story is
self-contained, using LPCOMP (not GPIO SENSE) as the hibernate wake source.

AIN1 (P0.31) is wired as an analog button (pressed == analogRead() < threshold).
GPIO SENSE can't wake on it: the digital input buffer reads the *released* idle
level as LOW even though analogRead reports ~VDD, so arming SENSE_Low latches DETECT
the instant we enter SYSTEMOFF — sd_power_system_off() returns immediately and the
fall-through reset reboots ("instant wake"). LATCH/EVENTS_PORT clearing and release
debounce don't help, because the released level itself reads LOW digitally.

LPCOMP operates in the analog domain and sees the idle level correctly. Arm a DOWN
crossing at ~1/2 VDD: released idles above threshold, a press pulls the pin below ->
downward crossing -> wake. Wait for a confirmed release (analogRead above threshold)
before arming, bounded by a 5s timeout so a stuck/low reading can't wedge shutdown.

- NRF52Board::configureVoltageWake() gains a detect_down param (default false = UP
  crossing for voltage recovery; true = DOWN crossing for a button press), selecting
  ANADETECT Down/Up and INTENSET DOWN/UP accordingly.
- RAK3401Board.h: powerOff() override routing through initiateShutdown(USER).
- RAK3401Board::initiateShutdown() arms LPCOMP on AIN7 at REFSEL 3 (~1/2 VDD) for a
  USER shutdown when PIN_USER_BTN_ANA is defined. Channel/threshold overridable via
  PWRMGT_BTN_LPCOMP_AIN / PWRMGT_BTN_LPCOMP_REFSEL.

Ports the fix from meshcore-dev#2642. Built: RAK_3401_companion_radio_ble.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@disq

disq commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

This is also relevant, I've been testing both (plus the GPS fix) together #2662

disq added a commit to disq/MeshCore that referenced this pull request Jun 16, 2026
disq added a commit to disq/MeshCore that referenced this pull request Jun 16, 2026
disq and others added 2 commits June 20, 2026 21:59
Two board-level pieces from dorfman2's PR that are useful for any
RAK3401 firmware, not just the repeater variant the PR targets:

1. RAK3401Board::powerOff() override — routes _board->powerOff() through
   initiateShutdown(SHUTDOWN_REASON_USER) so the shutdown reason is
   properly tagged in GPREGRET2 instead of falling through to the base
   class default.

2. AIN1 GPIO SENSE LOW config in initiateShutdown() — when an env defines
   PIN_USER_BTN_ANA, configure that pin with pull-up + SENSE LOW before
   entering SYSTEMOFF, so pressing the AIN1 button wakes the board from
   the off state via the GPIO LATCH/SENSE mechanism. Waits for button
   release first (level-triggered SENSE would otherwise wake immediately
   if the user is still holding the button when we arm it).

Co-Authored-By: dorfman2 <noreply@github.com>
The SYSTEMOFF wake was hardwired to PIN_USER_BTN_ANA, so removing that
define (e.g. to share the AIN pin with an INT line) silently dropped the
wake. Add an explicit PIN_WAKEUP_ANA override that falls back to
PIN_USER_BTN_ANA, deriving the AIN channel from the pin (P0.31 = AIN7).
Default behavior is unchanged.
@disq disq force-pushed the rak3401-ain1-wake branch from 4d2cd5d to 2d71c30 Compare June 20, 2026 21:00
@disq disq changed the title RAK3401: powerOff() override + AIN button LPCOMP wake from SYSTEMOFF 🤖🤖 RAK3401: powerOff() override + AIN button LPCOMP wake from SYSTEMOFF Jun 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants