diff --git a/dts/arm/st/f1/stm32f1.dtsi b/dts/arm/st/f1/stm32f1.dtsi index 1f1eca739bc..7433f54ed71 100644 --- a/dts/arm/st/f1/stm32f1.dtsi +++ b/dts/arm/st/f1/stm32f1.dtsi @@ -15,11 +15,13 @@ #include #include #include +#include #include / { chosen { zephyr,flash-controller = &flash; + zephyr,cortex-m-idle-timer = &rtc; }; cpus { @@ -29,8 +31,27 @@ cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m3"; + 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 = <1000000>; + exit-latency-us = <400>; + }; + + stop1: stop1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <1000000>; + exit-latency-us = <600>; + }; + }; }; sram0: memory@20000000 { @@ -362,6 +383,22 @@ }; }; + pwr: power@40007000 { + compatible = "st,stm32-pwr"; + reg = <0x40007000 0x400>; /* PWR register bank */ + status = "disabled"; + + 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"; io-channels = <&adc1 16>; diff --git a/samples/boards/st/power_mgmt/wkup_pins/boards/nucleo_f103rb.overlay b/samples/boards/st/power_mgmt/wkup_pins/boards/nucleo_f103rb.overlay new file mode 100644 index 00000000000..36ae624130d --- /dev/null +++ b/samples/boards/st/power_mgmt/wkup_pins/boards/nucleo_f103rb.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 Oleh Kravchenko + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + wkup-src = &wkup_button; + }; + + gpio_keys { + wkup_button: wkup { + label = "WKUP"; + gpios = <&gpioa 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + 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 821f9d8d047..d6d697ba15d 100644 --- a/samples/boards/st/power_mgmt/wkup_pins/sample.yaml +++ b/samples/boards/st/power_mgmt/wkup_pins/sample.yaml @@ -11,5 +11,6 @@ tests: - nucleo_u575zi_q - nucleo_u5a5zj_q - nucleo_wl55jc + - nucleo_f103rb integration_platforms: - nucleo_l4r5zi diff --git a/soc/st/stm32/common/soc_config.c b/soc/st/stm32/common/soc_config.c index 07eb74a697c..7370b640e54 100644 --- a/soc/st/stm32/common/soc_config.c +++ b/soc/st/stm32/common/soc_config.c @@ -69,7 +69,11 @@ static int st_stm32_common_config(void) #if defined(CONFIG_STM32_ENABLE_DEBUG_SLEEP_STOP) -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(SOC_SERIES_STM32F1X) + LL_DBGMCU_EnableDBGSleepMode(); + LL_DBGMCU_EnableDBGStopMode(); + LL_DBGMCU_EnableDBGStandbyMode(); +#elif defined(CONFIG_SOC_SERIES_STM32H7X) LL_DBGMCU_EnableD1DebugInStopMode(); LL_DBGMCU_EnableD1DebugInSleepMode(); #elif defined(CONFIG_SOC_SERIES_STM32MP1X) @@ -85,7 +89,11 @@ static int st_stm32_common_config(void) #else /* keeping in mind that debugging draws a lot of power we explcitly disable when not needed */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(SOC_SERIES_STM32F1X) + LL_DBGMCU_DisableDBGSleepMode(); + LL_DBGMCU_DisableDBGStopMode(); + LL_DBGMCU_DisableDBGStandbyMode(); +#elif defined(CONFIG_SOC_SERIES_STM32H7X) LL_DBGMCU_DisableD1DebugInStopMode(); LL_DBGMCU_DisableD1DebugInSleepMode(); #elif defined(CONFIG_SOC_SERIES_STM32MP1X) diff --git a/soc/st/stm32/stm32f1x/CMakeLists.txt b/soc/st/stm32/stm32f1x/CMakeLists.txt index eebd281cd96..c254da84fb8 100644 --- a/soc/st/stm32/stm32f1x/CMakeLists.txt +++ b/soc/st/stm32/stm32f1x/CMakeLists.txt @@ -1,9 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_include_directories(${ZEPHYR_BASE}/drivers) -zephyr_sources( - soc.c - ) +zephyr_sources(soc.c) + +zephyr_sources_ifdef(CONFIG_PM power.c) +zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c) zephyr_include_directories(.) diff --git a/soc/st/stm32/stm32f1x/Kconfig b/soc/st/stm32/stm32f1x/Kconfig index fc6b8791acf..f94925c2b06 100644 --- a/soc/st/stm32/stm32f1x/Kconfig +++ b/soc/st/stm32/stm32f1x/Kconfig @@ -8,5 +8,7 @@ config SOC_SERIES_STM32F1X select CPU_CORTEX_M3 select CPU_CORTEX_M_HAS_DWT select HAS_STM32CUBE + select HAS_PM + select HAS_POWEROFF select HAS_SWO select SOC_EARLY_INIT_HOOK diff --git a/soc/st/stm32/stm32f1x/Kconfig.defconfig b/soc/st/stm32/stm32f1x/Kconfig.defconfig index 0ca499ef81f..132f346a571 100644 --- a/soc/st/stm32/stm32f1x/Kconfig.defconfig +++ b/soc/st/stm32/stm32f1x/Kconfig.defconfig @@ -14,4 +14,11 @@ config TASK_WDT_HW_FALLBACK_DELAY depends on TASK_WDT_HW_FALLBACK default 200 +if PM + +config COUNTER + default y + +endif # PM + endif # SOC_SERIES_STM32F1X diff --git a/soc/st/stm32/stm32f1x/power.c b/soc/st/stm32/stm32f1x/power.c new file mode 100644 index 00000000000..d00be505af7 --- /dev/null +++ b/soc/st/stm32/stm32f1x/power.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 Oleh Kravchenko + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +__weak 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) { + /* 250 uA */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_MAINREGU); + } else { + /* 245 uA */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_LPREGU); + } + + LL_LPM_EnableDeepSleep(); + k_cpu_idle(); + break; + + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +__weak 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); +} diff --git a/soc/st/stm32/stm32f1x/poweroff.c b/soc/st/stm32/stm32f1x/poweroff.c new file mode 100644 index 00000000000..343bca9c41b --- /dev/null +++ b/soc/st/stm32/stm32f1x/poweroff.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Oleh Kravchenko + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +void z_sys_poweroff(void) +{ +#ifdef CONFIG_STM32_WKUP_PINS + stm32_pwr_wkup_pin_cfg_pupd(); + + LL_PWR_ClearFlag_WU(); +#endif /* CONFIG_STM32_WKUP_PINS */ + + LL_LPM_DisableEventOnPend(); + LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY); + LL_LPM_EnableDeepSleep(); + + k_cpu_idle(); + + CODE_UNREACHABLE; +} diff --git a/soc/st/stm32/stm32f1x/soc.c b/soc/st/stm32/stm32f1x/soc.c index 72e679fd391..076b1acb4a9 100644 --- a/soc/st/stm32/stm32f1x/soc.c +++ b/soc/st/stm32/stm32f1x/soc.c @@ -13,6 +13,7 @@ #include #include +#include #include @@ -31,4 +32,8 @@ void soc_early_init_hook(void) /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 8 MHz from HSI */ SystemCoreClock = 8000000; + +#if defined(CONFIG_PM) || defined(CONFIG_POWEROFF) + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); +#endif }