soc: stm32l1x: Add support for sleep/stop/standby modes
Add stm32l1_disco and nucleo_l152re overlays for testing sleep/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: - low-power sleep ~1.72mA; - stop mode ~324uA; - standby mode ~2.2 uA; 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
9a9f060430
commit
585cda1360
@ -16,11 +16,13 @@
|
||||
#include <zephyr/dt-bindings/dma/stm32_dma.h>
|
||||
#include <zephyr/dt-bindings/adc/stm32f4_adc.h>
|
||||
#include <zephyr/dt-bindings/reset/stm32l1_reset.h>
|
||||
#include <zephyr/dt-bindings/power/stm32_pwr.h>
|
||||
#include <freq.h>
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zephyr,flash-controller = &flash;
|
||||
zephyr,cortex-m-idle-timer = &rtc;
|
||||
};
|
||||
|
||||
cpus {
|
||||
@ -30,10 +32,27 @@
|
||||
cpu0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-m3";
|
||||
cpu-power-states = <&sleep &stop>;
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
power-states {
|
||||
sleep: sleep {
|
||||
compatible = "zephyr,power-state";
|
||||
power-state-name = "runtime-idle";
|
||||
min-residency-us = <1000000>;
|
||||
exit-latency-us = <750>;
|
||||
};
|
||||
|
||||
stop: stop {
|
||||
compatible = "zephyr,power-state";
|
||||
power-state-name = "suspend-to-idle";
|
||||
min-residency-us = <1000000>;
|
||||
exit-latency-us = <750>;
|
||||
};
|
||||
};
|
||||
|
||||
sram0: memory@20000000 {
|
||||
compatible = "mmio-sram";
|
||||
};
|
||||
@ -81,7 +100,6 @@
|
||||
};
|
||||
|
||||
soc {
|
||||
|
||||
flash: flash-controller@40023c00 {
|
||||
compatible = "st,stm32-flash-controller", "st,stm32f1-flash-controller";
|
||||
reg = <0x40023c00 0x400>;
|
||||
@ -184,6 +202,32 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pwr: power@40007000 {
|
||||
compatible = "st,stm32-pwr";
|
||||
reg = <0x40007000 0x400>; /* PWR register bank */
|
||||
status = "disabled";
|
||||
|
||||
wkup-pins-nb = <3>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
wkup-pin@1 {
|
||||
reg = <0x1>;
|
||||
wkup-gpios = <&gpioa 0 STM32_PWR_WKUP_PIN_NOT_MUXED>;
|
||||
};
|
||||
|
||||
wkup-pin@2 {
|
||||
reg = <0x2>;
|
||||
wkup-gpios = <&gpioc 13 STM32_PWR_WKUP_PIN_NOT_MUXED>;
|
||||
};
|
||||
|
||||
wkup-pin@3 {
|
||||
reg = <0x3>;
|
||||
wkup-gpios = <&gpioe 6 STM32_PWR_WKUP_PIN_NOT_MUXED>;
|
||||
};
|
||||
};
|
||||
|
||||
spi1: spi@40013000 {
|
||||
compatible = "st,stm32-spi";
|
||||
#address-cells = <1>;
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Oleh Kravchenko <oleh@kaa.org.ua>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
wkup-src = &user_button;
|
||||
};
|
||||
};
|
||||
|
||||
&pwr {
|
||||
status = "okay";
|
||||
};
|
||||
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Oleh Kravchenko <oleh@kaa.org.ua>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
wkup-src = &user_button;
|
||||
};
|
||||
};
|
||||
|
||||
&pwr {
|
||||
status = "okay";
|
||||
};
|
||||
@ -12,5 +12,7 @@ tests:
|
||||
- nucleo_u5a5zj_q
|
||||
- nucleo_wl55jc
|
||||
- nucleo_f103rb
|
||||
- stm32l1_disco
|
||||
- nucleo_l152re
|
||||
integration_platforms:
|
||||
- nucleo_l4r5zi
|
||||
|
||||
@ -69,7 +69,7 @@ static int st_stm32_common_config(void)
|
||||
|
||||
#if defined(CONFIG_STM32_ENABLE_DEBUG_SLEEP_STOP)
|
||||
|
||||
#if defined(CONFIG_SOC_SERIES_STM32F1X)
|
||||
#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32L1X)
|
||||
LL_DBGMCU_EnableDBGSleepMode();
|
||||
LL_DBGMCU_EnableDBGStopMode();
|
||||
LL_DBGMCU_EnableDBGStandbyMode();
|
||||
@ -89,7 +89,7 @@ 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_STM32F1X)
|
||||
#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32L1X)
|
||||
LL_DBGMCU_DisableDBGSleepMode();
|
||||
LL_DBGMCU_DisableDBGStopMode();
|
||||
LL_DBGMCU_DisableDBGStandbyMode();
|
||||
|
||||
@ -1,7 +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(.)
|
||||
|
||||
|
||||
@ -7,7 +7,9 @@ config SOC_SERIES_STM32L1X
|
||||
select ARM
|
||||
select CPU_CORTEX_M3
|
||||
select CPU_CORTEX_M_HAS_DWT
|
||||
select CPU_HAS_ARM_MPU
|
||||
select HAS_PM
|
||||
select HAS_POWEROFF
|
||||
select HAS_STM32CUBE
|
||||
select HAS_SWO
|
||||
select CPU_HAS_ARM_MPU
|
||||
select SOC_EARLY_INIT_HOOK
|
||||
|
||||
@ -12,4 +12,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_STM32L1X
|
||||
|
||||
76
soc/st/stm32/stm32l1x/power.c
Normal file
76
soc/st/stm32/stm32l1x/power.c
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Oleh Kravchenko <oleh@kaa.org.ua>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <clock_control/clock_stm32_ll_common.h>
|
||||
#include <stm32l1xx_ll_cortex.h>
|
||||
#include <stm32l1xx_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_RUNTIME_IDLE:
|
||||
LL_LPM_DisableEventOnPend();
|
||||
LL_PWR_ClearFlag_WU();
|
||||
|
||||
LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_LOW_POWER);
|
||||
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP);
|
||||
LL_LPM_EnableSleep();
|
||||
|
||||
k_cpu_idle();
|
||||
break;
|
||||
|
||||
case PM_STATE_SUSPEND_TO_IDLE:
|
||||
LL_LPM_DisableEventOnPend();
|
||||
LL_PWR_ClearFlag_WU();
|
||||
|
||||
LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_LOW_POWER);
|
||||
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP);
|
||||
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_RUNTIME_IDLE:
|
||||
LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_MAIN);
|
||||
break;
|
||||
|
||||
case PM_STATE_SUSPEND_TO_IDLE:
|
||||
LL_LPM_DisableSleepOnExit();
|
||||
LL_LPM_EnableSleep();
|
||||
LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_MAIN);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
25
soc/st/stm32/stm32l1x/poweroff.c
Normal file
25
soc/st/stm32/stm32l1x/poweroff.c
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Oleh Kravchenko <oleh@kaa.org.ua>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stm32l1xx_ll_cortex.h>
|
||||
#include <stm32l1xx_ll_pwr.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/poweroff.h>
|
||||
|
||||
void z_sys_poweroff(void)
|
||||
{
|
||||
LL_PWR_ClearFlag_SB();
|
||||
LL_PWR_ClearFlag_WU();
|
||||
|
||||
LL_LPM_DisableEventOnPend();
|
||||
LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
|
||||
LL_LPM_EnableDeepSleep();
|
||||
|
||||
k_cpu_idle();
|
||||
|
||||
CODE_UNREACHABLE;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user