Skip to content

Commit

Permalink
tests: benchmark: multicore: Test PWM with low power modes
Browse files Browse the repository at this point in the history
Add test that confirms correct operation of PWM
when target enters and leaves low power mode.

Signed-off-by: Sebastian Głąb <sebastian.glab@nordicsemi.no>
  • Loading branch information
nordic-segl committed Sep 19, 2024
1 parent 204da36 commit de6dc40
Show file tree
Hide file tree
Showing 15 changed files with 367 additions and 0 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ Kconfig* @tejlmand
/tests/ @PerMac @katgiadla
/tests/benchmarks/multicore/ @carlescufi
/tests/benchmarks/multicore/idle/ @adamkondraciuk @nrfconnect/ncs-low-level-test
/tests/benchmarks/multicore/idle_with_pwm/ @nrfconnect/ncs-low-level-test
/tests/benchmarks/i2c_endless/ @nrfconnect/ncs-low-level-test
/tests/benchmarks/spi_endless/ @nrfconnect/ncs-low-level-test
/tests/bluetooth/tester/ @carlescufi @nrfconnect/ncs-paladin
Expand Down
19 changes: 19 additions & 0 deletions tests/benchmarks/multicore/idle_with_pwm/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

if (NOT SYSBUILD)
message(WARNING
" This is a multi-image application that should be built using sysbuild.\n"
" Add --sysbuild argument to west build command to prepare all the images.")
endif()

project(idle_with_pwm)

target_sources(app PRIVATE src/main.c)
10 changes: 10 additions & 0 deletions tests/benchmarks/multicore/idle_with_pwm/Kconfig.sysbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

source "${ZEPHYR_BASE}/share/sysbuild/Kconfig"

config REMOTE_BOARD
string "The board used for remote target"
67 changes: 67 additions & 0 deletions tests/benchmarks/multicore/idle_with_pwm/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
.. _multicore_idle_gpio_test:

Multicore idle GPIO test
########################

.. contents::
:local:
:depth: 2

The test benchmarks the idle behavior of an application that runs on multiple cores and uses PWM driver to light up LED.
Test scenario:
Repeat forever:
- gradually light up LED (this lasts for ~1 second),
- disable PWM (set period to 0); This will turn off LED,
- sleep for 1 second.

Requirements
************

The test supports the following development kits:

.. table-from-rows:: /includes/sample_board_rows.txt
:header: heading
:rows: nrf54h20dk_nrf54h20_cpuapp

Overview
********

The test demonstrates use of PWM with low power modes.

Code stored in :file:`main.c` is compiled for Application and Radio cores.
Application core uses pwm130 to generate PWM signal on LED2.
Radio core uses pwm131 to generate PWM signal on GPIO Port 0 pin 7.

There are two test configurations in :file:`testcase.yaml`.

#. 'benchmarks.multicore.idle_with_pwm.nrf54h20dk_cpuapp_cpurad.s2ram'
This configuration uses KConfigs that enable entering low power modes. However, logging is disabled here.
#. 'benchmarks.multicore.idle_with_pwm.nrf54h20dk_cpuapp_cpurad.no_sleep'
This configuration can be used for debug purposes. It has enabled logging while Power Moding is disabled.

Building and running
********************

.. |test path| replace:: :file:`tests/benchmarks/multicore/idle_with_pwm`

.. include:: /includes/build_and_run_test.txt

To build the test, use configuration setups from :file:`testcase.yaml` using the ``-T`` option.
See the following examples:

nRF54H20 DK
You can build the test for application and radio cores as follows:

.. code-block:: console
west build -p -b nrf54h20dk/nrf54h20/cpuapp -T benchmarks.multicore.idle_with_pwm.nrf54h20dk_cpuapp_cpurad.s2ram .
Testing
=======

After programming the test to your development kit, complete the following steps to test it:

#. Connect the PPK2 Power Profiler Kit or other current measurement device.
#. Reset the kit.
#. Observe the LED2 brightness (or use oscilloscope to collect PWM signal on Port 0 pin 7).
#. When LED2 is OFF power profiler shall indicate low current consumption resulting from both cores being in low power mode.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

/ {
power-states {
idle: idle {
compatible = "zephyr,power-state";
power-state-name = "suspend-to-idle";
min-residency-us = <100000>;
};

s2ram: s2ram {
compatible = "zephyr,power-state";
power-state-name = "suspend-to-ram";
min-residency-us = <800000>;
};
};
};

&cpu {
cpu-power-states = <&idle &s2ram>;
};
4 changes: 4 additions & 0 deletions tests/benchmarks/multicore/idle_with_pwm/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CONFIG_PRINTK=y
CONFIG_LOG=y
CONFIG_PWM=y
CONFIG_PWM_LOG_LEVEL_DBG=n
17 changes: 17 additions & 0 deletions tests/benchmarks/multicore/idle_with_pwm/prj_s2ram.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CONFIG_PM=y
CONFIG_PM_S2RAM=y
CONFIG_POWEROFF=y
CONFIG_PM_S2RAM_CUSTOM_MARKING=y

CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=y

CONFIG_CONSOLE=n
CONFIG_UART_CONSOLE=n
CONFIG_SERIAL=n
CONFIG_BOOT_BANNER=n
CONFIG_NRFS_MRAM_SERVICE_ENABLED=n
CONFIG_CLOCK_CONTROL=n

CONFIG_PWM=y
CONFIG_PWM_LOG_LEVEL_DBG=n
12 changes: 12 additions & 0 deletions tests/benchmarks/multicore/idle_with_pwm/remote/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(remote)

target_sources(app PRIVATE ../src/main.c)
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

/ {
aliases {
pwm-led0 = &pwm_gpio;
};

pwmleds {
compatible = "pwm-leds";
/*
* LEDs are connected to GPIO Port 9 - pins 0-3. There is no valid hardware
* configuration to pass PWM signal on pis 0 and 1. First valid config is P9.2.
* Signal on PWM130's channel 0 can be passed directly on GPIO Port 9 pin 2.
* PWM131 can't access GPIO Port 9, thus use GPIO Port 0, pin 7.
*/
pwm_gpio: pwm_gpio {
pwms = <&pwm131 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
};
};
};

&pinctrl {
/omit-if-no-ref/ pwm131_default: pwm131_default {
group1 {
psels = <NRF_PSEL(PWM_OUT0, 7, 0)>;
};
};

/omit-if-no-ref/ pwm131_sleep: pwm131_sleep {
group1 {
psels = <NRF_PSEL(PWM_OUT0, 7, 0)>;
low-power-enable;
};
};
};

&pwm131 {
status = "okay";
pinctrl-0 = <&pwm131_default>;
pinctrl-1 = <&pwm131_sleep>;
pinctrl-names = "default", "sleep";
memory-regions = <&cpurad_dma_region>;
};
4 changes: 4 additions & 0 deletions tests/benchmarks/multicore/idle_with_pwm/remote/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CONFIG_PRINTK=y
CONFIG_LOG=y
CONFIG_PWM=y
CONFIG_PWM_LOG_LEVEL_DBG=n
12 changes: 12 additions & 0 deletions tests/benchmarks/multicore/idle_with_pwm/remote/prj_s2ram.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CONFIG_PM=y
CONFIG_POWEROFF=y

CONFIG_CONSOLE=n
CONFIG_UART_CONSOLE=n
CONFIG_SERIAL=n
CONFIG_BOOT_BANNER=n
CONFIG_NRFS_MRAM_SERVICE_ENABLED=n
CONFIG_CLOCK_CONTROL=n

CONFIG_PWM=y
CONFIG_PWM_LOG_LEVEL_DBG=n
95 changes: 95 additions & 0 deletions tests/benchmarks/multicore/idle_with_pwm/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(idle_with_pwm, LOG_LEVEL_INF);

#include <zephyr/kernel.h>
#include <zephyr/pm/pm.h>
#include <zephyr/drivers/pwm.h>

#if IS_ENABLED(CONFIG_SOC_NRF54H20_CPUAPP)
/* Alias pwm-led0 = &pwm_led2 */
static const struct pwm_dt_spec pwm_led = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));
#elif IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)
/* Alias pwm-led0 = &pwm_led3 */
static const struct pwm_dt_spec pwm_led = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));
#else
#error "Invalid core selected. "
#endif

#define PWM_STEPS_PER_SEC (50)

int main(void)
{
int ret;
unsigned int cnt = 0;
uint32_t pwm_period;
uint32_t pulse_min;
uint32_t pulse_max;
int32_t pulse_step;
uint32_t current_pulse_width;

if (!pwm_is_ready_dt(&pwm_led)) {
LOG_ERR("Device %s is not ready.", pwm_led.dev->name);
return -ENODEV;
}

/*
* In case the default pwm_period value cannot be set for
* some PWM hardware, decrease its value until it can.
*/
LOG_INF("Detecting PWM period for channel %d", pwm_led.channel);
pwm_period = PWM_USEC(200U);
while (pwm_set_dt(&pwm_led, pwm_period, pwm_period) != 0) {
pwm_period /= 2U;
LOG_INF("Decreasing period to %u", pwm_period);
}

/*
* There is no distinct change in LED brightness for high PWM duty cycles.
* Thus limit duty cycle to [0; max/2].
*/
pulse_min = 0;
pulse_max = pwm_period / 2;
pulse_step = (pulse_max - pulse_min) / PWM_STEPS_PER_SEC;
LOG_DBG("Period is %u nsec", pwm_period);
LOG_DBG("PWM pulse width varies from %u to %u with %u step",
pulse_min, pulse_max, pulse_step);

LOG_INF("Multicore idle_with_pwm test on %s", CONFIG_BOARD_TARGET);

while (1) {
LOG_INF("Multicore idle_with_pwm test iteration %u", cnt++);

/* Light up LED */
current_pulse_width = pulse_min;
for (int i = 0; i < PWM_STEPS_PER_SEC; i++) {
/* set pulse width */
ret = pwm_set_dt(&pwm_led, pwm_period, current_pulse_width);
if (ret) {
LOG_ERR("pwm_set_dt(%u, %u) returned %d",
pwm_period, current_pulse_width, ret);
return ret;
}
current_pulse_width += pulse_step;
k_msleep(1000 / PWM_STEPS_PER_SEC);
}

/* Disable PWM / LED OFF */
ret = pwm_set_dt(&pwm_led, 0, 0);
if (ret) {
LOG_ERR("pwm_set_dt(%u, %u) returned %d",
0, 0, ret);
return ret;
}

/* Sleep 1 second */
k_msleep(1000);
}

return 0;
}
22 changes: 22 additions & 0 deletions tests/benchmarks/multicore/idle_with_pwm/sysbuild.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

if("${SB_CONFIG_REMOTE_BOARD}" STREQUAL "")
message(FATAL_ERROR "REMOTE_BOARD must be set to a valid board name")
endif()

# Add remote project
ExternalZephyrProject_Add(
APPLICATION remote
SOURCE_DIR ${APP_DIR}/remote
BOARD ${SB_CONFIG_REMOTE_BOARD}
BOARD_REVISION ${BOARD_REVISION}
)

# Add a dependency so that the remote image will be built and flashed first
add_dependencies(idle_with_pwm remote)
# Add dependency so that the remote image is flashed first.
sysbuild_add_dependencies(FLASH idle_with_pwm remote)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SB_CONFIG_REMOTE_BOARD="nrf54h20dk/nrf54h20/cpurad"
31 changes: 31 additions & 0 deletions tests/benchmarks/multicore/idle_with_pwm/testcase.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
common:
sysbuild: true
tags: ci_build ci_tests_benchmarks_multicore
platform_allow:
- nrf54h20dk/nrf54h20/cpuapp
integration_platforms:
- nrf54h20dk/nrf54h20/cpuapp

tests:
benchmarks.multicore.idle_with_pwm.nrf54h20dk_cpuapp_cpurad.no_sleep:
extra_args:
SB_CONF_FILE=sysbuild/nrf54h20dk_nrf54h20_cpurad.conf
harness: console
harness_config:
type: multi_line
ordered: true
regex:
- "Multicore idle_with_pwm test on"
- "Multicore idle_with_pwm test iteration 0"
- "Multicore idle_with_pwm test iteration 1"

benchmarks.multicore.idle_with_pwm.nrf54h20dk_cpuapp_cpurad.s2ram:
extra_args:
SB_CONF_FILE=sysbuild/nrf54h20dk_nrf54h20_cpurad.conf
idle_with_pwm_CONF_FILE=prj_s2ram.conf
remote_CONF_FILE=prj_s2ram.conf
harness: pytest
harness_config:
fixture: ppk_power_measure
pytest_root:
- "${CUSTOM_ROOT_TEST_DIR}/test_measure_power_consumption.py::test_measure_and_data_dump_power_consumption_simple"

0 comments on commit de6dc40

Please sign in to comment.