Skip to content

Commit 56e8801

Browse files
gautierg-stpdgendt
authored andcommitted
samples: boards: stm32: pm: suspend_to_ram: add wba standby sample
Add a sample for STM32WBA standby power management. Signed-off-by: Guillaume Gautier <[email protected]>
1 parent d3d23be commit 56e8801

File tree

6 files changed

+286
-0
lines changed

6 files changed

+286
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
5+
project(stm32_pm_suspend_to_ram)
6+
7+
target_sources(app PRIVATE src/main.c)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.. _stm32-pm-suspend-to-ram-sample:
2+
3+
STM32 PM Suspend to RAM
4+
#######################
5+
6+
Overview
7+
********
8+
9+
This sample is a minimum application to demonstrate basic power management
10+
behavior in a basic blinking LED set up using the :ref:`GPIO API <gpio_api>` in
11+
low power context + ADC measurements and entropy.
12+
13+
.. _stm32-pm-suspend-to-ram-sample-requirements:
14+
15+
Requirements
16+
************
17+
18+
The board should support enabling PM. For a STM32 based target, it means that
19+
it should support a clock source alternative to Cortex Systick that can be used
20+
in core sleep states, as LPTIM (:dtcompatible:`st,stm32-lptim`).
21+
The board shall have an RTC to use it during the standby mode as a replacement
22+
for LPTIM (which is disabled). The board shall also have RAM retention to be
23+
able to restore context after standby.
24+
25+
Building and Running
26+
********************
27+
28+
Build and flash Blinky as follows, changing ``stm32wba55cg`` for your board:
29+
30+
.. zephyr-app-commands::
31+
:zephyr-app: samples/boards/stm32/power_mgmt/suspend_to_ram
32+
:board: stm32wba55cg
33+
:goals: build flash
34+
:compact:
35+
36+
After flashing, the LED starts to blink.
37+
38+
PM configurations
39+
*****************
40+
41+
By default, :kconfig:option:`CONFIG_PM_DEVICE` and :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME`
42+
are enabled.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* Copyright (c) 2023 STMicroelectronics
5+
*/
6+
7+
/ {
8+
/* Change min residency time to ease power consumption measurement */
9+
cpus {
10+
power-states {
11+
stop0: state0 {
12+
min-residency-us = <500000>;
13+
exit-latency-us = <50>;
14+
};
15+
stop1: state1 {
16+
min-residency-us = <1000000>;
17+
exit-latency-us = <100>;
18+
};
19+
standby: state2 {
20+
min-residency-us = <2000000>;
21+
exit-latency-us = <1000>;
22+
};
23+
};
24+
};
25+
26+
zephyr,user {
27+
/* adjust channel number according to pinmux in board.dts */
28+
io-channels = <&adc4 8>;
29+
};
30+
};
31+
32+
&lptim1 {
33+
status = "okay";
34+
};
35+
36+
&adc4 {
37+
pinctrl-0 = <&adc4_in8_pa1>;
38+
#address-cells = <1>;
39+
#size-cells = <0>;
40+
41+
channel@8 {
42+
reg = <8>;
43+
zephyr,gain = "ADC_GAIN_1";
44+
zephyr,reference = "ADC_REF_INTERNAL";
45+
zephyr,acquisition-time = <ADC_ACQ_TIME_MAX>;
46+
zephyr,resolution = <12>;
47+
};
48+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CONFIG_PM=y
2+
CONFIG_PM_DEVICE=y
3+
CONFIG_PM_DEVICE_RUNTIME=y
4+
CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n
5+
CONFIG_PM_S2RAM=y
6+
CONFIG_ADC=y
7+
CONFIG_ENTROPY_GENERATOR=y
8+
#CONFIG_DEBUG=y
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
sample:
2+
name: STM32 PM Standby Power Management
3+
tests:
4+
sample.boards.stm32.power_mgmt.suspend_to_ram:
5+
tags:
6+
- power
7+
harness: console
8+
harness_config:
9+
type: one_line
10+
regex:
11+
- "Exit Standby"
12+
filter: dt_compat_enabled("zephyr,power-state") and
13+
dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and
14+
dt_compat_enabled("st,stm32-lptim")
15+
extra_args: "CONFIG_DEBUG=y"
16+
platform_allow:
17+
- nucleo_wba55cg
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright (c) 2024 STMicroelectronics
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/device.h>
9+
#include <zephyr/devicetree.h>
10+
#include <zephyr/drivers/gpio.h>
11+
#include <zephyr/sys/printk.h>
12+
#include <zephyr/pm/pm.h>
13+
#include <zephyr/pm/device_runtime.h>
14+
#include <zephyr/drivers/adc.h>
15+
#include <zephyr/drivers/entropy.h>
16+
#include <string.h>
17+
18+
#define SLEEP_TIME_STOP0_MS 800
19+
#define SLEEP_TIME_STOP1_MS 1500
20+
#define SLEEP_TIME_STANDBY_MS 3000
21+
#define SLEEP_TIME_BUSY_MS 2000
22+
23+
static const struct gpio_dt_spec led =
24+
GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
25+
26+
#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \
27+
!DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
28+
#error "No suitable devicetree overlay specified"
29+
#endif
30+
31+
#define DT_SPEC_AND_COMMA(node_id, prop, idx) \
32+
ADC_DT_SPEC_GET_BY_IDX(node_id, idx),
33+
34+
/* Data of ADC io-channels specified in devicetree. */
35+
static const struct adc_dt_spec adc_channels[] = {
36+
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels,
37+
DT_SPEC_AND_COMMA)
38+
};
39+
40+
const struct device *rng_dev;
41+
42+
#define BUFFER_LENGTH 3
43+
44+
static uint8_t entropy_buffer[BUFFER_LENGTH] = {0};
45+
46+
static int adc_test(void)
47+
{
48+
int err;
49+
static uint32_t count;
50+
uint16_t buf;
51+
struct adc_sequence sequence = {
52+
.buffer = &buf,
53+
/* buffer size in bytes, not number of samples */
54+
.buffer_size = sizeof(buf),
55+
};
56+
57+
/* Configure channels individually prior to sampling. */
58+
for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
59+
if (!adc_is_ready_dt(&adc_channels[i])) {
60+
printk("ADC controller device %s not ready\n", adc_channels[i].dev->name);
61+
return 0;
62+
}
63+
64+
err = adc_channel_setup_dt(&adc_channels[i]);
65+
if (err < 0) {
66+
printk("Could not setup channel #%d (%d)\n", i, err);
67+
return 0;
68+
}
69+
}
70+
71+
printk("ADC reading[%u]:\n", count++);
72+
for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
73+
int32_t val_mv;
74+
75+
printk("- %s, channel %d: ",
76+
adc_channels[i].dev->name,
77+
adc_channels[i].channel_id);
78+
79+
(void)adc_sequence_init_dt(&adc_channels[i], &sequence);
80+
81+
err = adc_read_dt(&adc_channels[i], &sequence);
82+
if (err < 0) {
83+
printk("Could not read (%d)\n", err);
84+
continue;
85+
}
86+
87+
/*
88+
* If using differential mode, the 16 bit value
89+
* in the ADC sample buffer should be a signed 2's
90+
* complement value.
91+
*/
92+
if (adc_channels[i].channel_cfg.differential) {
93+
val_mv = (int32_t)((int16_t)buf);
94+
} else {
95+
val_mv = (int32_t)buf;
96+
}
97+
printk("%"PRId32, val_mv);
98+
err = adc_raw_to_millivolts_dt(&adc_channels[i],
99+
&val_mv);
100+
/* conversion to mV may not be supported, skip if not */
101+
if (err < 0) {
102+
printk(" (value in mV not available)\n");
103+
} else {
104+
printk(" = %"PRId32" mV\n", val_mv);
105+
}
106+
}
107+
108+
return 0;
109+
}
110+
111+
void print_buf(uint8_t *buffer)
112+
{
113+
int i;
114+
int count = 0;
115+
116+
for (i = 0; i < BUFFER_LENGTH; i++) {
117+
printk(" 0x%02x", buffer[i]);
118+
if (buffer[i] == 0x00) {
119+
count++;
120+
}
121+
}
122+
printk("\n");
123+
}
124+
125+
int main(void)
126+
{
127+
__ASSERT_NO_MSG(gpio_is_ready_dt(&led));
128+
129+
rng_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy));
130+
if (!device_is_ready(rng_dev)) {
131+
printk("error: random device not ready");
132+
}
133+
134+
printk("Device ready\n");
135+
136+
while (true) {
137+
gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
138+
adc_test();
139+
k_busy_wait(SLEEP_TIME_BUSY_MS*1000);
140+
gpio_pin_set_dt(&led, 0);
141+
k_msleep(SLEEP_TIME_STOP0_MS);
142+
printk("Exit Stop0\n");
143+
144+
gpio_pin_set_dt(&led, 1);
145+
adc_test();
146+
k_busy_wait(SLEEP_TIME_BUSY_MS*1000);
147+
gpio_pin_set_dt(&led, 0);
148+
k_msleep(SLEEP_TIME_STOP1_MS);
149+
printk("Exit Stop1\n");
150+
151+
(void)memset(entropy_buffer, 0x00, BUFFER_LENGTH);
152+
entropy_get_entropy(rng_dev, (char *)entropy_buffer, BUFFER_LENGTH);
153+
printk("Sync entropy: ");
154+
print_buf(entropy_buffer);
155+
156+
gpio_pin_set_dt(&led, 1);
157+
adc_test();
158+
k_busy_wait(SLEEP_TIME_BUSY_MS*1000);
159+
gpio_pin_configure_dt(&led, GPIO_DISCONNECTED);
160+
k_msleep(SLEEP_TIME_STANDBY_MS);
161+
printk("Exit Standby\n");
162+
}
163+
return 0;
164+
}

0 commit comments

Comments
 (0)