Embedded HandbookApps
All sections › II. Core and system mechanisms
STM32F103, STM32F407 · level intermediate · 20 min read
Open in the interactive handbook

10. Power and power saving

A device powered from a wall socket may never sleep. A device powered from a battery must sleep almost always: the difference between a running and a sleeping chip is four orders of magnitude, and it is exactly what decides whether the product lives a week or three years.


10.1 Three sleep modes

Terms used in the documentation

Term Meaning
low-power modes modes with reduced consumption
Sleep / Stop / Standby the three sleep depths, from light to deep
wakeup pin a pin that wakes the chip
backup domain the part that runs from VBAT
voltage regulator the internal regulator that powers the core
low-power regulator the economical mode of the regulator
programmable voltage detector (PVD) a supply level detector with a programmable threshold
power reset / brown-out reset a reset on power-up / on a supply dip
to retain the content to keep the contents
wakeup latency the time to leave the mode
send event on pending (SEVONPEND) an event on a pending interrupt
burden voltage the voltage drop across the ammeter
average current the current averaged over time
debug in low-power modes debugging while the chip sleeps
Sleep Stop Standby
core stopped stopped off
peripherals running stopped off
RAM contents retained retained lost
peripheral registers retained retained lost
exit any interrupt EXTI, RTC, IWDG the WKUP pin, RTC, reset
after exit continues from the same line continues, but the clocks are reset to HSI reset, the program starts over
exit time cycles microseconds tens to hundreds of µs
consumption (F103, order) units to tens of mA tens of µA units of µA

Three sleep modes as steps: Sleep, Stop and Standby — current, exit time and what is lost

The exit time is counted up to the first program instruction: from Standby on F103 it is 50 µs, on F407 — 375 µs. But after Standby the program starts over: starting the crystal (about 2 ms), the PLL and the start-up code add milliseconds.

The figures are given as orders of magnitude: the exact values depend on temperature, voltage and what is enabled. They should be looked up in the datasheet, section Supply current characteristics — there are tables for each mode there.

How to choose. If the pause is short (milliseconds between sensor polls) and the peripherals must keep working — Sleep. If the pause is long but the program state must be kept — Stop. If the device wakes up rarely and on an external event, and the state can be restored — Standby.


10.2 Sleep: only the core stops

The simplest mode. The core stops, everything else keeps working: timers count, the UART receives, DMA transfers.

void enter_sleep(void)
{
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;   /* обычный сон, не глубокий */
    __WFI();                              /* Wait For Interrupt */
    /* Проснулись ровно здесь: контекст цел. */
}

If SysTick is running in the program (with HAL it always is), it wakes the core every millisecond. For the duration of sleep it is stopped — HAL_SuspendTick() or SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk — and after wake-up it is switched back on.

__WFI() is the core instruction "wait for interrupt". There is also __WFE() — "wait for event"; it also reacts to events without calling a handler (the very GPIO_MODE_EVT_* modes from section 8).

A useful technique is the SLEEPONEXIT bit: with it the core automatically falls asleep on exit from every handler. The program becomes a set of reactions to interrupts, and between them the chip sleeps:

SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;

Another bit of this register, SEVONPEND, makes any interrupt that becomes pending an event for __WFE() — even one disabled in the NVIC. The chip wakes up, but the handler is not called: this is how a peripheral flag is waited for without an interrupt handler.


10.3 Stop: the clocks are stopped, memory is intact

All oscillators stop, but the contents of RAM and registers are retained. The chip wakes up on an external interrupt, an RTC alarm or the watchdog timer.

There is also an entry condition: all pending EXTI flags, peripheral interrupt flags and the RTC alarm flag must be cleared. If even one is pending, Stop will not happen — the program will simply continue after WFI. The EXTI flags are all cleared at once with the line EXTI->PR = EXTI->PR;: a flag is cleared by writing a one, and this way everything pending goes away.

void enter_stop(void)
{
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;    /* доступ к регистрам питания */

    PWR->CR &= ~PWR_CR_PDDS;              /* 0 -> Stop, а не Standby */
    PWR->CR |= PWR_CR_LPDS;               /* регулятор в экономичный режим */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;    /* глубокий сон */

    __WFI();

    /* ← сюда возвращаемся после пробуждения */
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
    SystemClock_72MHz();                  /* обязательно! см. ниже */
}

⚠️ The main pitfall of the whole section. After leaving Stop the system is clocked from HSI, not from your PLL. The crystal is off, the multiplier is reset. The program continues from the same line and looks working, but runs nine times slower: delays stretch, the UART spits garbage, PWM changes frequency. The clock configuration from section 6 must be applied again — first thing after wake-up.

Note that Stop and Standby differ by one bit, PDDS. They are easy to confuse, and the consequences differ: in the second case the program will not continue but will start over.


10.4 Standby: exit through reset

Almost everything is switched off, including the main regulator. Only the backup domain stays alive. Consumption is a few microamperes, that is, the chip can wait for years.

void enter_standby(void)
{
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;

    PWR->CSR |= PWR_CSR_EWUP;             /* разрешить вывод WKUP (PA0) */
    PWR->CR |= PWR_CR_PDDS;               /* 1 -> Standby */
    PWR->CR |= PWR_CR_CWUF;               /* сбросить флаг — после EWUP */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

    __WFI();
    /* Сюда исполнение уже не вернётся. */
}

Wake-up from Standby is a reset: the program starts from Reset_Handler, RAM is lost (there are random values there; the zeros in .bss are written again by the start-up code), the peripherals are in their initial state. Such a start can be told from an ordinary power-up by a flag:

uint8_t woke_from_standby(void)
{
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    if (PWR->CSR & PWR_CSR_SBF) {
        PWR->CR |= PWR_CR_CSBF;           /* сбросить признак */
        return 1u;
    }
    return 0u;
}

⚠️ Clear CWUF before entry, last of all. If the wake-up flag stays set, the chip will leave Standby instantly — and you will see an endless reboot instead of sleep. On F1 enabling EWUP with a high level on PA0 sets the flag by itself, so CWUF is set after EWUP, right before __WFI.


10.5 The backup domain

A separate area powered from the VBAT pin — usually from a lithium cell or a supercapacitor. It keeps working when everything else is unpowered.

What lives there:

Writing there is protected, and the protection must be removed explicitly:

void backup_domain_write(uint32_t value)
{
    RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN;
    PWR->CR |= PWR_CR_DBP;                /* снять защиту записи */
    BKP->DR1 = (uint16_t)value;
    PWR->CR &= ~PWR_CR_DBP;               /* вернуть защиту */
}

A forgotten DBP is the typical cause of "I write to a backup register, but it does not change". There is no error, the write is simply ignored.

Backup registers are convenient precisely for Standby: save before sleep what must not be lost, and read it after wake-up.


10.6 What can wake it up

Source From Sleep From Stop From Standby
any peripheral interrupt yes no no
an external EXTI interrupt yes yes no
RTC alarm yes yes yes
the IWDG watchdog through reset through reset through reset
the WKUP pin (PA0) yes yes yes
the NRST signal yes yes yes

The key point: from Standby only WKUP, RTC and reset wake the chip. Ordinary pins do not work there — the EXTI controller is unpowered. If the device must wake up on a button press, the button is wired to PA0.

For periodic wake-up the RTC is used: it is clocked from LSE or LSI, which keep running in the backup domain.

A running watchdog does not stop in sleep. On F1 and F4 IWDG cannot be switched off either by the program or by sleep: it counts in both Stop and Standby. If the sleep is longer than its period (on F1 no more than 4096 × 256 / 40 kHz ≈ 26 s), the chip will reboot. Then the RTC wakes the chip ahead of time, the program refreshes the watchdog and falls asleep again. On L4, G0 and G4 the watchdog is frozen in Stop and Standby by the option bits IWDG_STOP and IWDG_STDBY.


10.7 The voltage detector (PVD)

It compares the supply with a threshold and reports when it has dropped. This is not a reset but a warning: the program has time left to save data to Flash or backup registers while the capacitors still hold their charge.

PWR->CR = (PWR->CR & ~PWR_CR_PLS) | PWR_CR_PLS_2V7;   /* порог 2,7 В */
PWR->CR |= PWR_CR_PVDE;         /* включить детектор */
EXTI->RTSR |= EXTI_RTSR_TR16;   /* нарастающий фронт PVDO: питание упало ниже порога */
EXTI->IMR  |= EXTI_IMR_MR16;
NVIC_EnableIRQ(PVD_IRQn);

Useful in products where the power may go off at any moment: meters, loggers, anything where an interruption in the middle of a write corrupts data.


10.8 How to measure the sleep current

The figures in table 10.1 are an order of magnitude, not a promise. Your own device has to be measured: a forgotten pull resistor or the debugger easily add more than the sleeping chip itself draws. And measuring is harder than it seems: within milliseconds the current changes by hundreds of times.

The example for the whole subsection is a sensor powered from two AA cells (3.0 V, about 2500 mAh). Once a second it wakes up for 5 ms and draws 10 mA during that time, the rest of the time it sleeps in Stop at 20 µA.

Where to connect the instrument. The ammeter is put into the supply line of the chip itself, not of the whole board: the regulator and the board's power LED also draw current, often more than the sleeping chip. Nucleo boards have the IDD jumper for this: if it is removed, only the microcontroller's supply is broken.

The instrument itself interferes. An ammeter is a shunt, and voltage drops across it. In a simple 3½-digit multimeter the shunt of each range is chosen so that full scale gives 200 mV across it:

Range Shunt Sleep, 20 µA Wake-up, 10 mA
200 µA 1 kΩ 20 mV, step 0.1 µA 10 V needed — impossible
2 mA 100 Ω 2 mV, step 1 µA 1 V: 2.0 V remains
20 mA 10 Ω 0.2 mV, step 10 µA 0.1 V

On the 200 µA range no more than (3.0 − 2.0) V / 1 kΩ = 1.0 mA will pass through the instrument. When trying to wake up, the supply sags below 2.0 V — the lower limit for F103. For a while the chip runs on the charge of the capacitors (10 µF at a current of 10 mA discharge by a volt in a millisecond), and then goes into reset. A short wake-up sometimes gets through, a long one never does, and from the outside this looks like a mysterious failure. On the 2 mA range the chip wakes up exactly at the limit of what is allowed, and on the 20 mA range the sleep current can no longer be seen.

Hence the technique: a jumper in parallel with the instrument. Start-up and wake-ups go through the closed jumper, and when the chip has fallen asleep, it is opened and the reading is taken.

The multimeter averages the wrong thing. The reading updates two or three times a second and is averaged over a window of about 100 ms. If a burst fell into the window, the instrument shows (10 mA · 5 ms + 20 µA · 95 ms) / 100 ms = 519 µA; if it did not — 20 µA. The reading jumps between these numbers, and the real average, about 70 µA, is shown by neither of them.

The sensor current on a meter and on an oscilloscope: 10 mA bursts of 5 ms, sleep at 20 µA, average 69.9 µA

Three measurements instead of one.

  1. Sleep current. Wake-ups are switched off (or the alarm is set to a minute), the 200 µA range, the jumper.
  2. The burst. A 10 Ω shunt in the supply and an oscilloscope: 10 mA gives 100 mV across it, the height and width of the pulse can be seen. The sleep current on the same shunt gives 0.2 mV and drowns in noise, which is why it is measured separately.
  3. Average current. It is calculated:
I_ср = I_акт · t_акт / T + I_сна · (1 − t_акт / T)
     = 10 мА · 0,005 + 20 мкА · 0,995 = 50 + 19,9 = 69,9 мкА

Instruments that measure everything at once do exist — these are current meters with automatic range switching. The task is not easy for them: the current changes 500-fold, and to see the sleep current with 1 % accuracy you need 10 mA / 0.2 µA = 50 000 counts. That is 25 times more than a 3½-digit multimeter has.

What the calculation gives. Five milliseconds out of a thousand — half a percent of the time — give 50 of the 69.9 µA, that is 72 % of the consumption. A 2500 mAh battery will last 2500 / 0.0699 ≈ 35 800 h, which is 4.1 years. What happens if you change one part at a time:

What was changed Average current Battery life
nothing 69.9 µA 4.1 years
a burst half as long, 2.5 ms 45 µA 6.3 years
half the sleep current, 10 µA 60 µA 4.8 years
a forgotten pull-up on a pin held to ground 145 µA 2.0 years

A burst half as long added more than two years, and half the sleep current eight months. Hunting for sleep microamperes is worth it when the active part has already been squeezed. The built-in pull resistor is about 40 kΩ. If a pin is held to ground externally by a pressed button or by the output of a neighbouring chip, through it flows 3.0 V / 40 kΩ = 75 µA — more than the whole average current of the example. One such pull resistor halves the battery life.

Preparing the chip for the measurement. Unused pins are put into analog mode: it has the input trigger switched off, and a floating input draws no current. On F1 this is four zero bits in CRL/CRH, on F4 two ones in MODER. After reset the pins of both F1 and F4 are inputs (except the debug pins), so you have to switch them yourself; on G4 and L4 the pins are already analog after reset.

/* keep — выводы порта, которые трогать нельзя (1 — оставить как есть) */
void port_to_analog(GPIO_TypeDef *port, uint16_t keep)
{
#if defined(STM32F10X_MD)
    uint32_t lo = 0, hi = 0;                /* по четыре бита на вывод */
    for (int i = 0; i < 8; i++) {
        if (keep & (1u << i))       lo |= 0xFu << (4 * i);
        if (keep & (1u << (i + 8))) hi |= 0xFu << (4 * i);
    }
    port->CRL &= lo;                        /* аналоговый вход у F1 — 0000 */
    port->CRH &= hi;
#elif defined(STM32F407xx)
    uint32_t m = 0;                         /* по два бита на вывод */
    for (int i = 0; i < 16; i++)
        if (keep & (1u << i))
            m |= 3u << (2 * i);
    port->MODER |= ~m;                      /* аналоговый режим у F4 — 11 */
    port->PUPDR &= m;                       /* и подтяжки снять */
#endif
}

void sleep_measure_prepare(void)
{
#if defined(STM32F10X_MD)                   /* без такта запись в порт не проходит */
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN;
#elif defined(STM32F407xx)
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
#endif
    port_to_analog(GPIOA, (1u << 13) | (1u << 14));   /* SWDIO и SWCLK */
    port_to_analog(GPIOB, 0);
    port_to_analog(GPIOC, (1u << 14) | (1u << 15));   /* кварц часов LSE */
    debug_off_in_sleep();
}

The debug pins PA13 and PA14 are left as they are: in analog mode the programmer may lose the connection with the chip, and flashing will require connecting under reset. The clock crystal pins PC14 and PC15 are left in case the RTC wakes the chip from LSE. The other ports are handled in the same way.

The debugger. To avoid losing the chip in sleep, the debugging environment sets in DBGMCU->CR the bits DBG_SLEEP, DBG_STOP and DBG_STANDBY — and in Stop the clocks from HSI keep running: instead of tens of microamperes you get a current of the Sleep order. The reset button does not clear these bits, only a power-off clears them. So after debugging the power is cycled or the bits are cleared by yourself (on F1 only the first way is reliable: without a debugger DBGMCU_CR is not accessible to the program, section 2а.4):

void debug_off_in_sleep(void)
{
    DBGMCU->CR &= ~(DBGMCU_CR_DBG_SLEEP | DBGMCU_CR_DBG_STOP | DBGMCU_CR_DBG_STANDBY);
}

10.9 F0 and G0: F0 is like F1, G0 has a mode field

F0 repeats F1 down to the bit: two registers PWR->CR and PWR->CSR, Stop and Standby differ by PDDS, the regulator by LPDS, the flags are cleared by CWUF/CSBF, the wake-up pin is enabled by EWUP1. There is one difference: after Stop the system starts from the 8 MHz HSI, and the 48 MHz from 6.7 must be enabled again.

    PWR->CR &= ~PWR_CR_PDDS;                    /* 0 -> Stop, а не Standby */
    PWR->CR |= PWR_CR_LPDS;                     /* регулятор в экономичный режим */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    __WFI();

G0 is built differently, and this design is shared with L4, G4, U5: the sleep mode is not a set of bits but the three-bit field LPMS in CR1. The values come from the LL header stm32g0xx_ll_pwr.h:

LPMS Mode What remains
000 Stop 0 RAM, the regulators in normal mode — fast exit
001 Stop 1 RAM, the regulator in low-power mode
011 Standby only the backup domain and, optionally, part of RAM
100 Shutdown nothing but the backup domain: no RAM and no voltage detector

The wake-up flags are read in SR1 and cleared by writing ones to a separate register SCR; the wake-up pins are EWUP1 in CR3. F0/F1 code does not build on G0: no member named 'CR' in 'PWR_TypeDef', PWR_CR_PDDS is not declared.

    PWR->CR1 = (PWR->CR1 & ~PWR_CR1_LPMS) | LL_PWR_MODE_STOP1;   /* Stop 1: регулятор в экономичном режиме */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    __WFI();
    PWR->SCR = PWR_SCR_CWUF1 | PWR_SCR_CSBF;    /* флаги — записью единиц в SCR, а не в CR */
    PWR->CR3 |= PWR_CR3_EWUP1;                  /* вывод WKUP1 (PA0) */
    PWR->CR1 = (PWR->CR1 & ~PWR_CR1_LPMS) | LL_PWR_MODE_STANDBY;

Two modes that F0 and F1 do not have at all. Shutdown is deeper than Standby: even the voltage detector is off, RAM is not retained, exit is a reset. Low-power run (LPR in CR1): the core keeps executing code, but the regulator is in low-power mode — suitable for slow tasks between sleeps. After Stop G0 starts from HSI16 — the 64 MHz from 6.7 is enabled again, as on F0.


10.10 Pitfalls

A forgotten clock for PWR. The power registers are on APB1, and without RCC_APB1ENR_PWREN writes to them do not go through. Silently.

The clocks are not restored after Stop. Covered above — the most frequent and the least noticeable error of the mode.

Stop does not happen, the current is as when running. A flag is pending: a pending one in EXTI->PR — often from the button that woke the chip last time — a peripheral interrupt flag or the RTC alarm flag. WFI then does not put it to sleep, and the program continues. Clear the flags before entry (10.3).

CWUF was not cleared or was cleared before EWUP. An instant exit from Standby that looks like a reboot after a failure.

The debugger interferes with measuring. While ST‑Link is connected, some blocks stay powered: the DBG_* bits in DBGMCU->CR keep the clocks running in Stop, and the consumption looks much higher than the real one. The reset button does not clear these bits — after debugging you must cycle the power or clear them in software (10.8).

The ammeter drops the supply. On the 200 µA range the multimeter's shunt is 1 kΩ, and the chip cannot wake up: the supply sags, and the wake-up turns into a reset. A jumper in parallel with the instrument saves the day (10.8).

Pins in an undefined state. Current leaks not only through the core: an input left "floating" may draw more than the sleeping chip. Before sleep it makes sense to put unused pins into analog mode — its consumption is zero (section 8, a ready function is in 10.8).

Peripherals keep eating current. In Sleep everything that is enabled runs: timers, the ADC, USB. If the goal is to save power, whatever is unnecessary must be switched off in RCC before falling asleep.

Waking up too often. Leaving Stop takes microseconds, and leaving Standby together with restarting the program takes milliseconds, and each time it is a current burst. Waking up a hundred times a second for the sake of Standby is pointless — the gain is eaten by the transitions.


10.11 Summary

Full sources

pwr_f0.c — STM32F072 sleep modes: PWR registers as on F1.

/* Раздел 10.9: режимы сна STM32F072 — регистры PWR как у F1: CR и CSR. */
#include <stddef.h>
#include "stm32f0xx.h"

_Static_assert(offsetof(PWR_TypeDef, CSR) == 0x04u, "у F0 два регистра PWR — CR и CSR, как у F1");

void enter_stop_f0(void)
{
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    PWR->CR &= ~PWR_CR_PDDS;                    /* 0 -> Stop, а не Standby */
    PWR->CR |= PWR_CR_LPDS;                     /* регулятор в экономичный режим */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    __WFI();
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
    /* после Stop система тактируется от HSI 8 МГц — 48 МГц из 6.7 включить заново */
}

void enter_standby_f0(void)
{
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    PWR->CR |= PWR_CR_CWUF;                     /* сбросить флаг пробуждения */
    PWR->CR |= PWR_CR_PDDS;                     /* 1 -> Standby */
    PWR->CSR |= PWR_CSR_EWUP1;                  /* вывод WKUP1 (PA0) */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    __WFI();
}

pwr_g0.c — STM32G071 sleep modes: the LPMS field, clearing flags through SCR, wake-up pins in CR3.

/* Раздел 10.9: режимы сна STM32G071 — режим выбирает поле LPMS в CR1,
 * флаги сбрасываются записью в SCR, будящие выводы разрешают в CR3. */
#include <stddef.h>
#include "stm32g0xx.h"
#include "stm32g0xx_ll_pwr.h"

_Static_assert(offsetof(PWR_TypeDef, SCR) == 0x18u && offsetof(PWR_TypeDef, SR1) == 0x10u, "SR1 и SCR");
_Static_assert(LL_PWR_MODE_STOP0 == 0u && LL_PWR_MODE_STOP1 == PWR_CR1_LPMS_0
               && LL_PWR_MODE_STANDBY == (PWR_CR1_LPMS_1 | PWR_CR1_LPMS_0) && LL_PWR_MODE_SHUTDOWN == PWR_CR1_LPMS_2,
               "LPMS: 000 Stop 0, 001 Stop 1, 011 Standby, 100 Shutdown");

void enter_stop1_g0(void)
{
    RCC->APBENR1 |= RCC_APBENR1_PWREN;
    PWR->CR1 = (PWR->CR1 & ~PWR_CR1_LPMS) | LL_PWR_MODE_STOP1;   /* Stop 1: регулятор в экономичном режиме */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    __WFI();
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
    /* после Stop система тактируется от HSI16 — 64 МГц из 6.7 включить заново */
}

void enter_standby_g0(void)
{
    RCC->APBENR1 |= RCC_APBENR1_PWREN;
    PWR->SCR = PWR_SCR_CWUF1 | PWR_SCR_CSBF;    /* флаги — записью единиц в SCR, а не в CR */
    PWR->CR3 |= PWR_CR3_EWUP1;                  /* вывод WKUP1 (PA0) */
    PWR->CR1 = (PWR->CR1 & ~PWR_CR1_LPMS) | LL_PWR_MODE_STANDBY;
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    __WFI();
}

/* Чего нет у F0 и F1: работа на пониженном напряжении регулятора (LPR)
 * и Shutdown — глубже Standby, без ОЗУ и без часов сна. */
void enter_shutdown_g0(void)
{
    PWR->CR1 = (PWR->CR1 & ~PWR_CR1_LPMS) | LL_PWR_MODE_SHUTDOWN;
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    __WFI();
}

Next: section 10а "Low power on L4 and U5" — Stop 2, Stop 3, Shutdown and why a battery lives only a quarter longer with them.

Open in the interactive handbook