All guides
TECHNICAL GUIDESTM32L4R5LOW POWER2026

Low-Power Modes
& Wakeup

Run, Sleep, Stop 0/1/2, Standby and Shutdown on the STM32L4R5 (Cortex-M4F, RM0432): the PWR CR1–CR4 / SR / SCR registers, the SLEEPDEEP + WFI/WFE mechanism, RAM retention, wakeup sources and a complete RTC periodic-wakeup example.

01 Why go low-power: the mode ladder

The STM32L4R5 is an ultra-low-power Cortex-M4F running up to 120 MHz. Its value is the ability to trade activity for current across a ladder of modes, from full Run down to a few tens of nanoamps in Shutdown. Each rung switches off more clocks, more of the voltage regulator, and eventually most of the RAM — so choosing a mode is really choosing what must survive and what may wake you.

The seven states, deepest wins

RunCPU + all clocks live. Main regulator, voltage scaling Range 1 (up to 120 MHz) or Range 2 (up to 26 MHz).
Low-power runSYSCLK ≤ 2 MHz on the low-power regulator (LPR). CPU still executes; ideal for slow polling loops.
Sleep / Low-power sleepCPU clock gated (WFI/WFE); every peripheral keeps its clock. Wake on any enabled interrupt in a few cycles.
Stop 0 / 1 / 2All clocks stopped (HSI16/HSE/PLL off); SRAM and all registers retained. Stop 0 keeps the main regulator (fastest wake), Stop 1/2 use the LPR (lowest current). Wake via EXTI, RTC, LPTIM, LPUART, etc.
StandbyRegulators off, kernel powered down. Only the backup domain (RTC + 32 backup registers) and, optionally, the 64-KB SRAM2 survive. Wakeup = full reset.
ShutdownDeepest mode. Even the LSI and brown-out reset are off; only LSE + backup registers survive. Wakeup = full reset.

Typical current & what is retained

Figures below are typical at TA = 25 °C, VDD = 3.0 V from DS12023; always use the datasheet tables for guaranteed maxima in your temperature range.

ModeLPMSRegulatorTyp. IDDRetainedWake exit
Run @ 80 MHzMain≈ 100 µA/MHzeverything
SleepMain≈ 30 µA/MHzeverythingresume (few cycles)
Low-power runLPR< 10 µA @ 2 MHzeverything
Stop 0000Main≈ 114 µAall SRAM + regsresume, MSI ~4 MHz
Stop 1001LPR≈ 4.6 µAall SRAM + regsresume, MSI ~4 MHz
Stop 2010LPR (reduced)≈ 1.2 µAall SRAM + regsresume, MSI ~4 MHz
Standby (no RTC)011off≈ 0.12 µAbackup regsRESET
Standby + RTC011off (LPR if RRS)≈ 0.42 µAbackup regs (+SRAM2 if RRS)RESET
Shutdown (no RTC)1xxoff≈ 0.03 µAbackup regsRESET
Shutdown + RTC1xxoff≈ 0.30 µAbackup regsRESET
KEY RETENTION RULE

In every Stop mode all of SRAM1 (192 KB), SRAM2 (64 KB), SRAM3 (384 KB) and every peripheral register keep their contents — you resume exactly where you left off. In Standby and Shutdown the core is reset: only the RTC backup registers (RTC_BKP0R…BKP31R) survive, plus SRAM2 in Standby if you set the RRS bit. Plan your state accordingly.

02 The mechanism: SLEEPDEEP, LPMS, WFI/WFE

There is exactly one instruction that stops the core — WFI (Wait For Interrupt) or WFE (Wait For Event). Two bits decide what "stop" means: the Cortex-M4 SLEEPDEEP bit in SCB->SCR, and the LPMS[2:0] field in PWR_CR1.

The decision tree

SLEEPDEEP = 0WFI/WFE → Sleep (or Low-power sleep if LPR is on). Only the CPU clock stops. LPMS is ignored.
SLEEPDEEP = 1WFI/WFE → Deep-sleep. The PWR block now reads LPMS[2:0] to pick Stop 0/1/2, Standby or Shutdown.

So the universal entry sequence is: pick the mode in LPMS, set/clear SLEEPDEEP, make sure no wakeup flag is already pending, then execute WFI. Bracket the store to SCR with a data-sync barrier so it lands before the core sleeps.

c — SCB SCR bits (0xE000ED10)
/* Cortex-M4 System Control Register — CMSIS names */
/* SCB_SCR_SLEEPONEXIT_Msk  (bit 1) : re-sleep on ISR return       */
/* SCB_SCR_SLEEPDEEP_Msk    (bit 2) : 0 = Sleep, 1 = Stop/Standby   */
/* SCB_SCR_SEVONPEND_Msk    (bit 4) : pending IRQ generates an event */

static inline void deepsleep(int on)
{
    if (on) SCB->SCR |=  SCB_SCR_SLEEPDEEP_Msk;
    else    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
    __DSB();          /* ensure the SCR write completes before WFI */
}

WFI vs WFE

WFIWFE
Wakes onany NVIC-enabled interrupt (and NMI/reset)an event: SEV, EXTI event-mode line, or a pending IRQ if SEVONPEND=1
Runs the ISR?yes — vectoring to the handler is how you resumeno — execution just continues after WFE; no handler needed
Typical useStop/Standby with an EXTI/RTC interrupt configuredtight polling loops, or waking on an EXTI line in event mode (EXTI_EMR1)
Gotchathe peripheral IRQ must be enabled in NVIC or you never returnan already-latched event makes WFE return instantly — issue a dummy SEV; WFE; to clear it first

Most designs use WFI: enable the wakeup peripheral's EXTI line + NVIC IRQ, then __WFI(). In Stop modes the core is halted but the EXTI controller stays alive on the LSI/LSE/HSI16-on-demand paths, so an EXTI or RTC edge restarts the clocks and vectors the pending interrupt.

03 PWR register map (CR1–CR4, SR1/SR2, SCR)

The power controller lives at 0x4000_7000 on APB1. Enable its clock with RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN before touching any of these, and set PWR_CR1.DBP before writing the RTC/backup domain.

RegisterOffsetPurpose
PWR_CR10x00LPMS mode select, voltage scaling (VOS), low-power run (LPR), backup unlock (DBP)
PWR_CR20x04PVD level, peripheral voltage monitors, independent VDDUSB/VDDIO2 supplies
PWR_CR30x08Wakeup-pin enables (EWUPn), SRAM2 retention (RRS), pull config apply (APC), internal wakeup (EIWUL)
PWR_CR40x0CWakeup-pin polarity (WPn), VBAT charging (VBE/VBRS)
PWR_SR10x10Wakeup flags (WUFn), Standby flag (SBF), internal wakeup flag (WUFI)
PWR_SR20x14Regulator/scaling ready flags (VOSF, REGLPF, REGLPS), PVDO, PVMOx
PWR_SCR0x18Clear-wakeup (CWUFn) and clear-Standby (CSBF) — write 1 to clear
PWR_PUCRx / PDCRx0x20+Per-port pull-up / pull-down hold during Standby/Shutdown (needs APC=1)
PWR_CR50x80R1MODE: Range 1 "boost" (0) enables 120 MHz; normal Range 1 (1) caps ~80 MHz

PWR_CR1 — the mode selector

LPMS[2:0] — bits 2:0000 Stop 0 · 001 Stop 1 · 010 Stop 2 · 011 Standby · 1xx Shutdown. Read when SLEEPDEEP=1.
DBP — bit 8Disable Backup-domain write protection. Must be 1 to write RTC, backup registers, LSE/RTCSEL.
VOS[1:0] — bits 10:901 = Range 1 (high perf), 10 = Range 2 (low power, ≤ 26 MHz). Wait SR2.VOSF=0 after changing.
LPR — bit 14Low-power run. Set only after SYSCLK ≤ 2 MHz and VOS = Range 2.

PWR_CR3 — Standby/Shutdown behaviour & wakeup pins

EWUP1…EWUP5 — bits 0..4Enable wakeup pin WKUP1..WKUP5 for Standby/Shutdown.
RRS — bit 8SRAM2 Retention in Standby: 1 keeps the 64-KB SRAM2 powered by the LPR. No effect in Shutdown.
APC — bit 10Apply pull-up/pull-down: activates PWR_PUCRx/PDCRx so GPIOs are held (not floating) in Standby/Shutdown.
EIWUL — bit 15Enable Internal Wakeup Line (e.g. RTC/IWDG) as a Standby wakeup.

Status & clear registers

PWR_SR1: WUF1..WUF5 (0..4), SBF (8), WUFI (15)Wakeup-pin flags, Standby flag (set after Standby wake), internal wakeup flag. Read-only.
PWR_SR2: REGLPS (8), REGLPF (9), VOSF (10)LPR started / LPR in use / voltage-scaling ongoing. Poll these when switching regulator or VOS.
PWR_SCR: CWUF1..CWUF5 (0..4), CSBF (8)Write 1 to clear the matching SR1 flag. Clearing WUFn should be the LAST step before entering low-power.

04 Run, Sleep and Low-power run/sleep

Sleep is the cheapest win: peripherals keep running (a DMA transfer, a UART receive, a timer PWM) while the core idles. Nothing is lost, wake latency is a few cycles. Low-power run/sleep additionally moves the regulator to the LPR for sub-2-MHz duty.

c — Sleep on WFI, and sleep-on-exit
#include "stm32l4xx.h"

/* Plain Sleep: SLEEPDEEP=0, so WFI only gates the CPU clock.
   Any NVIC-enabled interrupt wakes and vectors to its handler. */
static void enter_sleep(void)
{
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;   /* Sleep, not Stop */
    __DSB();
    __WFI();                              /* halt until an interrupt */
}

/* Sleep-on-exit: the core automatically re-sleeps every time it
   returns from an ISR. Perfect for purely event-driven firmware —
   main() sets it once and the while(1) never actually runs. */
static void enable_sleep_on_exit(void)
{
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
    SCB->SCR |=  SCB_SCR_SLEEPONEXIT_Msk;
    __DSB();
    __WFI();                              /* first sleep; ISRs do the rest */
}
c — Low-power run (register level)
/* Low-power run needs: VOS = Range 2, then SYSCLK <= 2 MHz,
   then set LPR. Order matters. */
static void enter_low_power_run(void)
{
    RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;

    /* 1. Voltage scaling Range 2 (VOS = 10) */
    PWR->CR1 = (PWR->CR1 & ~PWR_CR1_VOS_Msk) | (0x2u << PWR_CR1_VOS_Pos);
    while (PWR->SR2 & PWR_SR2_VOSF) { }     /* wait until scaling done */

    /* 2. Drop SYSCLK to <= 2 MHz here (e.g. MSI range 2 MHz) ... */

    /* 3. Enter low-power run */
    PWR->CR1 |= PWR_CR1_LPR;
    while (!(PWR->SR2 & PWR_SR2_REGLPF)) { } /* LPR now supplying core */
}

static void exit_low_power_run(void)
{
    PWR->CR1 &= ~PWR_CR1_LPR;
    while (PWR->SR2 & PWR_SR2_REGLPF) { }    /* back on main regulator */
    /* raise SYSCLK and VOS = Range 1 again as needed */
}
SLEEP vs LOW-POWER SLEEP

"Low-power sleep" is simply Sleep entered while LPR=1. Because the LPR limits SYSCLK to 2 MHz, Flash is put in power-down and instruction fetch stalls — great for a peripheral waiting on a slow event, but do not expect fast code between wakes. To go back to full speed you must exit LPR (clear LPR, restore VOS Range 1, raise the clock) first.

05 Stop 0 / Stop 1 / Stop 2

Stop modes are the workhorse of battery designs: HSE, HSI16 and the PLL are switched off, but every byte of SRAM and every register is retained, so WFI returns to the very next instruction. The three variants trade wake speed for current — Stop 0 keeps the main regulator (fastest, ~114 µA), Stop 2 drops to a reduced LPR (~1.2 µA).

c — generic Stop entry (register level)
#include "stm32l4xx.h"

/* lpms: 0 = Stop0, 1 = Stop1, 2 = Stop2 */
static void enter_stop(uint32_t lpms)
{
    RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;

    /* 1. Select the Stop level in LPMS[2:0] */
    PWR->CR1 = (PWR->CR1 & ~PWR_CR1_LPMS_Msk)
             | (lpms & PWR_CR1_LPMS_Msk);

    /* 2. SLEEPDEEP = 1 so WFI enters Stop, not Sleep */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

    /* 3. Barrier, then sleep. Execution resumes HERE on wakeup. */
    __DSB();
    __WFI();

    /* 4. Restore SLEEPDEEP so a later plain Sleep behaves */
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
}

On wakeup the system clock is whatever STOPWUCK in RCC_CFGR selects — MSI (default, ~4 MHz) or HSI16. The PLL and HSE are off. If your app ran at 120 MHz you must rebuild the clock tree, otherwise you silently continue at 4 MHz.

c — rebuild the clock after Stop
/* After Stop the tree is MSI-only. Re-arm HSE + PLL and switch back.
   In practice just call your generated SystemClock_Config() again. */
static void restore_clock_after_stop(void)
{
    RCC->CR |= RCC_CR_HSEON;
    while (!(RCC->CR & RCC_CR_HSERDY)) { }

    RCC->CR |= RCC_CR_PLLON;
    while (!(RCC->CR & RCC_CR_PLLRDY)) { }

    RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW_Msk) | RCC_CFGR_SW_PLL;
    while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) { }
}
c — HAL equivalents
/* HAL rolls LPMS + SLEEPDEEP + WFI into one call per mode.        */
/* Stop 0 (main regulator kept):                                  */
HAL_PWREx_EnterSTOP0Mode(PWR_STOPENTRY_WFI);

/* Stop 1 (LPR):                                                  */
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);

/* Stop 2 (deepest Stop):                                         */
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);

/* Every one of these returns on wakeup with the clock on MSI,    */
/* so re-run your clock config immediately:                       */
SystemClock_Config();
CHOOSING A STOP LEVEL

Stop 0 — need < ~5 µs wake and full-speed restart: main regulator stays warm. Stop 1 — general low-power idle. Stop 2 — longest idles; a few peripherals (some GPIO/EXTI, LPUART, LPTIM, RTC, comparators, I2C3) can still wake you, but fewer than Stop 1. All three preserve SRAM and context.

06 Standby, Shutdown, SRAM2 retention & wakeup pins

Below Stop the regulators shut down and the core is powered off. Wakeup is a reset: firmware restarts at the reset vector with SRAM1/SRAM3 gone. Only the backup domain survives — plus SRAM2 in Standby if you ask for it. These are the modes for shelf-life and long sleep intervals.

c — enter Standby (optional SRAM2 retention)
#include "stm32l4xx.h"

/* retain_sram2 != 0 keeps the 64-KB SRAM2 alive across Standby
   (powered by the LPR) so you can stash state there. */
static void enter_standby(int retain_sram2)
{
    RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;

    if (retain_sram2) PWR->CR3 |=  PWR_CR3_RRS;
    else              PWR->CR3 &= ~PWR_CR3_RRS;

    /* LPMS = 011 -> Standby */
    PWR->CR1 = (PWR->CR1 & ~PWR_CR1_LPMS_Msk)
             | (0x3u << PWR_CR1_LPMS_Pos);

    /* Clear every stale wakeup flag LAST, per RM0432 */
    PWR->SCR = PWR_SCR_CWUF1 | PWR_SCR_CWUF2 | PWR_SCR_CWUF3
             | PWR_SCR_CWUF4 | PWR_SCR_CWUF5;

    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    __DSB();
    __WFI();                 /* powers down; wakeup causes a RESET */
}

/* LPMS = 1xx -> Shutdown (use 100). Deepest; ignores RRS. */
static void enter_shutdown(void)
{
    RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;
    PWR->CR1 = (PWR->CR1 & ~PWR_CR1_LPMS_Msk)
             | (0x4u << PWR_CR1_LPMS_Pos);
    PWR->SCR = PWR_SCR_CWUF1 | PWR_SCR_CWUF2 | PWR_SCR_CWUF3
             | PWR_SCR_CWUF4 | PWR_SCR_CWUF5;
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    __DSB();
    __WFI();
}

Wakeup pins (Standby/Shutdown)

Five dedicated WKUPn pins can pull the device out of Standby or Shutdown. Each is enabled by EWUPn in PWR_CR3 and its edge polarity chosen by WPn in PWR_CR4 (0 = rising, 1 = falling). On STM32L4R5 each WKUP line maps to a fixed pad:

Wakeup linePinEnable bit (PWR_CR3)Polarity bit (PWR_CR4)Flag / clear
WKUP1PA0EWUP1 (bit 0)WP1 (bit 0)WUF1 / CWUF1
WKUP2PC13EWUP2 (bit 1)WP2 (bit 1)WUF2 / CWUF2
WKUP3PE6EWUP3 (bit 2)WP3 (bit 2)WUF3 / CWUF3
WKUP4PA2EWUP4 (bit 3)WP4 (bit 3)WUF4 / CWUF4
WKUP5PC5EWUP5 (bit 4)WP5 (bit 4)WUF5 / CWUF5

Confirm the pad for your exact package against the "Additional functions" table in DS12023 — the mapping above is the standard STM32L4R5 assignment.

c — WKUP1 (PA0) rising-edge wakeup + boot detection
/* Arm WKUP1 (PA0) as a rising-edge Standby/Shutdown wakeup. The pad
   itself needs no GPIO clock — the WKUP function is always wired. */
static void configure_wakeup_pin1(void)
{
    PWR->CR4 &= ~PWR_CR4_WP1;    /* WP1 = 0 -> detect a rising edge */
    PWR->SCR  =  PWR_SCR_CWUF1;   /* clear any pending flag first     */
    PWR->CR3 |=  PWR_CR3_EWUP1;   /* enable WKUP1                     */
}

/* At every boot, tell "cold power-on" from "woke from Standby". */
int main(void)
{
    RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;

    if (PWR->SR1 & PWR_SR1_SBF) {         /* came out of Standby/Shutdown */
        PWR->SCR = PWR_SCR_CSBF;          /* clear the Standby flag       */
        /* SRAM2 is valid only if RRS was set; SRAM1/SRAM3 are cleared.
           Backup registers RTC->BKP0R..BKP31R are always valid.        */
    } else {
        /* genuine cold start: full init */
    }

    configure_wakeup_pin1();
    /* ... */
    for (;;) { }
}
FLOATING PINS DOMINATE THE BUDGET

In Standby/Shutdown, GPIOs are Hi-Z by default and a floating input can burn far more than the 0.1 µA core current. Either drive/terminate them externally, or use PWR_PUCRx/PWR_PDCRx with APC=1 in PWR_CR3 to latch a defined pull-up/pull-down that persists through the low-power mode.

07 RTC wakeup timer: periodic wake from Stop 2

The RTC wakeup timer is the canonical periodic "heartbeat": a down-counter clocked from the RTC that fires an interrupt every N ticks and pulls the core out of Stop (via EXTI line 20) or out of Standby/Shutdown (via the internal wakeup line). Clocked by the 32.768-kHz LSE it costs about a microamp in Stop 2. This is a complete, self-contained example.

c — one-time RTC + LSE bring-up
#include "stm32l4xx.h"

/* Enable the LSE and route it to the RTC. Do this once at startup. */
static void rtc_lse_init(void)
{
    RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;   /* PWR clock             */
    PWR->CR1 |= PWR_CR1_DBP;                /* unlock backup domain  */

    /* Start the 32.768 kHz LSE crystal */
    RCC->BDCR |= RCC_BDCR_LSEON;
    while (!(RCC->BDCR & RCC_BDCR_LSERDY)) { }

    /* RTCSEL = 01 (LSE) and switch the RTC on */
    RCC->BDCR = (RCC->BDCR & ~RCC_BDCR_RTCSEL_Msk)
              | (0x1u << RCC_BDCR_RTCSEL_Pos)
              | RCC_BDCR_RTCEN;
}
c — program the wakeup timer + EXTI line 20
/* Period = (seconds) using ck_spre = 1 Hz. Valid 1..65536 s.
   WUCKSEL = 100b selects ck_spre; counter reload = seconds - 1. */
static void rtc_wakeup_start(uint32_t seconds)
{
    /* 1. Unlock RTC write protection */
    RTC->WPR = 0xCA;
    RTC->WPR = 0x53;

    /* 2. Disable the timer, then wait until it is safe to write WUTR */
    RTC->CR &= ~RTC_CR_WUTE;
    while (!(RTC->ISR & RTC_ISR_WUTWF)) { }   /* WUTWF = write allowed */

    /* 3. Reload value and clock source */
    RTC->WUTR = (seconds - 1u) & 0xFFFFu;
    RTC->CR = (RTC->CR & ~RTC_CR_WUCKSEL_Msk)
            | (0x4u << RTC_CR_WUCKSEL_Pos);   /* ck_spre (1 Hz)       */

    /* 4. Enable timer + its interrupt */
    RTC->CR |= RTC_CR_WUTE | RTC_CR_WUTIE;

    /* 5. Re-lock the RTC */
    RTC->WPR = 0xFF;

    /* 6. RTC wakeup is EXTI line 20 — unmask + rising edge so it can
          restart the clocks and vector the IRQ out of Stop. */
    EXTI->IMR1  |= (1u << 20);   /* interrupt mask   (IM20)  */
    EXTI->RTSR1 |= (1u << 20);   /* rising trigger   (RT20)  */

    NVIC_SetPriority(RTC_WKUP_IRQn, 2);
    NVIC_EnableIRQ(RTC_WKUP_IRQn);
}
c — ISR + Stop 2 main loop
volatile uint32_t ticks;

/* WUTF is an rc_w0 flag and is NOT under RTC write protection,
   so clearing it needs no WPR dance. Also clear EXTI line 20. */
void RTC_WKUP_IRQHandler(void)
{
    if (RTC->ISR & RTC_ISR_WUTF) {
        RTC->ISR &= ~RTC_ISR_WUTF;   /* acknowledge wakeup timer */
        ticks++;
    }
    EXTI->PR1 = (1u << 20);           /* clear pending (write 1)  */
}

int main(void)
{
    rtc_lse_init();
    rtc_wakeup_start(5);              /* wake every 5 seconds */

    for (;;) {
        /* --- enter Stop 2 --- */
        PWR->CR1 = (PWR->CR1 & ~PWR_CR1_LPMS_Msk)
                 | (0x2u << PWR_CR1_LPMS_Pos);
        SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
        __DSB();
        __WFI();                     /* sleeps ~5 s, wakes in ISR */
        SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;

        /* Back on MSI ~4 MHz. Do a short task, then loop.
           Call restore_clock_after_stop() if you need full speed. */
    }
}
c — HAL variant of the same wakeup
/* Assuming hrtc is initialised by HAL_RTC_Init() with LSE selected. */
RTC_HandleTypeDef hrtc;

/* 5-second period using ck_spre (1 Hz): counter = 5 - 1.
   The 4th arg (WakeUpAutoClr) = 0 disables the auto-reload output. */
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 5u - 1u,
                            RTC_WAKEUPCLOCK_CKSPRE, 0u);

/* HAL enables EXTI line 20 + NVIC for you. Enter Stop 2: */
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
SystemClock_Config();                /* rebuild clock after wake */

/* HAL supplies RTC_WKUP_IRQHandler -> HAL_RTCEx_WakeUpTimerIRQHandler.
   Handle the tick in the weak callback: */
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *h)
{
    (void)h;
    /* periodic work here */
}
PICKING THE WAKEUP PERIOD

Two clock domains feed WUCKSEL. For 1 s…36 h use ck_spre (1 Hz): WUCKSEL=100, period = (WUT+1) seconds; add WUCKSEL=110 to tack on 216 s. For sub-second/finer resolution use RTCCLK/2/4/8/16 (WUCKSEL=011..000): with LSE/16 one tick is 16/32768 = 488.28 µs, so WUT = round(T / 488.28µs) - 1. Always wait for WUTWF=1 before writing WUTR.

08 Wakeup sources & EXTI mapping

What can wake you depends on the mode. In Stop, wakeups are asynchronous EXTI edges (the clocks restart on the edge). In Standby/Shutdown only a handful of always-on sources remain, and each one causes a reset.

SourceStop 0/1/2StandbyShutdown
WKUP1..WKUP5 pinsvia EXTI 0–15 (if mapped)yes (EWUPn)yes (EWUPn)
GPIO EXTI lines 0–15yesno (use WKUP pins)no
RTC alarm A/Byes (EXTI 18)yesyes (LSE)
RTC wakeup timeryes (EXTI 20)yesyes (LSE)
RTC tamper / timestampyes (EXTI 19)yesyes (LSE)
LPTIM1/2, LPUART1, I2C3yesnono
Comparators COMP1/2yes (EXTI 21/22)nono
IWDGresetresetno (LSI off)
NRST pin / BORresetresetNRST only (BOR off)

Selected EXTI internal lines (RM0432)

EXTI lines 0–15 are the GPIO edge detectors; from 16 up they are internal peripheral wakeup lines. The load-bearing ones for low power:

LineSourceConfig register bits
0–15GPIO PXn edgeIMR1/EMR1, RTSR1/FTSR1, SYSCFG_EXTICR
16PVD outputIMR1 bit 16
18RTC alarms A/BIMR1/RTSR1 bit 18
19RTC tamper / timestamp / LSECSSIMR1/RTSR1 bit 19
20RTC wakeup timerIMR1/RTSR1 bit 20
21 / 22COMP1 / COMP2 outputIMR1/RTSR1 bits 21/22
23+I2Cx / USARTx / LPUART1 / LPTIMx / PVMx / USB wakeupssee RM0432 §EXTI (some in IMR2/RTSR2)
STOP NEEDS THE EXTI UNMASK

For a peripheral to wake the core from Stop, its EXTI line must be unmasked in EXTI_IMR1 (interrupt) and given a trigger edge in EXTI_RTSR1/FTSR1. Enabling only the peripheral interrupt (e.g. RTC_CR.WUTIE) is not enough — without line 20 unmasked the core stays asleep forever. Standby/Shutdown wakeups do not use the configurable EXTI mask; they go through the internal wakeup line and always reset.

09 Gotchas & common mistakes

Almost every "it won't sleep / won't wake / draws too much" bug is one of these.

SLEEPDEEP not setForgetting SCB->SCR |= SLEEPDEEP makes WFI do plain Sleep instead of Stop/Standby — current stays high and nothing "went to sleep". Conversely, leaving it set turns a later intended Sleep into a Stop.
PWR clock offWrites to PWR registers are ignored until RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN. Enable it once at startup.
DBP not setRTC, backup registers, LSE and RTCSEL are write-protected until PWR_CR1.DBP = 1. Without it your RTC config silently no-ops.
Stale wakeup flagsIf WUFn (or the RTC WUTF, or EXTI_PR1) is still set, WFI returns immediately. Clear flags as the LAST step before sleeping — and clear EXTI_PR1 and WUTF inside the ISR.
RTC won't wake from StopYou enabled WUTIE but not EXTI line 20. Set EXTI_IMR1 bit 20 + EXTI_RTSR1 bit 20 (rising) and enable RTC_WKUP_IRQn in the NVIC.
Running at 4 MHz after StopStop returns on MSI (or HSI16 if STOPWUCK=1); PLL/HSE are off. Re-run SystemClock_Config() or you unknowingly execute 30× slower.
Expecting SRAM to survive StandbyStandby/Shutdown reset the core: SRAM1 and SRAM3 are lost. Only backup registers survive (and SRAM2 if RRS=1). Detect the wake with PWR_SR1.SBF and restore from backup registers.
WUTWF ignoredAfter clearing WUTE you must poll RTC_ISR.WUTWF = 1 before writing WUTR/WUCKSEL. Writing early is dropped and the period is wrong (often "wakes once, then never").
Floating GPIOsIn Stop/Standby a floating input can leak more than the whole core budget. Terminate externally or hold pins with PWR_PUCRx/PDCRx + APC=1.
Shutdown has no LSI / BOROnly LSE survives Shutdown. An RTC/IWDG on LSI cannot wake you; brown-out reset is disabled. Use LSE-clocked RTC (or a WKUP pin) for Shutdown wakeup.
Low-power run entered wrongSet VOS = Range 2 and drop SYSCLK ≤ 2 MHz BEFORE setting LPR. Doing it out of order gives undefined behaviour; to leave, clear LPR, wait REGLPF=0, then raise the clock.
Debugger drops in low powerSWD disconnects in Stop/Standby, so breakpoints "vanish". During bring-up set DBGMCU_CR DBG_STOP/DBG_STANDBY to keep debug alive — but clear them in production, they add current.
WFE returns instantlyA latched event makes WFE fall through. The idiom is __SEV(); __WFE(); __WFE(); — the first WFE consumes the self-posted event, the second actually waits.
MINIMAL RELIABLE STOP-2 CHECKLIST

1) PWREN clock on · 2) wakeup source armed (RTC/EXTI) with its EXTI line unmasked + NVIC enabled · 3) all flags cleared · 4) LPMS = 010 · 5) SLEEPDEEP = 1 · 6) __DSB(); __WFI(); · 7) on return clear SLEEPDEEP and rebuild the clock.