soc: stm32f1x: Add support for stop/standby modes
Add config and overlay to samples for testing stop/standby modes: - samples/boards/st/power_mgmt/blinky - samples/boards/st/power_mgmt/wkup_pins I've measured consumption for each low-power mode: - stop (regulator in run mode) ~217 uA - stop (regulator in low-power mode) ~206 uA - standby mode ~3.5 uA Low-power mode wakeup timings from the datasheet, but it barely meets these in reality: - stop (regulator in run mode) 3.6 us - stop (regulator in low-power mode) 5.4 us - standby 50 us It's possible to use RTC as idle timer to exit from stop mode. Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
This commit is contained in:
parent
90a48e814b
commit
4f69acc3d4
10 changed files with 182 additions and 5 deletions
|
@ -15,11 +15,13 @@
|
||||||
#include <zephyr/dt-bindings/adc/stm32f1_adc.h>
|
#include <zephyr/dt-bindings/adc/stm32f1_adc.h>
|
||||||
#include <zephyr/dt-bindings/reset/stm32f0_1_3_reset.h>
|
#include <zephyr/dt-bindings/reset/stm32f0_1_3_reset.h>
|
||||||
#include <zephyr/dt-bindings/adc/adc.h>
|
#include <zephyr/dt-bindings/adc/adc.h>
|
||||||
|
#include <zephyr/dt-bindings/power/stm32_pwr.h>
|
||||||
#include <freq.h>
|
#include <freq.h>
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
chosen {
|
chosen {
|
||||||
zephyr,flash-controller = &flash;
|
zephyr,flash-controller = &flash;
|
||||||
|
zephyr,cortex-m-idle-timer = &rtc;
|
||||||
};
|
};
|
||||||
|
|
||||||
cpus {
|
cpus {
|
||||||
|
@ -29,8 +31,27 @@
|
||||||
cpu0: cpu@0 {
|
cpu0: cpu@0 {
|
||||||
device_type = "cpu";
|
device_type = "cpu";
|
||||||
compatible = "arm,cortex-m3";
|
compatible = "arm,cortex-m3";
|
||||||
|
cpu-power-states = <&stop0 &stop1>;
|
||||||
reg = <0>;
|
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 {
|
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 {
|
die_temp: dietemp {
|
||||||
compatible = "st,stm32-temp";
|
compatible = "st,stm32-temp";
|
||||||
io-channels = <&adc1 16>;
|
io-channels = <&adc1 16>;
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Oleh Kravchenko <oleh@kaa.org.ua>
|
||||||
|
*
|
||||||
|
* 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 = <INPUT_KEY_POWER>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&pwr {
|
||||||
|
status = "okay";
|
||||||
|
};
|
|
@ -11,5 +11,6 @@ tests:
|
||||||
- nucleo_u575zi_q
|
- nucleo_u575zi_q
|
||||||
- nucleo_u5a5zj_q
|
- nucleo_u5a5zj_q
|
||||||
- nucleo_wl55jc
|
- nucleo_wl55jc
|
||||||
|
- nucleo_f103rb
|
||||||
integration_platforms:
|
integration_platforms:
|
||||||
- nucleo_l4r5zi
|
- nucleo_l4r5zi
|
||||||
|
|
|
@ -69,7 +69,11 @@ static int st_stm32_common_config(void)
|
||||||
|
|
||||||
#if defined(CONFIG_STM32_ENABLE_DEBUG_SLEEP_STOP)
|
#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_EnableD1DebugInStopMode();
|
||||||
LL_DBGMCU_EnableD1DebugInSleepMode();
|
LL_DBGMCU_EnableD1DebugInSleepMode();
|
||||||
#elif defined(CONFIG_SOC_SERIES_STM32MP1X)
|
#elif defined(CONFIG_SOC_SERIES_STM32MP1X)
|
||||||
|
@ -85,7 +89,11 @@ static int st_stm32_common_config(void)
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* keeping in mind that debugging draws a lot of power we explcitly disable when not needed */
|
/* 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_DisableD1DebugInStopMode();
|
||||||
LL_DBGMCU_DisableD1DebugInSleepMode();
|
LL_DBGMCU_DisableD1DebugInSleepMode();
|
||||||
#elif defined(CONFIG_SOC_SERIES_STM32MP1X)
|
#elif defined(CONFIG_SOC_SERIES_STM32MP1X)
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
zephyr_include_directories(${ZEPHYR_BASE}/drivers)
|
zephyr_include_directories(${ZEPHYR_BASE}/drivers)
|
||||||
zephyr_sources(
|
zephyr_sources(soc.c)
|
||||||
soc.c
|
|
||||||
)
|
zephyr_sources_ifdef(CONFIG_PM power.c)
|
||||||
|
zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c)
|
||||||
|
|
||||||
zephyr_include_directories(.)
|
zephyr_include_directories(.)
|
||||||
|
|
||||||
|
|
|
@ -8,5 +8,7 @@ config SOC_SERIES_STM32F1X
|
||||||
select CPU_CORTEX_M3
|
select CPU_CORTEX_M3
|
||||||
select CPU_CORTEX_M_HAS_DWT
|
select CPU_CORTEX_M_HAS_DWT
|
||||||
select HAS_STM32CUBE
|
select HAS_STM32CUBE
|
||||||
|
select HAS_PM
|
||||||
|
select HAS_POWEROFF
|
||||||
select HAS_SWO
|
select HAS_SWO
|
||||||
select SOC_EARLY_INIT_HOOK
|
select SOC_EARLY_INIT_HOOK
|
||||||
|
|
|
@ -14,4 +14,11 @@ config TASK_WDT_HW_FALLBACK_DELAY
|
||||||
depends on TASK_WDT_HW_FALLBACK
|
depends on TASK_WDT_HW_FALLBACK
|
||||||
default 200
|
default 200
|
||||||
|
|
||||||
|
if PM
|
||||||
|
|
||||||
|
config COUNTER
|
||||||
|
default y
|
||||||
|
|
||||||
|
endif # PM
|
||||||
|
|
||||||
endif # SOC_SERIES_STM32F1X
|
endif # SOC_SERIES_STM32F1X
|
||||||
|
|
65
soc/st/stm32/stm32f1x/power.c
Normal file
65
soc/st/stm32/stm32f1x/power.c
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Oleh Kravchenko <oleh@kaa.org.ua>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <clock_control/clock_stm32_ll_common.h>
|
||||||
|
#include <stm32f1xx_ll_cortex.h>
|
||||||
|
#include <stm32f1xx_ll_pwr.h>
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zephyr/pm/pm.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
28
soc/st/stm32/stm32f1x/poweroff.c
Normal file
28
soc/st/stm32/stm32f1x/poweroff.c
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Oleh Kravchenko <oleh@kaa.org.ua>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stm32f1xx_ll_cortex.h>
|
||||||
|
#include <stm32f1xx_ll_pwr.h>
|
||||||
|
|
||||||
|
#include <zephyr/drivers/misc/stm32_wkup_pins/stm32_wkup_pins.h>
|
||||||
|
#include <zephyr/sys/poweroff.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -13,6 +13,7 @@
|
||||||
#include <zephyr/init.h>
|
#include <zephyr/init.h>
|
||||||
|
|
||||||
#include <stm32_ll_system.h>
|
#include <stm32_ll_system.h>
|
||||||
|
#include <stm32f1xx_ll_bus.h>
|
||||||
|
|
||||||
#include <cmsis_core.h>
|
#include <cmsis_core.h>
|
||||||
|
|
||||||
|
@ -31,4 +32,8 @@ void soc_early_init_hook(void)
|
||||||
/* Update CMSIS SystemCoreClock variable (HCLK) */
|
/* Update CMSIS SystemCoreClock variable (HCLK) */
|
||||||
/* At reset, system core clock is set to 8 MHz from HSI */
|
/* At reset, system core clock is set to 8 MHz from HSI */
|
||||||
SystemCoreClock = 8000000;
|
SystemCoreClock = 8000000;
|
||||||
|
|
||||||
|
#if defined(CONFIG_PM) || defined(CONFIG_POWEROFF)
|
||||||
|
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue