samples: boards: stm32: Power_mgmt: sample for standby shutdownn mode

STM32L4x power management (ultra_low_power) of Standby mode
and shutdown mode

Signed-off-by: Marc Desvaux <marc.desvaux-ext@st.com>
This commit is contained in:
Marc Desvaux 2023-03-03 09:42:48 +01:00 committed by Carles Cufí
parent ba44549ae8
commit b3f739476c
5 changed files with 232 additions and 0 deletions

View file

@ -0,0 +1,7 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(stm32_pm_standby_shutdown)
target_sources(app PRIVATE src/main.c)

View file

@ -0,0 +1,47 @@
.. _stm32-pm-standby_shutdown-sample:
STM32 PM Standby shutdown
#########################
Overview
********
This sample is a minimum application to demonstrate basic power management of Standby mode and
shutdown mode
behavior in a basic blinking LED set up you can enter in shutdown mode or in standbymode mode.
Press and hold the user button:
when LED2 is OFF to enter to Shutdown Mode
when LED2 is ON to enter to Standby Mode
release the user button to exit from shutdown mode or from shutdown mode.
.. _stm32-pm-standby_shutdown-sample-requirements:
Requirements
************
The board should support enabling PM. For a STM32 based target, it means that
it should support a clock source alternative to Cortex Systick that can be used
in core sleep states, as LPTIM (:dtcompatible:`st,stm32-lptim`).
For another board than nucleo_L476RG please adjust wakeup pin into config_wakeup_features().
Building and Running
********************
Build and flash standby_shutdown as follows, changing ``nucleo_L476RG`` for your board:
.. zephyr-app-commands::
:zephyr-app: samples/samples/boards/stm32/power_mgmt/standby_shutdown
:board: nucleo_L476RG
:goals: build flash
:compact:
After flashing, the LED starts to blink.
Press and hold the user button:
when LED2 is OFF to enter to Shutdown Mode
when LED2 is ON to enter to Standby Mode
release the user button to exit from shutdown mode or from shutdown mode.
PM configurations
*****************
By default, :kconfig:option:`CONFIG_PM` is enabled.

View file

@ -0,0 +1,4 @@
CONFIG_PM=y
CONFIG_PM_DEVICE=n
CONFIG_PM_DEVICE_RUNTIME=n
CONFIG_HWINFO=y

View file

@ -0,0 +1,19 @@
sample:
name: STM32 GPIO Power Management
tests:
sample.boards.stm32.power_mgmt.standby_shutdown:
platform_allow: nucleo_l476rg disco_l475_iot1
tags: LED power
harness: console
harness_config:
type: multi_line
regex:
- "Reset cause: Reset pin"
- "Device ready: .*"
- "Press and hold the user button:"
- "when LED2 is OFF to enter to Shutdown Mode"
- "when LED2 is ON to enter to Standby Mode"
filter: dt_compat_enabled("zephyr,power-state") and
dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and
dt_compat_enabled("st,stm32-lptim")
extra_args: "CONFIG_DEBUG=y"

View file

@ -0,0 +1,155 @@
/*
* Copyright (c) 2023 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/hwinfo.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/printk.h>
#include <zephyr/pm/pm.h>
#include <stm32_ll_pwr.h>
#if !defined(CONFIG_SOC_SERIES_STM32L4X)
#error Not implemented for other series
#endif /* CONFIG_SOC_SERIES_STM32L4X */
#define STACKSIZE 1024
#define PRIORITY 7
#define SLEEP_TIME_MS 3000
#define SW0_NODE DT_ALIAS(sw0)
#if !DT_NODE_HAS_STATUS(SW0_NODE, okay)
#error "Unsupported board: sw0 devicetree alias is not defined"
#endif
/* Semaphore used to control button pressed value */
static struct k_sem button_sem;
static int led_is_on;
static const struct gpio_dt_spec button =
GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0});
static const struct gpio_dt_spec led =
GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
static struct gpio_callback button_cb_data;
void config_wakeup_features(void)
{
/* Configure wake-up features */
/* WKUP2(PC13) only , - active low, pull-up */
/* Set pull-ups for standby modes */
LL_PWR_EnableGPIOPullUp(LL_PWR_GPIO_C, LL_PWR_GPIO_BIT_13);
LL_PWR_IsWakeUpPinPolarityLow(LL_PWR_WAKEUP_PIN2);
/* Enable pin pull up configurations and wakeup pins */
LL_PWR_EnablePUPDCfg();
LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN2);
/* Clear wakeup flags */
LL_PWR_ClearFlag_WU();
}
void button_pressed(const struct device *dev, struct gpio_callback *cb,
uint32_t pins)
{
k_sem_give(&button_sem);
}
void thread_shutdown_standby_mode(void)
{
k_sem_init(&button_sem, 0, 1);
k_sem_take(&button_sem, K_FOREVER);
gpio_pin_configure(led.port, led.pin, GPIO_DISCONNECTED);
printk("User button pressed\n");
config_wakeup_features();
if (led_is_on == false) {
printk("Shutdown Mode requested\n");
printk("Release the user button to exit from Shutdown Mode\n\n");
#ifdef CONFIG_LOG
k_msleep(2000);
#endif /* CONFIG_LOG */
pm_state_force(0u, &(struct pm_state_info) {PM_STATE_SOFT_OFF, 0, 0});
/* stay in Shutdown mode until wakeup line activated */
} else {
printk("Standby Mode requested\n");
printk("Release the user button to exit from Standby Mode\n\n");
#ifdef CONFIG_LOG
k_msleep(2000);
#endif /* CONFIG_LOG */
pm_state_force(0u, &(struct pm_state_info) {PM_STATE_STANDBY, 0, 0});
/* stay in Standby mode until wakeup line activated */
}
}
K_THREAD_DEFINE(thread_shutdown_standby_mode_id, STACKSIZE, thread_shutdown_standby_mode,
NULL, NULL, NULL, PRIORITY, 0, 0);
void main(void)
{
int ret;
uint32_t cause;
hwinfo_get_reset_cause(&cause);
hwinfo_clear_reset_cause();
if ((LL_PWR_IsActiveFlag_SB() == true) && (cause == 0)) {
LL_PWR_ClearFlag_SB();
LL_PWR_ClearFlag_WU();
printk("\nReset cause: Standby mode\n\n");
}
if (cause == (RESET_PIN | RESET_BROWNOUT)) {
LL_PWR_ClearFlag_WU();
printk("\nReset cause: Shutdown mode or power up\n\n");
}
if (cause == RESET_PIN) {
LL_PWR_ClearFlag_WU();
printk("\nReset cause: Reset pin\n\n");
}
__ASSERT_NO_MSG(device_is_ready(led.port));
if (!gpio_is_ready_dt(&button)) {
printk("Error: button device %s is not ready\n",
button.port->name);
return;
}
ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
if (ret != 0) {
printk("Error %d: failed to configure %s pin %d\n",
ret, button.port->name, button.pin);
return;
}
ret = gpio_pin_interrupt_configure_dt(&button,
GPIO_INT_EDGE_TO_ACTIVE);
if (ret != 0) {
printk("Error %d: failed to configure interrupt on %s pin %d\n",
ret, button.port->name, button.pin);
return;
}
gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
gpio_add_callback(button.port, &button_cb_data);
printk("Device ready: %s\n\n\n", CONFIG_BOARD);
printk("Press and hold the user button:\n");
printk(" when LED2 is OFF to enter to Shutdown Mode\n");
printk(" when LED2 is ON to enter to Standby Mode\n\n");
led_is_on = true;
while (true) {
gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
gpio_pin_set(led.port, led.pin, (int)led_is_on);
k_msleep(SLEEP_TIME_MS);
led_is_on = !led_is_on;
}
}