Skip to content

Commit fed0681

Browse files
committed
soc: st: stm32f3: Add power management
Adds full low-power support to STM32F3 in Zephyr, including: STOP0 & STOP1 modes (with main/LP regulator) STANDBY (poweroff) mode Wakeup pin (PA0) support SoC clock reinitialization on wakeup Idle timer using RTC Samples updated to test wakeup pin and poweroff This is a significant power-management enablement patch for the STM32F3 series. Tested on: NUCLEO-F302R8 board. Signed-off-by: Enes Albay <[email protected]>
1 parent e3ef835 commit fed0681

File tree

10 files changed

+165
-2
lines changed

10 files changed

+165
-2
lines changed

dts/arm/st/f3/stm32f3.dtsi

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <zephyr/dt-bindings/pwm/stm32_pwm.h>
1515
#include <zephyr/dt-bindings/dma/stm32_dma.h>
1616
#include <zephyr/dt-bindings/reset/stm32f0_1_3_reset.h>
17+
#include <zephyr/dt-bindings/power/stm32_pwr.h>
1718
#include <zephyr/dt-bindings/sensor/qdec_stm32.h>
1819
#include <zephyr/dt-bindings/adc/adc.h>
1920
#include <freq.h>
@@ -22,6 +23,7 @@
2223
/ {
2324
chosen {
2425
zephyr,flash-controller = &flash;
26+
zephyr,cortex-m-idle-timer = &rtc;
2527
};
2628

2729
cpus {
@@ -31,8 +33,27 @@
3133
cpu0: cpu@0 {
3234
device_type = "cpu";
3335
compatible = "arm,cortex-m4f";
36+
cpu-power-states = <&stop0 &stop1>;
3437
reg = <0>;
3538
};
39+
40+
power-states {
41+
stop0: stop0 {
42+
compatible = "zephyr,power-state";
43+
power-state-name = "suspend-to-idle";
44+
substate-id = <0>;
45+
min-residency-us = <1000000>;
46+
exit-latency-us = <400>;
47+
};
48+
49+
stop1: stop1 {
50+
compatible = "zephyr,power-state";
51+
power-state-name = "suspend-to-idle";
52+
substate-id = <1>;
53+
min-residency-us = <1000000>;
54+
exit-latency-us = <600>;
55+
};
56+
};
3657
};
3758

3859
sram0: memory@20000000 {
@@ -412,6 +433,22 @@
412433
};
413434
};
414435

436+
pwr: power@40007000 {
437+
compatible = "st,stm32-pwr";
438+
reg = <0x40007000 0x400>;
439+
status = "okay";
440+
441+
wkup-pins-nb = <1>;
442+
443+
#address-cells = <1>;
444+
#size-cells = <0>;
445+
446+
wkup-pin@1 {
447+
reg = <0x1>;
448+
wkup-gpios = <&gpioa 0 STM32_PWR_WKUP_PIN_NOT_MUXED>;
449+
};
450+
};
451+
415452
die_temp: dietemp {
416453
compatible = "st,stm32-temp-cal";
417454
ts-cal1-addr = <0x1FFFF7B8>;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/ {
2+
aliases {
3+
wkup-src = &wkup_button;
4+
};
5+
6+
gpio_keys {
7+
wkup_button: wkup {
8+
label = "WKUP";
9+
gpios = <&gpioa 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
10+
zephyr,code = <INPUT_KEY_POWER>;
11+
};
12+
};
13+
};
14+
15+
&pwr {
16+
status = "okay";
17+
};

samples/boards/st/power_mgmt/wkup_pins/sample.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ tests:
88
platform_allow:
99
- nucleo_c092rc
1010
- nucleo_f103rb
11+
- nucleo_f302r8
1112
- nucleo_g031k8
1213
- nucleo_l152re
1314
- nucleo_l4r5zi

soc/st/stm32/common/soc_config.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ static int st_stm32_common_config(void)
6969

7070
#if defined(CONFIG_STM32_ENABLE_DEBUG_SLEEP_STOP)
7171

72-
#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32L1X)
72+
#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32F3X) || \
73+
defined(CONFIG_SOC_SERIES_STM32L1X)
7374
LL_DBGMCU_EnableDBGSleepMode();
7475
LL_DBGMCU_EnableDBGStopMode();
7576
LL_DBGMCU_EnableDBGStandbyMode();
@@ -89,7 +90,8 @@ static int st_stm32_common_config(void)
8990
#else
9091

9192
/* keeping in mind that debugging draws a lot of power we explicitly disable when not needed */
92-
#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32L1X)
93+
#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32F3X) || \
94+
defined(CONFIG_SOC_SERIES_STM32L1X)
9395
LL_DBGMCU_DisableDBGSleepMode();
9496
LL_DBGMCU_DisableDBGStopMode();
9597
LL_DBGMCU_DisableDBGStandbyMode();

soc/st/stm32/stm32f3x/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ zephyr_sources(
55
soc.c
66
)
77

8+
zephyr_sources_ifdef(CONFIG_PM power.c)
9+
zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c)
10+
811
zephyr_include_directories(.)
912

1013
set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "")

soc/st/stm32/stm32f3x/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ config SOC_SERIES_STM32F3X
1010
select CPU_HAS_FPU
1111
select HAS_STM32CUBE
1212
select HAS_STM32_FLASH_PREFETCH
13+
select HAS_PM
14+
select HAS_POWEROFF
1315
select HAS_SWO
1416
select SOC_EARLY_INIT_HOOK

soc/st/stm32/stm32f3x/Kconfig.defconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ configdefault SHARED_INTERRUPTS
1414
default y if $(dt_nodelabel_enabled,timers1) && $(dt_nodelabel_enabled,timers16)
1515
default y if $(dt_nodelabel_enabled,timers1) && $(dt_nodelabel_enabled,timers17)
1616

17+
config PM
18+
select COUNTER
19+
select COUNTER_RTC_STM32_SUBSECONDS
20+
1721
endif # SOC_SERIES_STM32F3X

soc/st/stm32/stm32f3x/power.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2025 Enes Albay <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <clock_control/clock_stm32_ll_common.h>
8+
#include <stm32_ll_bus.h>
9+
#include <stm32_ll_cortex.h>
10+
#include <stm32_ll_pwr.h>
11+
#include <zephyr/kernel.h>
12+
#include <zephyr/logging/log.h>
13+
#include <zephyr/pm/pm.h>
14+
15+
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
16+
17+
void pm_state_set(enum pm_state state, uint8_t substate_id)
18+
{
19+
switch (state) {
20+
case PM_STATE_SUSPEND_TO_IDLE:
21+
LL_LPM_DisableEventOnPend();
22+
LL_PWR_ClearFlag_WU();
23+
24+
if (substate_id == 0) {
25+
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_MAINREGU);
26+
} else {
27+
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_LPREGU);
28+
}
29+
30+
LL_LPM_EnableDeepSleep();
31+
k_cpu_idle();
32+
break;
33+
34+
default:
35+
LOG_DBG("Unsupported power state %u", state);
36+
break;
37+
}
38+
}
39+
40+
void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
41+
{
42+
ARG_UNUSED(substate_id);
43+
44+
switch (state) {
45+
case PM_STATE_SUSPEND_TO_IDLE:
46+
LL_LPM_DisableSleepOnExit();
47+
LL_LPM_EnableSleep();
48+
49+
/* Restore the clock setup. */
50+
stm32_clock_control_init(NULL);
51+
break;
52+
53+
default:
54+
LOG_DBG("Unsupported power substate-id %u", state);
55+
break;
56+
}
57+
58+
/*
59+
* System is now in active mode. Reenable interrupts which were
60+
* disabled when OS started idling code.
61+
*/
62+
irq_unlock(0);
63+
}
64+
65+
void stm32_power_init(void)
66+
{
67+
/* Enable Power clock. It should by done by default, but make sure to
68+
* enable it for all STM32F3x chips.
69+
*/
70+
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
71+
}

soc/st/stm32/stm32f3x/poweroff.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (c) 2025 Enes Albay <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <stm32_ll_cortex.h>
8+
#include <stm32_ll_pwr.h>
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/sys/poweroff.h>
11+
12+
void z_sys_poweroff(void)
13+
{
14+
LL_PWR_ClearFlag_SB();
15+
LL_PWR_ClearFlag_WU();
16+
17+
LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
18+
19+
stm32_enter_poweroff();
20+
}

soc/st/stm32/stm32f3x/soc.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
#include <cmsis_core.h>
1717

18+
extern void stm32_power_init(void);
19+
1820
/**
1921
* @brief Perform basic hardware initialization at boot.
2022
*
@@ -31,6 +33,10 @@ void soc_early_init_hook(void)
3133
/* At reset, system core clock is set to 8 MHz from HSI */
3234
SystemCoreClock = 8000000;
3335

36+
#if defined(CONFIG_PM) || defined(CONFIG_POWEROFF)
37+
stm32_power_init();
38+
#endif
39+
3440
/* Allow reflashing the board */
3541
LL_DBGMCU_EnableDBGSleepMode();
3642
}

0 commit comments

Comments
 (0)