From 2caf720c51c459864636ba2fd43d08fb78acbe74 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 20 Oct 2023 11:10:22 +0200 Subject: [PATCH] samples: board: stm32 pm: add adc power management sample Add a sample for STM32 ADC power management Signed-off-by: Guillaume Gautier --- .../stm32/power_mgmt/adc/CMakeLists.txt | 7 ++ .../boards/stm32/power_mgmt/adc/README.rst | 42 ++++++++ .../adc/boards/nucleo_g474re.overlay | 27 ++++++ .../adc/boards/nucleo_wb55rg.overlay | 26 +++++ .../adc/boards/nucleo_wba52cg.overlay | 12 +++ samples/boards/stm32/power_mgmt/adc/prj.conf | 6 ++ .../boards/stm32/power_mgmt/adc/sample.yaml | 17 ++++ .../boards/stm32/power_mgmt/adc/src/main.c | 97 +++++++++++++++++++ 8 files changed, 234 insertions(+) create mode 100644 samples/boards/stm32/power_mgmt/adc/CMakeLists.txt create mode 100644 samples/boards/stm32/power_mgmt/adc/README.rst create mode 100644 samples/boards/stm32/power_mgmt/adc/boards/nucleo_g474re.overlay create mode 100644 samples/boards/stm32/power_mgmt/adc/boards/nucleo_wb55rg.overlay create mode 100644 samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay create mode 100644 samples/boards/stm32/power_mgmt/adc/prj.conf create mode 100644 samples/boards/stm32/power_mgmt/adc/sample.yaml create mode 100644 samples/boards/stm32/power_mgmt/adc/src/main.c diff --git a/samples/boards/stm32/power_mgmt/adc/CMakeLists.txt b/samples/boards/stm32/power_mgmt/adc/CMakeLists.txt new file mode 100644 index 00000000000..b0eea852bf5 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/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_adc) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/stm32/power_mgmt/adc/README.rst b/samples/boards/stm32/power_mgmt/adc/README.rst new file mode 100644 index 00000000000..2ec694884fa --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/README.rst @@ -0,0 +1,42 @@ +.. _stm32-pm-adc-sample: + +STM32 PM ADC +############ + +Overview +******** + +This sample is a minimum application to demonstrate basic power management +behavior in a basic ADC set up in low power context. + +.. _stm32-pm-adc-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`). + +Building and Running +******************** + +Build and flash as follows, changing ``nucleo_wb55rg`` for your board: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/stm32/power_mgmt/adc + :board: nucleo_wb55rg + :goals: build flash + :compact: + +After flashing, the console shows the ADC measurement in the form: +``ADC reading[0]:`` +``- adc@50040000, channel 3: 1158 = 932 mV`` + +PM configurations +***************** + +By default, :kconfig:option:`CONFIG_PM_DEVICE` and :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME` are +enabled. +On STM32WB, we can observe a power consumption of about 25µA with both kconfig +enabled, 27.5µA without (each time with :kconfig:option:`CONFIG_PM` enabled). diff --git a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_g474re.overlay b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_g474re.overlay new file mode 100644 index 00000000000..bde07e0f2d6 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_g474re.overlay @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +#include + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 1>; + }; +}; + +&adc1 { + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wb55rg.overlay b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wb55rg.overlay new file mode 100644 index 00000000000..6a39f681c45 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wb55rg.overlay @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 3>; + }; +}; + +&adc1 { + pinctrl-0 = <&adc1_in3_pc2>; + #address-cells = <1>; + #size-cells = <0>; + + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay new file mode 100644 index 00000000000..3cd6cb64bf5 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc4 8>; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/adc/prj.conf b/samples/boards/stm32/power_mgmt/adc/prj.conf new file mode 100644 index 00000000000..c5359fe0238 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/prj.conf @@ -0,0 +1,6 @@ +CONFIG_PM=y +CONFIG_PM_DEVICE=y +CONFIG_PM_DEVICE_RUNTIME=y +CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n +CONFIG_ADC=y +#CONFIG_DEBUG=y diff --git a/samples/boards/stm32/power_mgmt/adc/sample.yaml b/samples/boards/stm32/power_mgmt/adc/sample.yaml new file mode 100644 index 00000000000..e27cc5b268d --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/sample.yaml @@ -0,0 +1,17 @@ +sample: + name: STM32 ADC Power Management +tests: + sample.boards.stm32.power_mgmt.adc: + tags: + - ADC + - power + harness: console + harness_config: + type: one_line + regex: + - "Device ready" + filter: dt_compat_enabled("zephyr,power-state") and + dt_compat_enabled("st,stm32-adc") and + dt_compat_enabled("st,stm32-lptim") + extra_args: "CONFIG_DEBUG=y" + platform_allow: nucleo_wb55rg diff --git a/samples/boards/stm32/power_mgmt/adc/src/main.c b/samples/boards/stm32/power_mgmt/adc/src/main.c new file mode 100644 index 00000000000..b75ab4a9af2 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/src/main.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define SLEEP_TIME_MS 2000 + +#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) +}; + +int main(void) +{ + int err; + uint32_t count = 0; + 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("Device ready\n"); + + while (true) { + 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); + } + } + + k_msleep(SLEEP_TIME_MS); + } + return 0; +}