RAK3401: powerOff() override + AIN button LPCOMP wake from SYSTEMOFF 🤖🤖#2642
Open
disq wants to merge 2 commits into
Open
RAK3401: powerOff() override + AIN button LPCOMP wake from SYSTEMOFF 🤖🤖#2642disq wants to merge 2 commits into
disq wants to merge 2 commits into
Conversation
Two board-level pieces from dorfman2's PR meshcore-dev#2414 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). The repeater-specific UI redesign, status screen, and simple_repeater main.cpp button handler from the same PR are out of scope here; the companion radio UI tree already has its own equivalent button handling in examples/companion_radio/ui-new/UITask.cpp. Co-Authored-By: dorfman2 <noreply@github.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
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! |
Author
|
|
…tton The AIN user button on the companion_radio build is an *analog* button (MomentaryButton reads it as analogRead() < threshold), not a digital switch. GPIO SENSE cannot wake from this pin: the digital input buffer reads the line as LOW even at the released idle level — verified on hardware, analogRead reports ~VDD while NRF_GPIO->IN reads 0 and the SENSE_Low condition latches immediately (LATCH bit re-asserts right after being cleared). So a GPIO SENSE_Low arm wakes the chip the instant it enters SYSTEMOFF and it can never stay off. This reproduced identically on USB and battery (RESETREAS = Wake from GPIO, 0x10000), ruling out VBUS. This also fixes an earlier hang: the original release-wait used digitalRead() on this pin, which always returns LOW (SAADC leaves the digital buffer disconnected), so shutdown never reached SYSTEMOFF — screen off, BLE/serial still alive. Fix: arm LPCOMP instead. It works in the analog domain, so it sees the idle level correctly. Configure a DOWN crossing at ~1/2 VDD (released idles near VDD = above, a press pulls to ~0V = below -> wake). 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. - NRF52Board::configureVoltageWake() gains a detect_down flag (default false = existing upward voltage-recovery behavior, backward compatible) to also support downward-crossing wake. - RAK3401 initiateShutdown() waits for release via analogRead (bounded by a 5s timeout so a stuck reading can never wedge shutdown), then arms LPCOMP on AIN7. AIN channel / threshold are overridable build defines. Verified on hardware: device reaches SYSTEMOFF and stays off; a button press wakes it (RESETREAS = Wake from LPCOMP). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
RAK3401Board::powerOff()override (variants/rak3401/RAK3401Board.h) — routes_board->powerOff()throughinitiateShutdown(SHUTDOWN_REASON_USER)so the shutdown reason is properly tagged inGPREGRET2instead of falling through to the base class default.AIN button wake-from-SYSTEMOFF via LPCOMP (
variants/rak3401/RAK3401Board.cpp) — when an env definesPIN_USER_BTN_ANA, arm a wake source before entering SYSTEMOFF so pressing the button powers the board back on.NRF52Board::configureVoltageWake()gains adetect_downflag (src/helpers/NRF52Board.{h,cpp}) — defaults tofalse(the existing upward-crossing voltage-recovery behavior, so no other NRF52 board is affected), andtrueselects 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 —MomentaryButtonreads it asanalogRead() < threshold.Two failures, both reproduced and verified on hardware (companion_radio_ble, on USB and battery):
digitalRead()on this pin, but the SAADC leaves the digital input buffer disconnected, sodigitalRead()always returns LOW. The loop never exited, SYSTEMOFF was never reached — screen off, but BLE/serial still alive.SENSE_Lowreads this line as LOW at the released idle level (analogReadreports ~VDD whileNRF_GPIO->INreads 0 and theSENSElatch 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
analogReadand 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.What this does NOT include
The repeater-specific UI redesign, status screen, and
simple_repeater/main.cppbutton handler from #2414 are out of scope here — the companion_radio UI tree already has its own button handling inexamples/companion_radio/ui-new/UITask.cpp. This PR cleanly lifts only the universally-beneficial board-level pieces; #2414 can land independently with the repeater UI work on top.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).RESETREAS = Wake from LPCOMPand the subsequent boot is normal.RAK_3401_repeater(noPIN_USER_BTN_ANA) andRAK_3401_companion_radio_bleboth build clean; theconfigureVoltageWake()signature change is backward-compatible via the defaulted parameter.🤖 Generated with Claude Code