diff --git a/CODEOWNERS b/CODEOWNERS index 5c79479cc493..a27b73033e86 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -941,6 +941,7 @@ /tests/subsys/partition_manager/region/ @nordicjm @tejlmand /tests/subsys/partition_manager/static_pm_file/ @nordicjm @tejlmand /tests/subsys/pcd/ @nrfconnect/ncs-pluto +/tests/subsys/swo/ @nrfconnect/ncs-low-level-test /tests/subsys/usb/negotiated_speed/ @nrfconnect/ncs-low-level-test /tests/subsys/ipc/ @nrfconnect/ncs-low-level-test /tests/tfm/ @nrfconnect/ncs-aegir @magnev diff --git a/scripts/ci/tags.yaml b/scripts/ci/tags.yaml index 0f82d2d899ad..201d2d84ecb8 100644 --- a/scripts/ci/tags.yaml +++ b/scripts/ci/tags.yaml @@ -1916,3 +1916,7 @@ ci_samples_nrf54h20: - nrf/samples/nrf54h20/ - zephyr/modules/hal_nordic/ - zephyr/soc/nordic/nrf54h/ + +ci_tests_subsys_swo: + files: + - nrf/tests/subsys/swo/ diff --git a/tests/subsys/swo/CMakeLists.txt b/tests/subsys/swo/CMakeLists.txt new file mode 100644 index 000000000000..ba03d4deae16 --- /dev/null +++ b/tests/subsys/swo/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright (c) 2025 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(log_swo) + +FILE(GLOB app_sources src/main.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/swo/prj.conf b/tests/subsys/swo/prj.conf new file mode 100644 index 000000000000..d2ef8d955271 --- /dev/null +++ b/tests/subsys/swo/prj.conf @@ -0,0 +1,2 @@ +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SWO=y diff --git a/tests/subsys/swo/pytest/test_swo.py b/tests/subsys/swo/pytest/test_swo.py new file mode 100644 index 000000000000..46758e726970 --- /dev/null +++ b/tests/subsys/swo/pytest/test_swo.py @@ -0,0 +1,131 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +import logging +import re +import subprocess +from pathlib import Path +import time + +import psutil +from twister_harness import DeviceAdapter + +logger = logging.getLogger(__name__) + +# Kill parent process and all child processes (if started) +def _kill(proc): + try: + for child in psutil.Process(proc.pid).children(recursive=True): + child.kill() + proc.kill() + except Exception as e: + logger.exception(f'Could not kill nrfutil - {e}') + + +def test_swo_logging(dut: DeviceAdapter): + """ + Compile and flash test application on MCU. + Tested core(s) uses SWO backend for logging. + JLinkSWOViewerCLExe is used to collect logs. + """ + BUILD_DIR = str(dut.device_config.build_dir) + PLATFORM = dut.device_config.platform + SEGGER_ID = dut.device_config.id + COLLECT_TIMEOUT = 10.0 + EXPECTED = rf"\d+: Hello from {PLATFORM}" + + logger.debug(f"{dut.device_config=}") + + SWO_CONFIG = { + 'nrf52dk/nrf52832': { + 'device': 'nRF52832_xxAA', + 'cpufreq': 64000000, + 'swofreq': 1000000, + }, + 'nrf52840dk/nrf52840': { + 'device': 'nRF52840_xxAA', + 'cpufreq': 64000000, + 'swofreq': 1000000, + }, + 'nrf5340dk/nrf5340/cpuapp': { + 'device': 'nRF5340_xxAA_APP', + 'cpufreq': 64000000, + 'swofreq': 1000000, + }, + 'nrf54l15dk/nrf54l05/cpuapp': { + 'device': 'nRF54L05_M33', + 'cpufreq': 128000000, + 'swofreq': 1000000, + }, + 'nrf54l15dk/nrf54l10/cpuapp': { + 'device': 'nRF54L10_M33', + 'cpufreq': 128000000, + 'swofreq': 1000000, + }, + 'nrf54l15dk/nrf54l15/cpuapp': { + 'device': 'nRF54L15_M33', + 'cpufreq': 128000000, + 'swofreq': 1000000, + }, + 'nrf54lm20dk/nrf54lm20a/cpuapp': { + 'device': 'NRF54LM20A_M33', + 'cpufreq': 128000000, + 'swofreq': 1000000, + }, + 'nrf54lv10dk/nrf54lv10a/cpuapp': { + 'device': 'NRF54LV10A_M33', + 'cpufreq': 128000000, + 'swofreq': 1000000, + }, + } + + log_filename = f"{BUILD_DIR}/log_swo.txt" + try: + Path(f"{log_filename}").unlink() + logger.info("Old output file was deleted") + except FileNotFoundError: + pass + + # Wait a bit for the core to boot + time.sleep(2) + + # use JLinkSWOViewerCLExe to collect logs + cmd = f"JLinkSWOViewerCLExe -USB {SEGGER_ID}" + cmd += f" -device {SWO_CONFIG[PLATFORM]['device']}" + cmd += f" -cpufreq {SWO_CONFIG[PLATFORM]['cpufreq']}" + cmd += f" -swofreq {SWO_CONFIG[PLATFORM]['swofreq']}" + cmd += f" -itmmask 0xFFFF -outputfile {log_filename}" + try: + logger.info(f"Executing:\n{cmd}") + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + encoding='UTF-8', + shell=True, + ) + except OSError as exc: + logger.error(f"Unable to start JLinkSWOViewerCLExe:\n{cmd=}\n{exc=}") + + try: + proc.wait(COLLECT_TIMEOUT) + except subprocess.TimeoutExpired: + pass + finally: + _kill(proc) + + # read logs + with open(f"{log_filename}", errors="ignore") as log_file: + log_file_content = log_file.read() + + # if nothing in log_file, stop test + assert( + len(log_file_content) > 0 + ), f"File {log_filename} is empty" + + # Check if log file contains expected string + expected_str = re.search(EXPECTED, log_file_content) + assert expected_str is not None, f"Failed to match {EXPECTED} in {log_filename}" diff --git a/tests/subsys/swo/src/main.c b/tests/subsys/swo/src/main.c new file mode 100644 index 000000000000..186a590addbc --- /dev/null +++ b/tests/subsys/swo/src/main.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +LOG_MODULE_REGISTER(log_swo, LOG_LEVEL_INF); + +#include + +int main(void) +{ + int counter = 1; + + while (true) { + LOG_INF("%d: Hello from %s", counter, CONFIG_BOARD_TARGET); + counter++; + k_msleep(1000); + } +} diff --git a/tests/subsys/swo/testcase.yaml b/tests/subsys/swo/testcase.yaml new file mode 100644 index 000000000000..2275be78df9c --- /dev/null +++ b/tests/subsys/swo/testcase.yaml @@ -0,0 +1,20 @@ +tests: + swo.logging: + tags: ci_tests_subsys_swo + harness: pytest + harness_config: + pytest_dut_scope: session + pytest_root: + - "pytest/test_swo.py::test_swo_logging" + timeout: 30 + platform_allow: + - nrf52dk/nrf52832 + - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp + - nrf54l15dk/nrf54l05/cpuapp + - nrf54l15dk/nrf54l10/cpuapp + - nrf54l15dk/nrf54l15/cpuapp + - nrf54lm20dk/nrf54lm20a/cpuapp + - nrf54lv10dk/nrf54lv10a/cpuapp + integration_platforms: + - nrf5340dk/nrf5340/cpuapp