Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions scripts/ci/tags.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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/
13 changes: 13 additions & 0 deletions tests/subsys/swo/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})
2 changes: 2 additions & 0 deletions tests/subsys/swo/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CONFIG_LOG=y
CONFIG_LOG_BACKEND_SWO=y
131 changes: 131 additions & 0 deletions tests/subsys/swo/pytest/test_swo.py
Original file line number Diff line number Diff line change
@@ -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}"
21 changes: 21 additions & 0 deletions tests/subsys/swo/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

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

#include <zephyr/kernel.h>

int main(void)
{
int counter = 1;

while (true) {
LOG_INF("%d: Hello from %s", counter, CONFIG_BOARD_TARGET);
counter++;
k_msleep(1000);
}
}
20 changes: 20 additions & 0 deletions tests/subsys/swo/testcase.yaml
Original file line number Diff line number Diff line change
@@ -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