Skip to content

Power/RTC: let the PowerHub STM32 arm the alarm before powering off - #369

Merged
lovyan03 merged 1 commit into
m5stack:developfrom
ainyan03:powerhub_alarm_wait
Sep 18, 2026
Merged

lovyan03 merged 1 commit into
m5stack:developfrom
ainyan03:powerhub_alarm_wait

Conversation

@ainyan03

Copy link
Copy Markdown
Contributor

Summary

On PowerHub, Power::timerSleep(time) powered the board off before the STM32 front-end had armed the RTC alarm, so the board never woke up and only the power button brought it back.

The STM32 acknowledges alarm register writes (D0..D3) immediately but applies them to the RX8130 from its main loop (about 13 ms per iteration), behind a single "update pending" flag that it clears after each apply. A power-off request (0xE0) that follows the alarm-enable write without a gap can overtake that step, and an update that lands while an older one is being applied can be dropped with the flag. Measured with timerSleep(time): 0 of 6 wake-ups without a gap, 6 of 6 with a 500 ms gap.

Changes

  • RTC_PowerHub_Class: the alarm is handed over as one D0..D3 block write (values and enable in a single STM32 callback) after the wake-source check, and every alarm-register write (initial disable retries, block write, rollback, disableIRQ) goes through one helper that pauses 50 ms afterwards regardless of the result, so the main loop consumes each update before the next one can race with the pending flag.
  • Power_Class: when an alarm was armed, wait 500 ms before the power-off request; after the request is accepted, stay off the I2C bus and wait up to 3 s for the power to drop instead of entering a light sleep with no wake source. If the call still returns, the request cannot be withdrawn, so timerSleep() leaves the alarm armed instead of clearing it (a late power-off would otherwise sleep with no wake source). Documented on powerOff() and both date/time timerSleep() overloads.

Behaviour

  • timerSleep(time) / timerSleep(date, time) on PowerHub spend about 0.75 s before the power-off request (paced alarm writes, then the 0.5 s settle) and up to 3 s waiting for the power to drop.
  • powerOff() on PowerHub returns after about 3 s if the board is still running; the board may still power off later.
  • Rtc.setAlarmIRQ() / disableIRQ() on PowerHub block about 100-200 ms.

Verification

PowerHub (STM32 firmware 0xF3), timerSleep(now + 1 min) from a test firmware, wake-up = board reboots on the alarm:

Build Wake-ups
develop 0 / 6
500 ms settle only 6 / 6
block write + settle 3 / 3
this PR 6 / 6

Builds: ESP32-S3 Arduino, no new warnings. Three rounds of independent adversarial review until no implementation finding remained. CI run on the ainyan03 fork before this PR.

The PowerHub STM32 acknowledges the alarm register writes immediately but
applies them to the RX8130 from its main loop (about 13 ms per iteration),
behind a single "update pending" flag that it clears after each apply. A
power-off request that arrives right after the alarm-enable write can
overtake that step, and an update that lands while an older one is being
applied can be dropped with the flag; either way the board powers off with
no alarm armed and only the power button brings it back. Measured with
timerSleep(time) on firmware 0xF3: 0 of 6 wake-ups with no gap, 6 of 6 with
a 500 ms gap.

- RTC_PowerHub: hand the alarm over as one D0..D3 block write (values and
  enable in a single STM32 callback) after the wake-source check, and route
  every alarm-register write (disable retries, block write, rollback,
  disableIRQ) through one helper that pauses 50 ms afterwards regardless of
  the result, so the main loop consumes each update before the next one.
- Power: wait 500 ms before the power-off request when an alarm was armed,
  then stay off the I2C bus and wait up to 3 s for the power to drop instead
  of entering a light sleep with no wake source. The request cannot be
  withdrawn, so if the call still returns, timerSleep() leaves the alarm
  armed rather than clearing it. Documented on powerOff() and both
  date/time timerSleep() overloads.

Verified on a PowerHub: 6 of 6 wake-ups through timerSleep(time).
@lovyan03
lovyan03 merged commit 639000a into m5stack:develop Sep 18, 2026
28 checks passed
@ainyan03
ainyan03 deleted the powerhub_alarm_wait branch September 18, 2026 01:19
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