From b3f739476c35922888a3dc1a8b7f86cbef2cae67 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Fri, 3 Mar 2023 09:42:48 +0100 Subject: [PATCH] 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 --- .../standby_shutdown/CMakeLists.txt | 7 + .../power_mgmt/standby_shutdown/README.rst | 47 ++++++ .../power_mgmt/standby_shutdown/prj.conf | 4 + .../power_mgmt/standby_shutdown/sample.yaml | 19 +++ .../power_mgmt/standby_shutdown/src/main.c | 155 ++++++++++++++++++ 5 files changed, 232 insertions(+) create mode 100644 samples/boards/stm32/power_mgmt/standby_shutdown/CMakeLists.txt create mode 100644 samples/boards/stm32/power_mgmt/standby_shutdown/README.rst create mode 100644 samples/boards/stm32/power_mgmt/standby_shutdown/prj.conf create mode 100644 samples/boards/stm32/power_mgmt/standby_shutdown/sample.yaml create mode 100644 samples/boards/stm32/power_mgmt/standby_shutdown/src/main.c diff --git a/samples/boards/stm32/power_mgmt/standby_shutdown/CMakeLists.txt b/samples/boards/stm32/power_mgmt/standby_shutdown/CMakeLists.txt new file mode 100644 index 00000000000..b583c9a246f --- /dev/null +++ b/samples/boards/stm32/power_mgmt/standby_shutdown/CMakeLists.txt @@ -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) diff --git a/samples/boards/stm32/power_mgmt/standby_shutdown/README.rst b/samples/boards/stm32/power_mgmt/standby_shutdown/README.rst new file mode 100644 index 00000000000..3efd2b08a93 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/standby_shutdown/README.rst @@ -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. diff --git a/samples/boards/stm32/power_mgmt/standby_shutdown/prj.conf b/samples/boards/stm32/power_mgmt/standby_shutdown/prj.conf new file mode 100644 index 00000000000..738c014c57a --- /dev/null +++ b/samples/boards/stm32/power_mgmt/standby_shutdown/prj.conf @@ -0,0 +1,4 @@ +CONFIG_PM=y +CONFIG_PM_DEVICE=n +CONFIG_PM_DEVICE_RUNTIME=n +CONFIG_HWINFO=y diff --git a/samples/boards/stm32/power_mgmt/standby_shutdown/sample.yaml b/samples/boards/stm32/power_mgmt/standby_shutdown/sample.yaml new file mode 100644 index 00000000000..b4d610de660 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/standby_shutdown/sample.yaml @@ -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" diff --git a/samples/boards/stm32/power_mgmt/standby_shutdown/src/main.c b/samples/boards/stm32/power_mgmt/standby_shutdown/src/main.c new file mode 100644 index 00000000000..118ecaafc7f --- /dev/null +++ b/samples/boards/stm32/power_mgmt/standby_shutdown/src/main.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + } + +}