Power
Battery life is about being asleep most of the time. core_power exposes the three low-power modes and the ways to wake from them — a timed RTC interval, a pin edge — plus backup registers that survive the deepest sleep. It sits on ll_pwr (there’s no HAL layer). Use the Core / HAL / LL toggle at the top of the sidebar to switch.
Overview
The modes trade wakeup latency and retained state against current draw. Picking one is mostly about what you need alive while asleep and how you’ll wake:
- Sleep — CPU halted, peripherals and clocks running. Wakes on any interrupt, ~instantly. The everyday idle.
- Stop — clocks halted, RAM retained. Wakes from EXTI or the RTC; the clock tree is rebuilt on wake.
- Standby — almost everything off; RAM is lost and wakeup is a full reset. Lowest draw.
Sleep, stop & standby
The Core calls bundle entry, wakeup configuration, and (for stop) clock recovery into one call. core_sleep returns on the next interrupt; core_stop_for wakes itself after N seconds, restores the clocks, and advances core_millis() by the time it slept:
#include "core.h"
core_sleep(); // idle until any interrupt
core_stop_for(30); // Stop for 30 s (RTC), then resume with clocks restored
if (core_standby_for(2) != HAL_OK) {
// refused: the watchdog is running and 2 s is more than half its timeout
} // on success: never returns, the Core resets on wakecore_stop_for sleeps in chunks of half the watchdog timeout and wakes briefly to feed it: any length is safe. Standby can’t be chunked, so with the watchdog running core_standby_for refuses anything longer than half the timeout (it returns HAL_ERROR without sleeping) and core_standby_until_on_change returns at once. Use core_stop_for for long sleeps. Core.ST.H5 still runs the older sleep code: no chunking and no Standby check, until its fix session.core_standby_* never returns — the MCU resets and RAM is lost. Detect it at the top of main() with core_woke_from_standby().Wakeup & the RTC
Beyond a timed interval, you can wake on a pin edge, and the RTC gives you a wall clock with periodic wakeups and a calendar alarm:
// Wake from Stop on a falling edge on pad 8, or after 10 s:
int why = core_stop_until_on_change_timeout(8, EDGE_FALLING, 10000);
// 1 = the pad (or it was already low), 0 = timed out, -1 = pad can't wake the Core
// No timeout: wait for the edge however long it takes
core_stop_until_on_change(8, EDGE_FALLING);
// RTC wall clock + alarm:
core_rtc_init();
core_rtc_set_time(12, 0, 0);
core_rtc_set_alarm(0xFF, 0xFF, 0); // 0xFF = wildcard → fire every minute at :00
if (core_rtc_alarm_fired()) { ... }A pin wake returns at once if the pad is already at its wake level (a sensor holding its interrupt line low until serviced would otherwise never wake the Core); EDGE_BOTH always waits for a change. On the H5 the timeout isn’t implemented yet: a non-zero one returns -1.
Check core_woke_from_standby() first thing in main() to branch on a Standby return, then core_clear_standby_flag() to acknowledge it.
Backup registers
Backup registers are 32-bit slots that survive reset and Standby (and power loss, with VBAT). Use them for crash counters, boot flags, or carrying state across a Standby cycle:
core_backup_write(0, 0x12345678);
uint32_t saved = core_backup_read(0); // persists across reset / StandbyCORE_BACKUP_COUNT is 32 on most Cores, 5 on the M0+ (Core.ST.L0).Cross-architecture support
Sleep is verified across the family. Stop passed a bench test of two back-to-back 10 s core_stop_for calls with a 5 s watchdog on the L4 and the W5 (25 September 2026). The L0’s sleep, RTC and backup code was rewritten against its reference manual the same day and awaits its bench pass. The H5 ran Stop and RTC wake-up before, but keeps the older sleep code until its fix session. Hover a chip for each feature:
See the implementation status for the full matrix.
Known gaps
What the SDK itself lists as missing here, straight from the headers:
core_standby_for / core_standby reset on wake — they never return on success and can't be safely exposed to the DSL, since the simulator would deadlock on a call that never returns. Recoverable variants (sleep, stop_for) are Tier 2; reaching Standby from a DSL program needs an "escape-to-C" fallthrough or a separate "would have entered Standby" event the simulator can model.
core_stop_until_on_change blocks until a configured pad edge wakes the chip. The DSL surface is straightforward in spirit but needs the EXTI handler bridge to express "block until" cleanly across the host-call boundary. Tracked alongside the broader DSL event- model story.
The register maps behind stop_for / standby_for / RTC / backup were corrected against RM0377 and RM0493 on 2026-09-25 (the L0 enabled the LSE instead of the LSI and hung; the WBA wrote CCIPR instead of BDCR1, had no RTC bus clock and a reserved Standby LPMS). The W5's Stop passed tests/hw-sleep-cycle on 2026-09-25; its Standby and all of the L0 are compile-only until they do. Core.ST.L4 passed the same test; Core.ST.H5 keeps its older sleep code until its own fix session.
The IWDG keeps counting in Standby (always on the L0, by option byte on the L4/WBA) and nothing feeds it until main() runs again, so with the watchdog on (the Studio default, 5 s) core_standby_for refuses anything longer than half the timeout and returns HAL_ERROR, and core_standby_until_on_change returns without sleeping. Long sleeps use core_stop_for, which wakes to feed. Changing the IWDG_STDBY option byte would lift this on the L4/WBA; the SDK doesn't touch option bytes.
core_standby_until_on_change is implemented for STM32L422 only — Core.ST.L4.2's PA0/PA2 WKUP pins. Other Cores hit the (void) fallback and return without entering Standby.
The SDK roadmap flags LPTIM as Tier 1 high-impact: it runs in Stop without the RTC and gives finer wakeup granularity than seconds. Not wrapped here yet.
The WBA's Stop2 autonomous mode (ADC / SPI / I2C / UART operating while the CPU sleeps) is on the roadmap as Tier 3 — none of it is surfaced through core_power yet.
The C surface has core_rtc_get_time / get_date taking out-pointers; they're not exposed because the host-call ABI doesn't map cleanly to multi-out values. The newer multi-scalar-out ABI (see DSL Capability Coverage close, 2026-05-03) could land them.
core_rtc_init always selects LSI (~32 kHz RC, ±5% typical drift on the L4/WBA; the L0's is 26-56 kHz part to part and is not calibrated against HSI16, so its RTC second can be off by tens of percent). Cores with an LSE crystal need ll_rtc_init(1) — no Tier 2 wrapper that takes a clock-source argument.
The wrapper exposes whole-second resolution. STM32 RTCs have a subsecond register (1/PREDIV_S) that's reachable from ll_rtc but not from this header — wall-clock timestamps round to the second.
read/write round-trip within a single run, but the per-slot store is cleared on every project reload — DSL programs that rely on backup state surviving a soft reset (e.g., boot counters across the user clicking Reset in the IDE) can't be exercised end-to-end.
The TAMP block on WBA/H5 hosts the backup registers but also drives tamper detection (active edge, anti-tamper erase, time-stamping on tamper). None of that is wrapped — backup is read/write only.
From the @studio unsupported notes in core_power.h, core_rtc.h, core_backup.h — tiles@6af026f.
API reference
Power modes
void core_sleep(void);void core_stop_for(uint32_t seconds);int core_woke_from_standby(void);void core_clock_init(void);int core_stop_until_on_change_timeout(uint8_t pad, uint32_t edge, uint32_t timeout_ms);void core_stop_until_on_change(uint8_t pad, uint32_t edge);hal_status_t core_standby_for(uint32_t seconds);void core_standby_until_on_change(uint8_t pad, uint32_t edge);void core_stop(void);void core_standby(void);void core_clear_standby_flag(void);void core_watchdog_start_seconds(uint32_t seconds);Generated from core_power.h — tiles@f70bca2.
RTC
void core_rtc_init(void);void core_rtc_set_time(uint8_t h, uint8_t m, uint8_t s);void core_rtc_set_date(uint8_t y, uint8_t mo, uint8_t d, uint8_t wd);void core_rtc_wakeup(uint32_t seconds);void core_rtc_wakeup_stop(void);void core_rtc_set_alarm(uint8_t hours, uint8_t minutes, uint8_t seconds);void core_rtc_clear_alarm(void);int core_rtc_alarm_fired(void);void core_rtc_get_time(uint8_t * h, uint8_t * m, uint8_t * s);void core_rtc_get_date(uint8_t * y, uint8_t * mo, uint8_t * d, uint8_t * wd);Generated from core_rtc.h — tiles@8f1266b.
Backup registers
uint32_t core_backup_read(uint8_t index);void core_backup_write(uint8_t index, uint32_t value);void _core_backup_ensure_clk(void);Generated from core_backup.h — tiles@4b95d38.

