Skip to content

suspend-to-off: Standby heartbeat sleep window (A/B candidate 2)#94

Draft
evgeny-boger wants to merge 2 commits into
feature/ec-suspend-modefrom
feature/ec-suspend-standby
Draft

suspend-to-off: Standby heartbeat sleep window (A/B candidate 2)#94
evgeny-boger wants to merge 2 commits into
feature/ec-suspend-modefrom
feature/ec-suspend-standby

Conversation

@evgeny-boger

Copy link
Copy Markdown
Member

A/B candidate 2 of 2 for the suspend-window low-power mode (competes with the Stop 1 variant; bench A/B = gate G2). Stacked on #92.

Reuses the proven poweroff machinery: STM32 Standby with a 5 s heartbeat — every wake is a reset that re-feeds the IWDG (the ec0bef4 10 s IWDG death is structurally impossible), deadline remainder persisted in TAMP BKP2R, cause-decoded resume in wbec_init shared with poweroff classification. No 5 V pull hack needed: the WB8.5.3 schematic (U14 EN: R38 470k pull-up to +5V/1) holds the module 5 V through reset/high-Z by hardware.

Wins vs Stop: ~3× smaller production diff (+281/−16, 6 files), no new execution regime (no ISRs/EXTI/clock-restore pipeline), late-SoC-abort recovery in ≤5 s (vs full-window). Tests: 427 PASS both models incl. the ec0bef4 root-cause regression (sleep interval never exceeds the heartbeat).

Known gap (on-battery suspend): wbmz_init() drives the WBMZ step-up EN (PB15) low on every heartbeat reboot — on battery this kills the 5 V rail and DRAM. Options under discussion: (a) marker-aware glitch-free takeover in wbmz_init, (b) refuse Standby-window when on WBMZ (busy-poll fallback, ~6 lines), (c) respin: module-side RC on EN mirroring the U14 pattern. Until resolved this variant is safe on external Vin only.

The structural trade vs Stop: every heartbeat re-runs the boot path over live DRAM — "boot path must stay DRAM-safe" becomes a permanent invariant (this PB15 gap is exactly that tax, found by inspection).

🤖 Generated with Claude Code

evgeny-boger and others added 2 commits July 8, 2026 14:52
…the window

Replace the 64 MHz busy-poll sleep window with the same STM32 Standby the
poweroff path uses, sharing its boot-time wake classification. Differences
from poweroff, and the fixes for the failed ec0bef4 Standby experiment:

- 5V stays ON through the window with NO pull on the 5V-enable pin: per the
  WB 8.5.3 schematic the module 5V switch (U14 SY6280) is held ON by the
  external R38 470k pull-up whenever the pin is high-Z, and C32 2.2uF
  (tau ~1 s) bridges the short wake-reset windows. The ec0bef4 internal
  pull-up hack and the early 5V hold in main() are unnecessary and dropped.
  Heater (U17 EN, 22k pull-down) and V_OUT (Q2 NPN-BRT base) are hardware-off
  on high-Z pins, so no forced-safe-output code is needed either.

- The RTC WUT wakes the EC every WBEC_SUSPEND_STANDBY_HEARTBEAT_S (5 s), NOT
  after the full requested sleep: every wake is a reset, watchdog_init()
  restarts the IWDG on boot, so the sleep window never exceeds the 10 s IWDG
  period. This removes the exact ec0bef4 root cause (unfed IWDG reset at 10 s
  misread as a resume, wake sequence fired into a mid-sleep PMIC, DRAM lost).

- The deadline remainder lives in a TAMP backup register (BKP2R) and is
  decremented on each heartbeat. The suspend marker (BKP1R) is consumed
  unconditionally on every boot, so a marker that survived a power loss via
  VBAT cannot be misread as a resume later.

- wbec_init routes the wake: heartbeat -> advance the deadline and re-enter
  Standby, resume with REASON_WATCHDOG when the deadline is exhausted, or
  resume immediately when 3.3V is back (late SoC suspend abort, recovered
  within one heartbeat); button -> the same debounce-or-sleep flow as
  poweroff; alarm -> resume with REASON_RTC_ALARM; unexpected reset with the
  marker set -> resume (safe action). Resume takes the 5V pin back
  glitch-free, suppresses the power-on beep (a beep on resume corrupts the
  DRAM re-init) and arms the PWROK-pulse wake sequence.

- A wake (alarm/button) that fires in the short window before Standby entry
  still resumes in place, preserving the same-core exit-arm semantics the
  2ac7e28 regression tests guard.

- If the system runs from WBMZ at entry, the step-up enable pin is held high
  through Standby by an internal pull-up (needs bench confirmation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
wbec suite (stubbed linux-power-control / mcu-pwr): wbec_init wake routing for
the suspend-to-off Standby window - alarm resume (REASON_RTC_ALARM, WUT
disabled, no cold-boot init), heartbeat re-entry (remainder advanced, marker
re-armed, no resume), deadline resume (REASON_WATCHDOG), late SoC abort (3.3V
back mid-window resumes immediately), button debounce-or-sleep (confirmed
press resumes with REASON_POWER_KEY, a brush re-enters Standby with the
remainder untouched), unexpected reset with the marker set resumes as the
safe action, and the ec0bef4 root-cause regression: the sleep interval never
exceeds the heartbeat (IWDG 10 s envelope), even with a huge remainder.

wbec-integration suite (real wbec + linux-power-control): the window entry
contract - Standby requested with a nonzero interval bounded by the
heartbeat, resume marker armed with the padded deadline remainder. The four
pre-existing 2ac7e28 suspend regressions pass unchanged: a wake that fires
before Standby entry still resumes in place with the same exit-arm
semantics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@evgeny-boger

Copy link
Copy Markdown
Member Author

Decision: the Stop 1 variant (#93) proceeds to bench first. This branch stays as the documented A/B alternative; the PB15/WBMZ gap (options a/b/c in the description) remains open if it's ever revisited.

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.

1 participant