samples: boards: stm32: pm: suspend_to_ram: add wba standby sample
Add a sample for STM32WBA standby power management. Signed-off-by: Guillaume Gautier <guillaume.gautier-ext@st.com>
This commit is contained in:
parent
7ba1f2e6d8
commit
05712250ea
6 changed files with 286 additions and 0 deletions
|
@ -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_suspend_to_ram)
|
||||||
|
|
||||||
|
target_sources(app PRIVATE src/main.c)
|
42
samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst
Normal file
42
samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
.. _stm32-pm-suspend-to-ram-sample:
|
||||||
|
|
||||||
|
STM32 PM Suspend to RAM
|
||||||
|
#######################
|
||||||
|
|
||||||
|
Overview
|
||||||
|
********
|
||||||
|
|
||||||
|
This sample is a minimum application to demonstrate basic power management
|
||||||
|
behavior in a basic blinking LED set up using the :ref:`GPIO API <gpio_api>` in
|
||||||
|
low power context + ADC measurements and entropy.
|
||||||
|
|
||||||
|
.. _stm32-pm-suspend-to-ram-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`).
|
||||||
|
The board shall have an RTC to use it during the standby mode as a replacement
|
||||||
|
for LPTIM (which is disabled). The board shall also have RAM retention to be
|
||||||
|
able to restore context after standby.
|
||||||
|
|
||||||
|
Building and Running
|
||||||
|
********************
|
||||||
|
|
||||||
|
Build and flash Blinky as follows, changing ``stm32wba55cg`` for your board:
|
||||||
|
|
||||||
|
.. zephyr-app-commands::
|
||||||
|
:zephyr-app: samples/boards/stm32/power_mgmt/suspend_to_ram
|
||||||
|
:board: stm32wba55cg
|
||||||
|
:goals: build flash
|
||||||
|
:compact:
|
||||||
|
|
||||||
|
After flashing, the LED starts to blink.
|
||||||
|
|
||||||
|
PM configurations
|
||||||
|
*****************
|
||||||
|
|
||||||
|
By default, :kconfig:option:`CONFIG_PM_DEVICE` and :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME`
|
||||||
|
are enabled.
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 STMicroelectronics
|
||||||
|
*/
|
||||||
|
|
||||||
|
/ {
|
||||||
|
/* Change min residency time to ease power consumption measurement */
|
||||||
|
cpus {
|
||||||
|
power-states {
|
||||||
|
stop0: state0 {
|
||||||
|
min-residency-us = <500000>;
|
||||||
|
exit-latency-us = <50>;
|
||||||
|
};
|
||||||
|
stop1: state1 {
|
||||||
|
min-residency-us = <1000000>;
|
||||||
|
exit-latency-us = <100>;
|
||||||
|
};
|
||||||
|
standby: state2 {
|
||||||
|
min-residency-us = <2000000>;
|
||||||
|
exit-latency-us = <1000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
zephyr,user {
|
||||||
|
/* adjust channel number according to pinmux in board.dts */
|
||||||
|
io-channels = <&adc4 8>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&lptim1 {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&adc4 {
|
||||||
|
pinctrl-0 = <&adc4_in8_pa1>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
channel@8 {
|
||||||
|
reg = <8>;
|
||||||
|
zephyr,gain = "ADC_GAIN_1";
|
||||||
|
zephyr,reference = "ADC_REF_INTERNAL";
|
||||||
|
zephyr,acquisition-time = <ADC_ACQ_TIME_MAX>;
|
||||||
|
zephyr,resolution = <12>;
|
||||||
|
};
|
||||||
|
};
|
8
samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf
Normal file
8
samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
CONFIG_PM=y
|
||||||
|
CONFIG_PM_DEVICE=y
|
||||||
|
CONFIG_PM_DEVICE_RUNTIME=y
|
||||||
|
CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n
|
||||||
|
CONFIG_PM_S2RAM=y
|
||||||
|
CONFIG_ADC=y
|
||||||
|
CONFIG_ENTROPY_GENERATOR=y
|
||||||
|
#CONFIG_DEBUG=y
|
17
samples/boards/stm32/power_mgmt/suspend_to_ram/sample.yaml
Normal file
17
samples/boards/stm32/power_mgmt/suspend_to_ram/sample.yaml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
sample:
|
||||||
|
name: STM32 PM Standby Power Management
|
||||||
|
tests:
|
||||||
|
sample.boards.stm32.power_mgmt.suspend_to_ram:
|
||||||
|
tags:
|
||||||
|
- power
|
||||||
|
harness: console
|
||||||
|
harness_config:
|
||||||
|
type: one_line
|
||||||
|
regex:
|
||||||
|
- "Exit Standby"
|
||||||
|
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"
|
||||||
|
platform_allow:
|
||||||
|
- nucleo_wba55cg
|
164
samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c
Normal file
164
samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 STMicroelectronics
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 <zephyr/pm/device_runtime.h>
|
||||||
|
#include <zephyr/drivers/adc.h>
|
||||||
|
#include <zephyr/drivers/entropy.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define SLEEP_TIME_STOP0_MS 800
|
||||||
|
#define SLEEP_TIME_STOP1_MS 1500
|
||||||
|
#define SLEEP_TIME_STANDBY_MS 3000
|
||||||
|
#define SLEEP_TIME_BUSY_MS 2000
|
||||||
|
|
||||||
|
static const struct gpio_dt_spec led =
|
||||||
|
GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
|
||||||
|
|
||||||
|
#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \
|
||||||
|
!DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
|
||||||
|
#error "No suitable devicetree overlay specified"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DT_SPEC_AND_COMMA(node_id, prop, idx) \
|
||||||
|
ADC_DT_SPEC_GET_BY_IDX(node_id, idx),
|
||||||
|
|
||||||
|
/* Data of ADC io-channels specified in devicetree. */
|
||||||
|
static const struct adc_dt_spec adc_channels[] = {
|
||||||
|
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels,
|
||||||
|
DT_SPEC_AND_COMMA)
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct device *rng_dev;
|
||||||
|
|
||||||
|
#define BUFFER_LENGTH 3
|
||||||
|
|
||||||
|
static uint8_t entropy_buffer[BUFFER_LENGTH] = {0};
|
||||||
|
|
||||||
|
static int adc_test(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
static uint32_t count;
|
||||||
|
uint16_t buf;
|
||||||
|
struct adc_sequence sequence = {
|
||||||
|
.buffer = &buf,
|
||||||
|
/* buffer size in bytes, not number of samples */
|
||||||
|
.buffer_size = sizeof(buf),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Configure channels individually prior to sampling. */
|
||||||
|
for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
|
||||||
|
if (!adc_is_ready_dt(&adc_channels[i])) {
|
||||||
|
printk("ADC controller device %s not ready\n", adc_channels[i].dev->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = adc_channel_setup_dt(&adc_channels[i]);
|
||||||
|
if (err < 0) {
|
||||||
|
printk("Could not setup channel #%d (%d)\n", i, err);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("ADC reading[%u]:\n", count++);
|
||||||
|
for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
|
||||||
|
int32_t val_mv;
|
||||||
|
|
||||||
|
printk("- %s, channel %d: ",
|
||||||
|
adc_channels[i].dev->name,
|
||||||
|
adc_channels[i].channel_id);
|
||||||
|
|
||||||
|
(void)adc_sequence_init_dt(&adc_channels[i], &sequence);
|
||||||
|
|
||||||
|
err = adc_read_dt(&adc_channels[i], &sequence);
|
||||||
|
if (err < 0) {
|
||||||
|
printk("Could not read (%d)\n", err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If using differential mode, the 16 bit value
|
||||||
|
* in the ADC sample buffer should be a signed 2's
|
||||||
|
* complement value.
|
||||||
|
*/
|
||||||
|
if (adc_channels[i].channel_cfg.differential) {
|
||||||
|
val_mv = (int32_t)((int16_t)buf);
|
||||||
|
} else {
|
||||||
|
val_mv = (int32_t)buf;
|
||||||
|
}
|
||||||
|
printk("%"PRId32, val_mv);
|
||||||
|
err = adc_raw_to_millivolts_dt(&adc_channels[i],
|
||||||
|
&val_mv);
|
||||||
|
/* conversion to mV may not be supported, skip if not */
|
||||||
|
if (err < 0) {
|
||||||
|
printk(" (value in mV not available)\n");
|
||||||
|
} else {
|
||||||
|
printk(" = %"PRId32" mV\n", val_mv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_buf(uint8_t *buffer)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < BUFFER_LENGTH; i++) {
|
||||||
|
printk(" 0x%02x", buffer[i]);
|
||||||
|
if (buffer[i] == 0x00) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printk("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
__ASSERT_NO_MSG(gpio_is_ready_dt(&led));
|
||||||
|
|
||||||
|
rng_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy));
|
||||||
|
if (!device_is_ready(rng_dev)) {
|
||||||
|
printk("error: random device not ready");
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Device ready\n");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
|
||||||
|
adc_test();
|
||||||
|
k_busy_wait(SLEEP_TIME_BUSY_MS*1000);
|
||||||
|
gpio_pin_set_dt(&led, 0);
|
||||||
|
k_msleep(SLEEP_TIME_STOP0_MS);
|
||||||
|
printk("Exit Stop0\n");
|
||||||
|
|
||||||
|
gpio_pin_set_dt(&led, 1);
|
||||||
|
adc_test();
|
||||||
|
k_busy_wait(SLEEP_TIME_BUSY_MS*1000);
|
||||||
|
gpio_pin_set_dt(&led, 0);
|
||||||
|
k_msleep(SLEEP_TIME_STOP1_MS);
|
||||||
|
printk("Exit Stop1\n");
|
||||||
|
|
||||||
|
(void)memset(entropy_buffer, 0x00, BUFFER_LENGTH);
|
||||||
|
entropy_get_entropy(rng_dev, (char *)entropy_buffer, BUFFER_LENGTH);
|
||||||
|
printk("Sync entropy: ");
|
||||||
|
print_buf(entropy_buffer);
|
||||||
|
|
||||||
|
gpio_pin_set_dt(&led, 1);
|
||||||
|
adc_test();
|
||||||
|
k_busy_wait(SLEEP_TIME_BUSY_MS*1000);
|
||||||
|
gpio_pin_configure_dt(&led, GPIO_DISCONNECTED);
|
||||||
|
k_msleep(SLEEP_TIME_STANDBY_MS);
|
||||||
|
printk("Exit Standby\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue