-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stm32: power: system power management support #14066
Comments
This is a much-needed feature by many, us included. Proper power management support would also require device power management and is not a trivial effort. However, maybe it would be possible to at least add an example implementing the needed functions out-of-tree, with a plain sample application. |
The Zephyr Power Management support seems to be under changes for this period. Locally, I have some samples consindering entering/exiting to/from LPMs on STM32L4, but they use the STM32 LL drivers. If you want me to upload anything in my local Zephyr fork, let me know. Otherwise, I'm planning to create a PR on this, utilizing Zephyr Power Management. |
@gon1332 I also have a somewhat-working sample for STOP1/STOP2 -- let's compare notes and maybe collaborate on a PR which shows how to do the basic power management integration. The issues I'm facing are around systick management and device power states. |
@kzyapkov I agree the STOP modes, due to the fact that the system doesn't reset (as in Standby or Shutdown) are a bit tricky. That's because, one should set the clock frequency and the systick appropriately after exiting from them. As for the device power management, I haven't gone deeper. So yes, we can share some knowledge. Maybe a PR would be perfect. |
Hi. @kzyapkov, @gon1332 @kzyapkov, |
@KwonTae-young |
I tested the STOP1/STOP2 does not exist in STM32F4. /** @defgroup PWR_LL_EC_MODE_PWR Mode Power
* @{
*/
#define LL_PWR_MODE_STOP_MAINREGU 0x00000000U /*!< Enter Stop mode when the CPU enters deepsleep */
#define LL_PWR_MODE_STOP_LPREGU (PWR_CR_LPDS) /*!< Enter Stop mode (with low power Regulator ON) when the CPU enters deepsleep */
#if defined(PWR_CR_MRUDS) && defined(PWR_CR_LPUDS) && defined(PWR_CR_FPDS)
#define LL_PWR_MODE_STOP_MAINREGU_UNDERDRIVE (PWR_CR_MRUDS | PWR_CR_FPDS) /*!< Enter Stop mode (with main Regulator in under-drive mode) when the CPU enters deepsleep */
#define LL_PWR_MODE_STOP_LPREGU_UNDERDRIVE (PWR_CR_LPDS | PWR_CR_LPUDS | PWR_CR_FPDS) /*!< Enter Stop mode (with low power Regulator in under-drive mode) when the CPU enters deepsleep */
#endif /* PWR_CR_MRUDS && PWR_CR_LPUDS && PWR_CR_FPDS */
#if defined(PWR_CR_MRLVDS) && defined(PWR_CR_LPLVDS) && defined(PWR_CR_FPDS)
#define LL_PWR_MODE_STOP_MAINREGU_DEEPSLEEP (PWR_CR_MRLVDS | PWR_CR_FPDS) /*!< Enter Stop mode (with main Regulator in Deep Sleep mode) when the CPU enters deepsleep */
#define LL_PWR_MODE_STOP_LPREGU_DEEPSLEEP (PWR_CR_LPDS | PWR_CR_LPLVDS | PWR_CR_FPDS) /*!< Enter Stop mode (with low power Regulator in Deep Sleep mode) when the CPU enters deepsleep */
#endif /* PWR_CR_MRLVDS && PWR_CR_LPLVDS && PWR_CR_FPDS */
#define LL_PWR_MODE_STANDBY (PWR_CR_PDDS) /*!< Enter Standby mode when the CPU enters deepsleep */ The source of the tested program is shown below.
#include <zephyr.h>
#include <misc/printk.h>
#include <stm32f4xx_ll_pwr.h>
#include <stm32f4xx_ll_cortex.h>
#include <device.h>
#include <gpio.h>
static struct device *gpioa;
static struct gpio_callback gpiocb;
static struct k_timer timer;
static int standby_mode_cnt = 0;
void sleep_mode_button(struct device *gpioc, struct gpio_callback *cb,
uint32_t pins)
{
k_timer_start(&timer, 100, 0);
}
void configure_gpio(void)
{
gpioa = device_get_binding("GPIOA");
if (!gpioa) {
printk("Error\n");
return;
}
gpio_pin_configure(gpioa, 0, GPIO_DIR_IN
| GPIO_INT | GPIO_INT_EDGE
| GPIO_INT_ACTIVE_HIGH);
gpio_init_callback(&gpiocb, sleep_mode_button, BIT(0));
gpio_add_callback(gpioa, &gpiocb);
gpio_pin_enable_callback(gpioa, 0);
}
/*
* Press and hold the user button(LL_PWR_WAKEUP_PIN1: PA0) for 3 seconds to enter standby mode.
*/
static void sleep_mode_timer(struct k_timer *work)
{
int value;
gpio_pin_read(gpioa, 0, &value);
if (value == 1) {
standby_mode_cnt++;
if (standby_mode_cnt == 30) {
/*
* In stm32f4_disco, LL_PWR_WAKEUP_PIN1 is PA0.
* PA0 is also built in as a User Button.
*/
LL_PWR_DisableWakeUpPin(LL_PWR_WAKEUP_PIN1);
LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN1);
LL_PWR_ClearFlag_WU();
if (LL_PWR_IsActiveFlag_WU()) {
LL_PWR_ClearFlag_WU();
}
LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
printk("Now call LL_LPM_EnableDeepSleep().\n");
LL_LPM_EnableDeepSleep();
}
k_timer_start(&timer, 100, 0);
} else {
standby_mode_cnt = 0;
}
}
void main(void)
{
printk("standby mode test: %s\n", CONFIG_BOARD);
configure_gpio();
k_timer_init(&timer, sleep_mode_timer, NULL);
while (1) {
k_sleep(1000);
printk("You can not see this message in standby mode.\n");
}
} The operation is shown in the following video.
EDIT: The source has been uploaded to my lpm_stm32 branch. |
@KwonTae-young That's the spirit. :) |
I tested One strange thing was that I woke up from `STOP mode' automatically after about 1 second even though I did not issue an interrupt. /*
* When the user button interrupts, it wakes up in STOP mode.
* However, STOP Mode is automatically released after about 1 second even if the User Button does not generate an interrupt.
* I thought there was a hardware interrupt that I do not know.
* So I disabled SYSTICK by referring to https://community.st.com/s/question/0D50X00009XkXphSAF/unwanted-stop-mode-wakeup-stm32l052k8.
* I do not know the exact reason yet.
*/
LL_SYSTICK_DisableIT(); Below is a test video. |
@KwonTae-young I remember experiencing the same behaviour but with Standby mode. So I clear my wake up flags on initialization, eg. if (LL_PWR_IsActiveFlag_WU2()) {
LL_PWR_ClearFlag_WU2();
} |
@gon1332 if (LL_PWR_IsActiveFlag_WU()) {
LL_PWR_ClearFlag_WU();
} However, there is no effect on |
Yes, the systick remains ticking in stop mode for some reason. If you have logging enabled, it schedules a wakeup every second: https://github.com/zephyrproject-rtos/zephyr/blob/master/subsys/logging/log_core.c#L685 but even without async logging I see wakeups every second. So one must stop the systick for stop mode and then re-enable it on wakeup. I see other platforms have alternative systick sources (like nrf_rtc_timer). So an alternative timer should be used while the systick is stopped, and the passed time should be z_clock_announce()-d. I could not get this to work reliably though. |
@kzyapkov /* Invoke Low Power/System Off specific Tasks */
void sys_set_power_state(enum power_states state)
{
switch (state) {
#ifdef CONFIG_SYS_POWER_DEEP_SLEEP
#ifdef CONFIG_SYS_POWER_STATE_DEEP_SLEEP_SUPPORTED
case SYS_POWER_STATE_DEEP_SLEEP:
/* Enable Backup Access for RTC registers */
// LL_PWR_EnableBkUpAccess();
/*
* Configure wake up sources
*/
/* Disable all used wakeup sources: WKUP pin*/
LL_PWR_DisableWakeUpPin(LL_PWR_WAKEUP_PIN2);
/* Clear wakeup Flag */
LL_PWR_ClearFlag_WU2();
LL_PWR_SetWakeUpPinPolarityHigh(LL_PWR_WAKEUP_PIN2);
/* Enable wakeup pin WKUP2 */
LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN2);
/*
* Enter Standby mode
*/
/* Set STANDBY mode when CPU enters deepsleep */
LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
/* Set SLEEPDEEP bit of Cortex System Control Register */
LL_LPM_EnableDeepSleep();
/* Request Wait For Interrupt */
__WFI();
break;
#endif
#endif
default:
LOG_ERR("Unsupported power state %u", state);
break;
}
} |
Has there been any movement on creating a PR for this? I can help test on the STM32L4+ series. |
^^@FRASTM |
@KwonTae-young, @kzyapkov, @gon1332, @psidhu: We're starting to investigate zephyr power management support for STM32, with a first focus on STM32WB. Since this is a pretty wide topic and there are many possible use cases and ways to implement them, we'd like to have information about the use cases STM32 users would be interested to use in Zephyr. It would be nice to have an overview of the use cases you'd like to be supported, with, for each use case:
Thanks |
@erwango Hi. Thanks for taking the time to get into this. I'm actually thinking of using the STM32WB55 for my next project, but I'll need to investigating FCC etc licensing first (needs to be pre-certified). Anyways, what I mean is I can help when possible.
I think this is most important if going into Standby mode. I'm not sure how it's done today in Zephyr, but I would assume that a 'parent' peripheral can't be suspended until child nodes are suspended (SPI devices, then the SPI peripheral itself). Having power 'profiles' that are on-the-fly configurable would support this very well. E.g. keep bt le radio on if connected when going to STOP1, but off if nothing was connected before going to STOP1. Application code could configure this.
A configurable sleep duration that is cancelled if woken early is important. Specifically using RTC alarms, even in shutdown mode. This may have to be a manual step.
Configuring these before sleep is important to me (EXTI or WKUP pins).
Going into Standby/Shutdown mode is required, with a continuous LSE so the RTC stays alive. On wake, don't erase current date. Going into at least STOP1 and STOP2 is required I think. Imagine a sensor device that wakes every .1s to take a reading and go back into STOP2. When a user comes along to wake it, they can grab sensor data (e.g. connect via Bluetooth). I think it would be interesting to have a method to switch from Run to Low-Power Run modes. I'm not sure how the clocking should get done as there's no real clock tree configuration in Zephyr today. |
Thanks for the time to get our opinions.
Like @psidhu
We use both fixed and unfixed sleep duration. Unfixed sleep duration is used e.g. when we want the device to be waken up from a radio module, when the network is awake, or a sensor that has a strange reading. OTOH, fixed sleep duration are implemented with the help of RTC.
It is crucial to know who woke up the device. In most, if not all cases, more than one peripherals would wake up a device, so like @psidhu
We are mainly using |
@KwonTae-young thx for open this topic. Since the last post has some time passed. |
@erwango
In all cases, it would be helpfull to have possibility to configure main clock after wake-up (static onfiguration or callback). I.e. in my case I need aways to switch to the highest clock (64MHz from PLL). Additionally there is also a deep sleep use case:
|
Thanks all for the inputs.
This is starting in following PR: #18582 |
For all who needs to deal with the stm32F4xx series. I figured out a work around. It's a bit dirty but it works well for me. I put the blueprint of the solution to my answer on StackOverflow: @erwango I am excited to see the official solution. |
I have a PR #19026 for adding the low power on stm32l4r5. This is based on a low power timer LPTIM and supports SLEEP Mode 1,2,3 as STOP 0,1,2 |
@KwonTae-young I propose to close this point. |
Is your feature request related to a problem? Please describe.
STM32
soc must be able to use thesystem power management
function.Describe the solution you'd like
I would like to switch between
sleep mode
,stop mode
, andstandby mode
in the application.Describe alternatives you've considered
I want to use the
system power management
function inSTM32
in the form samples/boards/nrf52/power_mgr.Additional context
I have tried testing
system power management
with stm32f4_disco.What I want to do is switch and recover the sleep mode in the application.
I have enabled the
CONFIG_SYS_POWER_MANAGEMENT
setting in Zephyr's Kernel configuration.And when I try to compile, the following error is output.
I searched soc that supports
system power management
with the following command.As far as I'm concerned, I think that only
nordic
andsilabs
are currently supported.(ARM)Does the
STM32
platform currently supportsystem power management
?Or is it an error due to the immaturity of my Zephyr usage?
I'm sorry I do not have enough English.
Thank you.
The text was updated successfully, but these errors were encountered: