samples: boards: stm32: Add a serial wakeup sample

Add a sample to demonstrate use of (LP)U(S)ART with wakeup capability
This sample is provided with 2 configurations
- nucleo_wb55rg: Basic configuration that could be exercised in CI
- stm32l562e_dk: "Full feature" configuration that require some set up
configuration (be able to display console from lpuart) and allows to
achieve lowest power consumption.

Signed-off-by: Erwan Gouriou <erwan.gouriou@linaro.org>
This commit is contained in:
Erwan Gouriou 2022-06-28 16:54:49 +02:00 committed by Fabio Baltieri
commit f5378424f7
7 changed files with 243 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_serial_wakeup)
target_sources(app PRIVATE src/main.c)

View file

@ -0,0 +1,86 @@
.. _stm32-pm-serial-wakeup-sample:
STM32 PM Serial wakeup
######################
Overview
********
This sample is a minimum application to demonstrate serial wakeup functionality
in low power context.
.. _stm32-pm-serial-wakeup-sample-requirements:
Requirements
************
1. 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`).
2. The serial port used by the shell should be configured, using device tree, to
be a functional wakeup source:
- Clocked by an oscillator available in Stop mode (LSE, LSI) or an oscillator capable
that can be requested dynamically by device on activity detection (HSI on STM32WB).
- Matching oscillator sources should be enabled
- If LSE is selected as clock source and shell serial port is a LPUART current speed
should be adapted (9600 bauds)
- Port should be set as "wakeup-source"
Note: Using HSI clock is a specific
Building and Running
********************
Build and flash this sample as follows, changing ``nucleo_wb55rg`` for a board
configured to be compatible with this sample.
.. zephyr-app-commands::
:zephyr-app: samples/boards/stm32/power_mgmt/serial_wakeup
:board: nucleo_wb55rg
:goals: build flash
:compact:
After flashing, the shell is enabled and device enter sleep mode.
User is able to wake up the device by typing into the shell
PM configurations
*****************
By default, :kconfig:option:`CONFIG_PM_DEVICE` and :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME`
are enabled, but user can also deactivate both or former to see each configuration in play.
Debugging
*********
:kconfig:option:`CONFIG_DEBUG` could be enabled to allow debug. Note that debug mode prevents
target to reach low power consumption.
Also note that after debug mode has been disabled, target should also be powered off in order
to get back to normal mode and reach low power consumption.
PM measurements on stm32l562e_dk using stm32l562e_dk PM shield
**************************************************************
Plug Power shield
Plug ST-Link
Set JP4 To 5V ST-Link
Set SW1 to PM_SEL_VDD
STM32Cube PowerMonitor settings to be applied:
- Sampling Freq: max
- Functional Mode: High
Optimal configuration for low power consumption
***********************************************
In order to reach lower power consumption numbers following parameters should be taken
into account:
- Use a LPUART instead of a basic U(S)ART node
- Chose LSE as clock source
- Ensure no other oscillators are enabled (disable HSI, ...)
- Provide "sleep" pinctrl configuration to other uart nodes.
- Disable Debug mode
With all these conditions matched, one can reach 10uA on stm32l562e_dk with this sample.

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2022 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
&clk_hsi {
status = "okay";
};
&usart1 {
clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>,
<&rcc STM32_SRC_HSI USART1_SEL(2)>;
wakeup-source;
pinctrl-1 = <&analog_pb6 &analog_pb7>;
pinctrl-names = "default", "sleep";
};

View file

@ -0,0 +1,50 @@
/ {
chosen {
/* Comment out these lines to use usart1 as console/shell */
zephyr,console = &lpuart1;
zephyr,shell-uart = &lpuart1;
};
};
&clk_lse {
status = "okay";
};
&clk_hsi {
/* Comment out this line to use HSI as clk source */
status = "disabled";
};
&lpuart1 {
pinctrl-0 = <&lpuart1_rx_pb10 &lpuart1_tx_pb11>;
pinctrl-1 = <&analog_pb10 &analog_pb11>;
pinctrl-names = "default", "sleep";
clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000001>,
<&rcc STM32_SRC_LSE LPUART1_SEL(3)>;
current-speed = <9600>;
wakeup-source;
status = "okay";
};
&usart1 {
pinctrl-1 = <&analog_pa9 &analog_pa10>;
pinctrl-names = "default", "sleep";
/* Uncomment out this line to use usart1 as wakeup source */
/* wakeup-source; */
clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>,
<&rcc STM32_SRC_HSI USART1_SEL(2)>;
status = "okay";
};
&usart3 {
status = "okay";
pinctrl-1 = <&analog_pc10 &analog_pc11>;
pinctrl-names = "default", "sleep";
};

View file

@ -0,0 +1,7 @@
CONFIG_PM=y
CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=n
CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n
CONFIG_SHELL=y
CONFIG_DEBUG=n

View file

@ -0,0 +1,17 @@
sample:
name: STM32 Power Management Serial Wakeup
tests:
sample.boards.stm32.power_mgmt.serial_wakeup:
tags: UART Wake up power
harness: console
harness_config:
type: multi_line
regex:
- "Device ready"
- "Device is wakeup capable"
- "Wakeup source enable ok"
- "Wakeup source enabled"
integration_platforms:
- nucleo_wb55rg
filter: dt_compat_enabled("zephyr,power-state")
extra_args: "CONFIG_DEBUG=y"

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2022 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/zephyr.h>
#include <zephyr/device.h>
#include <zephyr/pm/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/__assert.h>
#define DEV_NAME DT_CHOSEN(zephyr_console)
void main(void)
{
static const struct device *dev;
dev = DEVICE_DT_GET(DEV_NAME);
if (dev < 0) {
printk("Failed to get device");
}
printk("Device ready\n");
#if CONFIG_PM_DEVICE
/* In PM_DEVICE modes, enable device as a wakeup source will prevent
* system to switch it off (clock off, set pins to sleep configuration, ...)
* It is not requested in PM mode only since this mode will not
*/
bool ret;
ret = pm_device_wakeup_is_capable(dev);
if (!ret) {
printk("Device is not wakeup capable\n");
} else {
printk("Device is wakeup capable\n");
ret = pm_device_wakeup_enable(dev, true);
if (!ret) {
printk("Could not enable wakeup source\n");
} else {
printk("Wakeup source enable ok\n");
}
ret = pm_device_wakeup_is_enabled(dev);
if (!ret) {
printk("Wakeup source not enabled\n");
} else {
printk("Wakeup source enabled\n");
}
}
#endif
}