diff --git a/dts/arm/st/f3/stm32f3.dtsi b/dts/arm/st/f3/stm32f3.dtsi index fc26a624fa8be..044d0451dc5e8 100644 --- a/dts/arm/st/f3/stm32f3.dtsi +++ b/dts/arm/st/f3/stm32f3.dtsi @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,7 @@ / { chosen { zephyr,flash-controller = &flash; + zephyr,cortex-m-idle-timer = &rtc; }; cpus { @@ -31,8 +33,27 @@ cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4f"; + cpu-power-states = <&stop0 &stop1>; reg = <0>; }; + + power-states { + stop0: stop0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <0>; + min-residency-us = <500>; + exit-latency-us = <400>; + }; + + stop1: stop1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <500>; + exit-latency-us = <600>; + }; + }; }; sram0: memory@20000000 { @@ -412,6 +433,22 @@ }; }; + pwr: power@40007000 { + compatible = "st,stm32-pwr"; + reg = <0x40007000 0x400>; + status = "okay"; + + wkup-pins-nb = <1>; + + #address-cells = <1>; + #size-cells = <0>; + + wkup-pin@1 { + reg = <0x1>; + wkup-gpios = <&gpioa 0 STM32_PWR_WKUP_PIN_NOT_MUXED>; + }; + }; + die_temp: dietemp { compatible = "st,stm32-temp-cal"; ts-cal1-addr = <0x1FFFF7B8>; diff --git a/samples/boards/st/power_mgmt/wkup_pins/boards/nucleo_f302r8.overlay b/samples/boards/st/power_mgmt/wkup_pins/boards/nucleo_f302r8.overlay new file mode 100644 index 0000000000000..32fe4c5de6ddc --- /dev/null +++ b/samples/boards/st/power_mgmt/wkup_pins/boards/nucleo_f302r8.overlay @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Enes Albay + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + wkup-src = &wkup_button; + }; + + gpio_keys { + wkup_button: wkup { + label = "WKUP"; + /* + * PA0 is not connected to any button: you must connect it to VDD (+3.3V) + * using a jumper wire. For example, wiring PA0 CN7[28] (PA0) to VDD CN7[16] + */ + gpios = <&gpioa 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + zephyr,code = ; + }; + }; +}; + +&pwr { + status = "okay"; +}; diff --git a/samples/boards/st/power_mgmt/wkup_pins/sample.yaml b/samples/boards/st/power_mgmt/wkup_pins/sample.yaml index 80db1f2d39d6d..c8d2d52cd3428 100644 --- a/samples/boards/st/power_mgmt/wkup_pins/sample.yaml +++ b/samples/boards/st/power_mgmt/wkup_pins/sample.yaml @@ -8,6 +8,7 @@ tests: platform_allow: - nucleo_c092rc - nucleo_f103rb + - nucleo_f302r8 - nucleo_g031k8 - nucleo_l152re - nucleo_l4r5zi diff --git a/soc/st/stm32/common/soc_config.c b/soc/st/stm32/common/soc_config.c index 159a581ff9185..3c1411d7bbca9 100644 --- a/soc/st/stm32/common/soc_config.c +++ b/soc/st/stm32/common/soc_config.c @@ -69,7 +69,8 @@ static int st_stm32_common_config(void) #if defined(CONFIG_STM32_ENABLE_DEBUG_SLEEP_STOP) -#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32L1X) +#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32F3X) || \ + defined(CONFIG_SOC_SERIES_STM32L1X) LL_DBGMCU_EnableDBGSleepMode(); LL_DBGMCU_EnableDBGStopMode(); LL_DBGMCU_EnableDBGStandbyMode(); @@ -89,7 +90,8 @@ static int st_stm32_common_config(void) #else /* keeping in mind that debugging draws a lot of power we explicitly disable when not needed */ -#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32L1X) +#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32F3X) || \ + defined(CONFIG_SOC_SERIES_STM32L1X) LL_DBGMCU_DisableDBGSleepMode(); LL_DBGMCU_DisableDBGStopMode(); LL_DBGMCU_DisableDBGStandbyMode(); diff --git a/soc/st/stm32/stm32f3x/CMakeLists.txt b/soc/st/stm32/stm32f3x/CMakeLists.txt index eebd281cd96be..f737c62ce24d7 100644 --- a/soc/st/stm32/stm32f3x/CMakeLists.txt +++ b/soc/st/stm32/stm32f3x/CMakeLists.txt @@ -5,6 +5,9 @@ zephyr_sources( soc.c ) +zephyr_sources_ifdef(CONFIG_PM power.c) +zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c) + zephyr_include_directories(.) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/st/stm32/stm32f3x/Kconfig b/soc/st/stm32/stm32f3x/Kconfig index f5e0987fb004b..03992b04d0982 100644 --- a/soc/st/stm32/stm32f3x/Kconfig +++ b/soc/st/stm32/stm32f3x/Kconfig @@ -10,5 +10,7 @@ config SOC_SERIES_STM32F3X select CPU_HAS_FPU select HAS_STM32CUBE select HAS_STM32_FLASH_PREFETCH + select HAS_PM + select HAS_POWEROFF select HAS_SWO select SOC_EARLY_INIT_HOOK diff --git a/soc/st/stm32/stm32f3x/Kconfig.defconfig b/soc/st/stm32/stm32f3x/Kconfig.defconfig index f80f5906f4463..92b16d9759779 100644 --- a/soc/st/stm32/stm32f3x/Kconfig.defconfig +++ b/soc/st/stm32/stm32f3x/Kconfig.defconfig @@ -14,4 +14,14 @@ configdefault SHARED_INTERRUPTS default y if $(dt_nodelabel_enabled,timers1) && $(dt_nodelabel_enabled,timers16) default y if $(dt_nodelabel_enabled,timers1) && $(dt_nodelabel_enabled,timers17) +if PM + +config COUNTER + default y + +config COUNTER_RTC_STM32_SUBSECONDS + default y if DT_HAS_ST_STM32_RTC_ENABLED + +endif # PM + endif # SOC_SERIES_STM32F3X diff --git a/soc/st/stm32/stm32f3x/power.c b/soc/st/stm32/stm32f3x/power.c new file mode 100644 index 0000000000000..76c013aab803b --- /dev/null +++ b/soc/st/stm32/stm32f3x/power.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025 Enes Albay + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + LL_LPM_DisableEventOnPend(); + LL_PWR_ClearFlag_WU(); + + if (substate_id == 0) { + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_MAINREGU); + } else { + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_LPREGU); + } + + LL_LPM_EnableDeepSleep(); + k_cpu_idle(); + break; + + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + LL_LPM_DisableSleepOnExit(); + LL_LPM_EnableSleep(); + + /* Restore the clock setup. */ + stm32_clock_control_init(NULL); + break; + + default: + LOG_DBG("Unsupported power substate-id %u", state); + break; + } + + /* + * System is now in active mode. Reenable interrupts which were + * disabled when OS started idling code. + */ + irq_unlock(0); +} + +void stm32_power_init(void) +{ + /* Enable Power clock. It should by done by default, but make sure to + * enable it for all STM32F3x chips. + */ + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); +} diff --git a/soc/st/stm32/stm32f3x/poweroff.c b/soc/st/stm32/stm32f3x/poweroff.c new file mode 100644 index 0000000000000..e141946cc9bdf --- /dev/null +++ b/soc/st/stm32/stm32f3x/poweroff.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Enes Albay + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +void z_sys_poweroff(void) +{ + LL_PWR_ClearFlag_SB(); + LL_PWR_ClearFlag_WU(); + + LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY); + + stm32_enter_poweroff(); +} diff --git a/soc/st/stm32/stm32f3x/soc.c b/soc/st/stm32/stm32f3x/soc.c index f491a95595fb5..2a2b65f1e1f1c 100644 --- a/soc/st/stm32/stm32f3x/soc.c +++ b/soc/st/stm32/stm32f3x/soc.c @@ -15,6 +15,8 @@ #include +extern void stm32_power_init(void); + /** * @brief Perform basic hardware initialization at boot. * @@ -31,6 +33,10 @@ void soc_early_init_hook(void) /* At reset, system core clock is set to 8 MHz from HSI */ SystemCoreClock = 8000000; +#if defined(CONFIG_PM) + stm32_power_init(); +#endif + /* Allow reflashing the board */ LL_DBGMCU_EnableDBGSleepMode(); }