From 682e2ace4b58d5d42fe59c6bd89bbf02233b15ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 31 May 2024 13:14:49 +0200 Subject: [PATCH 01/15] tests: drivers: uart: Add test for async API using two instance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add test which is using two independent UART devices. Validate behavior of asynchronous API. Signed-off-by: Krzysztof Chruściński --- .../uart/uart_async_dual/CMakeLists.txt | 8 + tests/drivers/uart/uart_async_dual/Kconfig | 15 + .../uart_async_dual/boards/nrf52_bsim.overlay | 44 ++ .../boards/nrf54h20dk_nrf54h20_common.dtsi | 70 ++ .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 1 + .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 11 + .../boards/nrf54h20dk_nrf54h20_cpuppr.overlay | 7 + .../boards/nrf54h20dk_nrf54h20_cpurad.conf | 1 + .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 27 + .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 70 ++ .../boards/nrf9160dk_nrf9160.conf | 1 + .../boards/nrf9160dk_nrf9160.overlay | 70 ++ tests/drivers/uart/uart_async_dual/prj.conf | 6 + tests/drivers/uart/uart_async_dual/src/main.c | 683 ++++++++++++++++++ .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 11 + .../sysbuild/vpr_launcher/prj.conf | 1 + .../uart/uart_async_dual/testcase.yaml | 30 + 17 files changed, 1056 insertions(+) create mode 100644 tests/drivers/uart/uart_async_dual/CMakeLists.txt create mode 100644 tests/drivers/uart/uart_async_dual/Kconfig create mode 100644 tests/drivers/uart/uart_async_dual/boards/nrf52_bsim.overlay create mode 100644 tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi create mode 100644 tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.conf create mode 100644 tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.overlay create mode 100644 tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuppr.overlay create mode 100644 tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.conf create mode 100644 tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.overlay create mode 100644 tests/drivers/uart/uart_async_dual/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay create mode 100644 tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.conf create mode 100644 tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.overlay create mode 100644 tests/drivers/uart/uart_async_dual/prj.conf create mode 100644 tests/drivers/uart/uart_async_dual/src/main.c create mode 100644 tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay create mode 100644 tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/prj.conf create mode 100644 tests/drivers/uart/uart_async_dual/testcase.yaml diff --git a/tests/drivers/uart/uart_async_dual/CMakeLists.txt b/tests/drivers/uart/uart_async_dual/CMakeLists.txt new file mode 100644 index 000000000000..8dcea87b6487 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(uart_async_dual) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/drivers/uart/uart_async_dual/Kconfig b/tests/drivers/uart/uart_async_dual/Kconfig new file mode 100644 index 000000000000..d1c5ad6134b2 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config UART_ASYNC_DUAL_TEST_TIMEOUT + int "Single test case length (in milliseconds)" + # For the simulated devices, which are run by default in CI, we set it to less to not spend too + # much CI time + default 500 if SOC_SERIES_BSIM_NRFXX + default 3000 + help + For how many loops will the stress test run. The higher this number the longer the + test and therefore the higher likelihood an unlikely race/event will be triggered. + +# Include Zephyr's Kconfig +source "Kconfig" diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf52_bsim.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf52_bsim.overlay new file mode 100644 index 000000000000..afd9264d1901 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf52_bsim.overlay @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = , + , + , + ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; +}; + +dut: &uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +&timer0 { + status = "okay"; + interrupts = <8 0>; +}; + +/ { + busy-sim { + compatible = "vnd,busy-sim"; + status = "okay"; + counter = <&timer0>; + }; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi new file mode 100644 index 000000000000..36d09322a544 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&pinctrl { + uart134_alt_default: uart134_alt_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart134_alt_sleep: uart134_alt_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart137_alt_default: uart137_alt_default { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart137_alt_sleep: uart137_alt_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +dut: &uart134 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart134_alt_default>; + pinctrl-1 = <&uart134_alt_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +dut_aux: &uart137 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart137_alt_default>; + pinctrl-1 = <&uart137_alt_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +&timer137 { + status = "okay"; + interrupts = <467 0>; +}; + +/ { + busy-sim { + compatible = "vnd,busy-sim"; + status = "okay"; + counter = <&timer137>; + }; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 000000000000..97aee563c255 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1 @@ +CONFIG_UART_ASYNC_TX_CACHE_SIZE=64 diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 000000000000..3ef13b2ae0dc --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&dut { + memory-regions = <&cpuapp_dma_region>; +}; + +&dut_aux { + memory-regions = <&cpuapp_dma_region>; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuppr.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuppr.overlay new file mode 100644 index 000000000000..5217f2dd7e92 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuppr.overlay @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&timer137 { + interrupts = <467 (NRF_DEFAULT_IRQ_PRIORITY + 1)>; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.conf b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.conf new file mode 100644 index 000000000000..033183df85dd --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.conf @@ -0,0 +1 @@ +CONFIG_UART_ASYNC_TX_CACHE_SIZE=16 diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 000000000000..abc5944565f3 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&cpurad_dma_region { + compatible = "zephyr,memory-region"; + reg = <0x1e80 0x180>; +}; + +&dut { + memory-regions = <&cpurad_dma_region>; +}; + +&dut_aux { + memory-regions = <&cpurad_dma_region>; +}; + +&timer131 { + status = "okay"; + prescaler = <0>; +}; + +/ { + chosen { + zephyr,cpu-stats-counter = &timer131; + }; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 000000000000..cd0649411531 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&pinctrl { + uart21_default: uart21_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart21_sleep: uart21_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart22_default: uart22_default { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart22_sleep: uart22_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +dut: &uart21 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart21_default>; + pinctrl-1 = <&uart21_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +dut_aux: &uart22 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart22_default>; + pinctrl-1 = <&uart22_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +&timer20 { + status = "okay"; + interrupts = <202 0>; +}; + +/ { + busy-sim { + compatible = "vnd,busy-sim"; + status = "okay"; + counter = <&timer20>; + }; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.conf b/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.conf new file mode 100644 index 000000000000..4da3788618f3 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.conf @@ -0,0 +1 @@ +CONFIG_UART_NRFX_UARTE_ENHANCED_RX=y diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.overlay new file mode 100644 index 000000000000..d47b0db3ad9c --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.overlay @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&pinctrl { + uart1_default: uart1_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart2_default: uart2_default { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart2_sleep: uart2_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +dut: &uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +dut_aux: &uart2 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart2_default>; + pinctrl-1 = <&uart2_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +&timer2 { + status = "okay"; + interrupts = <17 0>; +}; + +/ { + busy-sim { + compatible = "vnd,busy-sim"; + status = "okay"; + counter = <&timer2>; + }; +}; diff --git a/tests/drivers/uart/uart_async_dual/prj.conf b/tests/drivers/uart/uart_async_dual/prj.conf new file mode 100644 index 000000000000..8c564ed02b39 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/prj.conf @@ -0,0 +1,6 @@ +CONFIG_ZTEST=y +CONFIG_RING_BUFFER=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_SERIAL=y +CONFIG_UART_ASYNC_API=y +CONFIG_UART_USE_RUNTIME_CONFIGURE=y diff --git a/tests/drivers/uart/uart_async_dual/src/main.c b/tests/drivers/uart/uart_async_dual/src/main.c new file mode 100644 index 000000000000..764c5fd7e616 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/src/main.c @@ -0,0 +1,683 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(test); + +#if DT_NODE_EXISTS(DT_NODELABEL(dut)) +#define DUT_NODE DT_NODELABEL(dut) +#else +#error "dut not defined" +#endif + +#if DT_NODE_EXISTS(DT_NODELABEL(dut_aux)) +#define DUT_AUX_NODE DT_NODELABEL(dut_aux) +#else +#define DUT_AUX_NODE DT_NODELABEL(dut) +#endif + +#define TX_TIMEOUT 100000 +#define RX_TIMEOUT 2000 + +#define MAX_PACKET_LEN 128 + +static const struct device *const rx_dev = DEVICE_DT_GET(DUT_NODE); +static const struct device *const tx_dev = DEVICE_DT_GET(DUT_AUX_NODE); + +enum test_tx_mode { + TX_BULK, + TX_PACKETS, +}; + +struct test_tx_data { + uint8_t buf[512]; + struct ring_buf rbuf; + atomic_t busy; + uint8_t packet_len; + uint8_t cnt; + volatile bool cont; + volatile enum test_tx_mode mode; + struct k_sem sem; +}; + +enum test_rx_state { + RX_HDR, + RX_PAYLOAD +}; + +enum test_rx_mode { + RX_CONT, + RX_DIS, +}; + +struct test_rx_data { + uint8_t hdr[1]; + uint8_t buf[256]; + uint32_t rx_cnt; + enum test_rx_state state; + enum test_rx_mode mode; + volatile bool cont; + bool buf_req; + struct k_sem sem; +}; + +static struct test_tx_data tx_data; +static struct test_rx_data rx_data; + +static void fill_tx(struct test_tx_data *data) +{ + uint8_t *buf; + uint32_t len; + int err; + + if (data->mode == TX_PACKETS) { + err = k_sem_take(&data->sem, K_MSEC(100)); + if (err < 0 && !data->cont) { + return; + } + zassert_equal(err, 0); + + uint8_t len = sys_rand8_get(); + + len = len % MAX_PACKET_LEN; + len = MAX(2, len); + + data->packet_len = len; + for (int i = 0; i < len; i++) { + data->buf[i] = len - i; + } + + return; + } + + while ((len = ring_buf_put_claim(&data->rbuf, &buf, 255)) > 1) { + uint8_t r = (sys_rand8_get() % MAX_PACKET_LEN) % len; + uint8_t packet_len = MAX(r, 2); + uint8_t rem = len - packet_len; + + packet_len = (rem < 3) ? len : packet_len; + buf[0] = packet_len; + for (int i = 1; i < packet_len; i++) { + buf[i] = packet_len - i; + } + + ring_buf_put_finish(&data->rbuf, packet_len); + } +} + +static void try_tx(const struct device *dev, bool irq) +{ + uint8_t *buf; + uint32_t len; + int err; + + if (!tx_data.cont) { + rx_data.cont = false; + return; + } + + if ((tx_data.mode == TX_PACKETS) && (tx_data.packet_len > 0)) { + uint8_t len = tx_data.packet_len; + + tx_data.packet_len = 0; + err = uart_tx(dev, tx_data.buf, len, TX_TIMEOUT); + zassert_equal(err, 0, + "Unexpected err:%d irq:%d cont:%d\n", + err, irq, tx_data.cont); + return; + } + zassert_true(tx_data.mode == TX_BULK); + + if (!atomic_cas(&tx_data.busy, 0, 1)) { + return; + } + + len = ring_buf_get_claim(&tx_data.rbuf, &buf, 255); + if (len > 0) { + err = uart_tx(dev, buf, len, TX_TIMEOUT); + zassert_equal(err, 0, + "Unexpected err:%d irq:%d cont:%d\n", + err, irq, tx_data.cont); + } +} + +static void on_tx_done(const struct device *dev, struct uart_event *evt) +{ + if (tx_data.mode == TX_PACKETS) { + k_sem_give(&tx_data.sem); + return; + } + + /* Finish previous data chunk and start new if any pending. */ + ring_buf_get_finish(&tx_data.rbuf, evt->data.tx.len); + atomic_set(&tx_data.busy, 0); + try_tx(dev, true); +} + +static void on_rx_rdy(const struct device *dev, struct uart_event *evt) +{ + uint32_t len = evt->data.rx.len; + uint32_t off = evt->data.rx.offset; + int err; + + if (!rx_data.cont) { + return; + } + + rx_data.rx_cnt += evt->data.rx.len; + if (evt->data.rx.buf == rx_data.hdr) { + rx_data.state = RX_PAYLOAD; + if ((rx_data.mode == RX_CONT) && rx_data.buf_req) { + size_t l = rx_data.hdr[0] - 1; + + zassert_true(l > 0); + rx_data.buf_req = false; + err = uart_rx_buf_rsp(dev, rx_data.buf, rx_data.hdr[0] - 1); + } + } else { + /* Payload received */ + rx_data.state = RX_HDR; + zassert_equal(len, rx_data.hdr[0] - 1); + + for (int i = 0; i < len; i++) { + bool ok = evt->data.rx.buf[off + i] == (uint8_t)(len - i); + + if (!ok) { + LOG_ERR("Unexpected data at %d, exp:%02x got:%02x", + i, len - i, evt->data.rx.buf[off + i]); + } + + zassert_true(ok, "Unexpected data at %d, exp:%02x got:%02x", + i, len - i, evt->data.rx.buf[off + i]); + if (!ok) { + rx_data.cont = false; + tx_data.cont = false; + /* Avoid flood of errors as we are in the interrupt and ztest + * cannot abort from here. + */ + return; + } + } + if ((rx_data.mode == RX_CONT) && rx_data.buf_req) { + rx_data.buf_req = false; + err = uart_rx_buf_rsp(dev, rx_data.hdr, 1); + } + } +} + +static void on_rx_dis(const struct device *dev, struct uart_event *evt, void *user_data) +{ + ARG_UNUSED(evt); + struct test_rx_data *data = user_data; + int err; + uint8_t *buf = (data->state == RX_HDR) ? data->hdr : data->buf; + uint32_t len = (data->state == RX_HDR) ? 1 : (data->hdr[0] - 1); + + data->buf_req = false; + + if (!data->cont) { + return; + } + + + zassert_true(len > 0); + err = uart_rx_enable(dev, buf, len, RX_TIMEOUT); + zassert_equal(err, 0, "Unexpected err:%d", err); +} + +static void test_end(void) +{ + tx_data.cont = false; +} + +static void test_timeout(struct k_timer *timer) +{ + test_end(); +} + +static K_TIMER_DEFINE(test_timer, test_timeout, NULL); + +static void uart_callback(const struct device *dev, struct uart_event *evt, void *user_data) +{ + switch (evt->type) { + case UART_TX_DONE: + zassert_true(dev == tx_dev); + on_tx_done(dev, evt); + break; + case UART_TX_ABORTED: + zassert_true(dev == tx_dev); + zassert_false(tx_data.cont, + "Unexpected TX abort, receiver not reading data on time"); + break; + case UART_RX_RDY: + zassert_true(dev == rx_dev); + on_rx_rdy(dev, evt); + break; + case UART_RX_BUF_RELEASED: + zassert_true(dev == rx_dev); + break; + case UART_RX_BUF_REQUEST: + rx_data.buf_req = true; + zassert_true(dev == rx_dev); + break; + case UART_RX_DISABLED: + zassert_true(dev == rx_dev); + on_rx_dis(dev, evt, &rx_data); + break; + case UART_RX_STOPPED: + zassert_true(false); + break; + default: + zassert_true(false); + break; + } +} + +static void config_baudrate(uint32_t rate) +{ + struct uart_config config; + int err; + + err = uart_config_get(rx_dev, &config); + zassert_equal(err, 0, "Unexpected err:%d", err); + + config.baudrate = rate; + + err = uart_configure(rx_dev, &config); + zassert_equal(err, 0, "Unexpected err:%d", err); + + if (rx_dev != tx_dev) { + err = uart_configure(tx_dev, &config); + zassert_equal(err, 0, "Unexpected err:%d", err); + } +} + +/* Test is running following scenario. Transmitter is sending packets which + * has 1 byte header with length followed by the payload. Transmitter can send + * packets in two modes: bulk where data is send in chunks without gaps between + * packets or in packet mode where transmitter sends packet by packet. + * Receiver receives the header and sets reception of the payload based on the + * length in the header. It can also work in two modes: continuous (CONT) where new + * transfer is started from UART_RX_RDY event or slower mode (DIS) where reception is + * started from UART_RX_DISABLED event. + * + * Test has busy simulator running if it is enabled in the configuration. + */ +static void var_packet_hwfc(uint32_t baudrate, bool tx_packets, bool cont) +{ + int err; + + config_baudrate(baudrate); + + if (IS_ENABLED(CONFIG_TEST_BUSY_SIM)) { + uint32_t active_avg = (baudrate == 1000000) ? 5 : 30; + uint32_t active_delta = (baudrate == 1000000) ? 2 : 10; + + busy_sim_start(active_avg, active_delta, 100, 50, NULL); + } + + memset(&tx_data, 0, sizeof(tx_data)); + memset(&rx_data, 0, sizeof(rx_data)); + tx_data.cont = true; + tx_data.mode = tx_packets ? TX_PACKETS : TX_BULK; + k_sem_init(&tx_data.sem, tx_packets ? 1 : 0, 1); + + rx_data.cont = true; + rx_data.rx_cnt = 0; + rx_data.state = RX_HDR; + rx_data.mode = cont ? RX_CONT : RX_DIS; + + ring_buf_init(&tx_data.rbuf, sizeof(tx_data.buf), tx_data.buf); + + k_timer_start(&test_timer, K_MSEC(CONFIG_UART_ASYNC_DUAL_TEST_TIMEOUT), K_NO_WAIT); + + err = uart_callback_set(rx_dev, uart_callback, &rx_data); + zassert_equal(err, 0, "Unexpected err:%d", err); + + err = uart_callback_set(tx_dev, uart_callback, &tx_data); + zassert_equal(err, 0, "Unexpected err:%d", err); + + on_rx_dis(rx_dev, NULL, &rx_data); + + while (tx_data.cont || rx_data.cont) { + fill_tx(&tx_data); + k_msleep(1); + try_tx(tx_dev, false); + } + + if (IS_ENABLED(CONFIG_TEST_BUSY_SIM)) { + busy_sim_stop(); + } + + (void)uart_tx_abort(tx_dev); + (void)uart_rx_disable(rx_dev); + + /* Flush all TX data that may be already started. */ + k_msleep(10); + (void)uart_rx_enable(rx_dev, rx_data.buf, sizeof(rx_data.buf), RX_TIMEOUT); + k_msleep(10); + (void)uart_rx_disable(rx_dev); + k_msleep(10); + + TC_PRINT("Received %d bytes for %d ms\n", + rx_data.rx_cnt, CONFIG_UART_ASYNC_DUAL_TEST_TIMEOUT); + zassert_true(rx_data.rx_cnt > 1000, "Unexected RX cnt: %d", rx_data.rx_cnt); +} + +ZTEST(uart_async_dual, test_var_packets_tx_bulk_dis_hwfc) +{ + /* TX in bulk mode, RX in DIS mode, 115k2 */ + var_packet_hwfc(115200, false, false); +} + +ZTEST(uart_async_dual, test_var_packets_tx_bulk_cont_hwfc) +{ + /* TX in bulk mode, RX in CONT mode, 115k2 */ + var_packet_hwfc(115200, false, true); +} + +ZTEST(uart_async_dual, test_var_packets_tx_bulk_dis_hwfc_1m) +{ + /* TX in bulk mode, RX in DIS mode, 1M */ + var_packet_hwfc(1000000, false, false); +} + +ZTEST(uart_async_dual, test_var_packets_tx_bulk_cont_hwfc_1m) +{ + /* TX in bulk mode, RX in CONT mode, 1M */ + var_packet_hwfc(1000000, false, true); +} + +ZTEST(uart_async_dual, test_var_packets_dis_hwfc) +{ + /* TX in packet mode, RX in DIS mode, 115k2 */ + var_packet_hwfc(115200, true, false); +} + +ZTEST(uart_async_dual, test_var_packets_cont_hwfc) +{ + /* TX in packet mode, RX in CONT mode, 115k2 */ + var_packet_hwfc(115200, true, true); +} + +ZTEST(uart_async_dual, test_var_packets_dis_hwfc_1m) +{ + /* TX in packet mode, RX in DIS mode, 1M */ + var_packet_hwfc(1000000, true, false); +} + +ZTEST(uart_async_dual, test_var_packets_cont_hwfc_1m) +{ + /* TX in packet mode, RX in CONT mode, 1M */ + var_packet_hwfc(1000000, true, true); +} + +static void hci_like_callback(const struct device *dev, struct uart_event *evt, void *user_data) +{ + switch (evt->type) { + case UART_TX_DONE: + zassert_true(dev == tx_dev); + k_sem_give(&tx_data.sem); + break; + case UART_TX_ABORTED: + zassert_true(dev == tx_dev); + zassert_false(tx_data.cont, + "Unexpected TX abort, receiver not reading data on time"); + break; + case UART_RX_RDY: + rx_data.rx_cnt += evt->data.rx.len; + zassert_true(dev == rx_dev); + break; + case UART_RX_BUF_RELEASED: + zassert_true(dev == rx_dev); + break; + case UART_RX_BUF_REQUEST: + zassert_true(dev == rx_dev); + break; + case UART_RX_DISABLED: + zassert_true(dev == rx_dev); + k_sem_give(&rx_data.sem); + break; + case UART_RX_STOPPED: + zassert_true(false); + break; + default: + zassert_true(false); + break; + } +} + +static bool rx(uint8_t *buf, size_t len) +{ + int err; + + err = uart_rx_enable(rx_dev, buf, len, RX_TIMEOUT); + zassert_equal(err, 0, "Unexpected err:%d", err); + + err = k_sem_take(&rx_data.sem, K_MSEC(100)); + if ((err < 0) || !tx_data.cont) { + zassert_false(tx_data.cont); + err = uart_rx_disable(rx_dev); + if (err == 0) { + err = k_sem_take(&rx_data.sem, K_MSEC(100)); + zassert_equal(err, 0, "Unexpected err:%d", err); + } + + return false; + } + + return true; +} + +static void check_pre_hdr(uint8_t *buf, uint8_t last_hdr) +{ + uint8_t exp_idx = (last_hdr + 1) & 0x7F; + + zassert_true(buf[0] & 0x80); + zassert_equal(exp_idx, buf[0] & 0x7F); +} + +static uint8_t get_len(uint8_t *buf) +{ + static const uint8_t exp_buf[] = {'a', 'b', 'c'}; + int rv; + + rv = memcmp(buf, exp_buf, sizeof(exp_buf)); + + zassert_equal(rv, 0, "exp: %02x %02x %02x, got: %02x %02x %02x", + exp_buf[0], exp_buf[1], exp_buf[2], buf[0], buf[1], buf[2]); + + return buf[sizeof(exp_buf)]; +} + +static void check_payload(uint8_t *buf, uint8_t len) +{ + for (int i = 0; i < len; i++) { + uint8_t exp_val = len - i; + bool ok = buf[i] == exp_val; + + zassert_true(ok, "Unexpected byte at %d, got:%02x exp:%02x", i, buf[i], exp_val); + if (!ok) { + test_end(); + return; + } + } +} + +static void hci_like_tx_prepare(struct test_tx_data *tx_data) +{ + int idx = tx_data->cnt & 0x1 ? sizeof(tx_data->buf) / 2 : 0; + uint8_t *buf = &tx_data->buf[idx]; + uint8_t len = sys_rand8_get() & 0x1F; + + len = MAX(1, len); + + *buf++ = 0x80 | (tx_data->cnt & 0x7F); + *buf++ = 'a'; + *buf++ = 'b'; + *buf++ = 'c'; + *buf++ = len; + + for (int i = 0; i < len; i++) { + *buf++ = len - i; + } + + tx_data->cnt++; +} + +static void hci_like_tx(struct test_tx_data *tx_data) +{ + int idx = tx_data->cnt & 0x1 ? 0 : sizeof(tx_data->buf) / 2; + uint8_t *buf = &tx_data->buf[idx]; + uint8_t len = buf[4] + 5; + int err; + + err = uart_tx(tx_dev, buf, len, TX_TIMEOUT); + zassert_equal(err, 0, "Unexpected err:%d", err); +} + +static void hci_like_tx_thread_entry(void *p1, void *p2, void *p3) +{ + int err; + + while (tx_data.cont) { + hci_like_tx_prepare(&tx_data); + + err = k_sem_take(&tx_data.sem, K_MSEC(500)); + if (err < 0) { + break; + } + zassert_equal(err, 0, "Unexpected err:%d", err); + + hci_like_tx(&tx_data); + } +} + + +static void hci_like_rx(void) +{ + uint8_t last_hdr = 0xff; + uint8_t len; + bool cont; + + while (1) { + cont = rx(rx_data.buf, 1); + if (!cont) { + break; + } + check_pre_hdr(rx_data.buf, last_hdr); + last_hdr = rx_data.buf[0]; + + cont = rx(rx_data.buf, 4); + if (!cont) { + break; + } + len = get_len(rx_data.buf); + + cont = rx(rx_data.buf, len); + if (!cont) { + break; + } + check_payload(rx_data.buf, len); + } +} + +#define HCI_LIKE_TX_STACK_SIZE 2048 +static K_THREAD_STACK_DEFINE(hci_like_tx_thread_stack, HCI_LIKE_TX_STACK_SIZE); +static struct k_thread hci_like_tx_thread; + +/* Test is emulating behavior that is implemented in the bluetooth HCI controller sample + * which is using UART asynchronous API. Each packet consists of 3 parts: 1 byte header + * indicating a type, 4 byte second header with length of the variable part which is + * a third part. + * + * Receiver sets reception of each part after receiver is disabled. + * + * If enabled, busy simulator is used in the test. + */ +static void hci_like_test(uint32_t baudrate) +{ + int err; + + config_baudrate(baudrate); + + if (IS_ENABLED(CONFIG_TEST_BUSY_SIM)) { + uint32_t active_avg = (baudrate == 1000000) ? 10 : 50; + uint32_t active_delta = (baudrate == 1000000) ? 5 : 20; + + busy_sim_start(active_avg, active_delta, 100, 50, NULL); + } + + memset(&tx_data, 0, sizeof(tx_data)); + memset(&rx_data, 0, sizeof(rx_data)); + tx_data.cnt = 0; + tx_data.cont = true; + rx_data.cont = true; + + k_sem_init(&tx_data.sem, 1, 1); + k_sem_init(&rx_data.sem, 0, 1); + + k_timer_start(&test_timer, K_MSEC(CONFIG_UART_ASYNC_DUAL_TEST_TIMEOUT), K_NO_WAIT); + + err = uart_callback_set(rx_dev, hci_like_callback, NULL); + zassert_equal(err, 0); + + err = uart_callback_set(tx_dev, hci_like_callback, NULL); + zassert_equal(err, 0); + + k_thread_create(&hci_like_tx_thread, hci_like_tx_thread_stack, + K_THREAD_STACK_SIZEOF(hci_like_tx_thread_stack), + hci_like_tx_thread_entry, NULL, NULL, NULL, + K_PRIO_COOP(7), 0, K_MSEC(10)); + + k_msleep(1); + + hci_like_rx(); + + if (IS_ENABLED(CONFIG_TEST_BUSY_SIM)) { + busy_sim_stop(); + } + + /* Flush data. */ + (void)uart_tx_abort(tx_dev); + k_msleep(10); + (void)uart_rx_enable(rx_dev, rx_data.buf, sizeof(rx_data.buf), RX_TIMEOUT); + k_msleep(1); + (void)uart_rx_disable(rx_dev); + + k_thread_abort(&hci_like_tx_thread); + k_msleep(10); + + TC_PRINT("Received %d bytes for %d ms\n", + rx_data.rx_cnt, CONFIG_UART_ASYNC_DUAL_TEST_TIMEOUT); +} + +ZTEST(uart_async_dual, test_hci_like_115k) +{ + /* HCI like test at 115k2 */ + hci_like_test(115200); +} + +ZTEST(uart_async_dual, test_hci_like_1M) +{ + /* HCI like test at 1M */ + hci_like_test(1000000); +} + +static void *setup(void) +{ + zassert_true(device_is_ready(rx_dev)); + zassert_true(device_is_ready(tx_dev)); + + return NULL; +} + +ZTEST_SUITE(uart_async_dual, NULL, setup, NULL, NULL, NULL); diff --git a/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 000000000000..fcdc838a54e4 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,11 @@ +#include "../../../boards/nrf54h20dk_nrf54h20_common.dtsi" + +&dut { + status = "reserved"; + interrupt-parent = <&cpuppr_clic>; +}; + +&dut_aux { + status = "reserved"; + interrupt-parent = <&cpuppr_clic>; +}; diff --git a/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/prj.conf b/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/prj.conf new file mode 100644 index 000000000000..b2a4ba591044 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/prj.conf @@ -0,0 +1 @@ +# nothing here diff --git a/tests/drivers/uart/uart_async_dual/testcase.yaml b/tests/drivers/uart/uart_async_dual/testcase.yaml new file mode 100644 index 000000000000..772aeb490d9c --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/testcase.yaml @@ -0,0 +1,30 @@ +common: + tags: + - drivers + - uart +tests: + drivers.uart.async_dual: + harness: ztest + harness_config: + fixture: uart_loopback + depends_on: gpio + platform_allow: + - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad + - nrf54h20dk/nrf54h20/cpuppr + - nrf9160dk/nrf9160 + - nrf52_bsim + drivers.uart.async_dual.busy_sim: + harness: ztest + harness_config: + fixture: uart_loopback + depends_on: gpio + platform_allow: + - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad + - nrf9160dk/nrf9160 + - nrf52_bsim + extra_configs: + - CONFIG_TEST_BUSY_SIM=y From bb6111f31c2397ab4622e68604daba62693e91fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 19 Jul 2024 11:59:00 +0200 Subject: [PATCH 02/15] tests: drivers: uart: async_dual: Rework for multi-instance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework test to be able to support running on multiple set of instance(s). Signed-off-by: Krzysztof Chruściński --- tests/drivers/uart/uart_async_dual/src/main.c | 53 ++++++++++++++++++- .../uart/uart_async_dual/testcase.yaml | 1 + 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/tests/drivers/uart/uart_async_dual/src/main.c b/tests/drivers/uart/uart_async_dual/src/main.c index 764c5fd7e616..5a9483c83c75 100644 --- a/tests/drivers/uart/uart_async_dual/src/main.c +++ b/tests/drivers/uart/uart_async_dual/src/main.c @@ -29,8 +29,38 @@ LOG_MODULE_REGISTER(test); #define MAX_PACKET_LEN 128 -static const struct device *const rx_dev = DEVICE_DT_GET(DUT_NODE); -static const struct device *const tx_dev = DEVICE_DT_GET(DUT_AUX_NODE); +struct dut_data { + const struct device *dev; + const struct device *dev_aux; + const char *name; + const char *name_aux; +}; + +ZTEST_DMEM struct dut_data duts[] = { + { + .dev = DEVICE_DT_GET(DUT_NODE), + .dev_aux = DT_SAME_NODE(DUT_NODE, DUT_AUX_NODE) ? + NULL : DEVICE_DT_GET(DUT_AUX_NODE), + .name = DT_NODE_FULL_NAME(DUT_NODE), + .name_aux = DT_SAME_NODE(DUT_NODE, DUT_AUX_NODE) ? + NULL : DT_NODE_FULL_NAME(DUT_AUX_NODE), + }, +#if 0 +#if DT_NODE_EXISTS(DT_NODELABEL(dut2)) + { + .dev = DEVICE_DT_GET(DT_NODELABEL(dut2)), + .name = DT_NODE_FULL_NAME(DT_NODELABEL(dut2)), +#if DT_NODE_EXISTS(DT_NODELABEL(dut_aux2)) + .dev_aux = DEVICE_DT_GET(DT_NODELABEL(dut_aux2)), + .name_aux = DT_NODE_FULL_NAME(DT_NODELABEL(dut_aux2)), +#endif + }, +#endif +#endif +}; + +static const struct device *rx_dev; +static const struct device *tx_dev; enum test_tx_mode { TX_BULK, @@ -674,6 +704,19 @@ ZTEST(uart_async_dual, test_hci_like_1M) static void *setup(void) { + static int idx; + + rx_dev = duts[idx].dev; + if (duts[idx].dev_aux == NULL) { + TC_PRINT("Single UART test on instance:%s\n", duts[idx].name); + tx_dev = rx_dev; + } else { + TC_PRINT("Dual UART test on instances:%s and %s\n", + duts[idx].name, duts[idx].name_aux); + tx_dev = duts[idx].dev_aux; + } + idx++; + zassert_true(device_is_ready(rx_dev)); zassert_true(device_is_ready(tx_dev)); @@ -681,3 +724,9 @@ static void *setup(void) } ZTEST_SUITE(uart_async_dual, NULL, setup, NULL, NULL, NULL); + +void test_main(void) +{ + ztest_run_all(NULL, false, ARRAY_SIZE(duts), 1); + ztest_verify_all_test_suites_ran(); +} diff --git a/tests/drivers/uart/uart_async_dual/testcase.yaml b/tests/drivers/uart/uart_async_dual/testcase.yaml index 772aeb490d9c..c202cdad577d 100644 --- a/tests/drivers/uart/uart_async_dual/testcase.yaml +++ b/tests/drivers/uart/uart_async_dual/testcase.yaml @@ -2,6 +2,7 @@ common: tags: - drivers - uart + timeout: 120 tests: drivers.uart.async_dual: harness: ztest From 7287ee3dadc0835dfd5af446d9104e47495d9f3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 19 Jul 2024 14:30:24 +0200 Subject: [PATCH 03/15] tests: drivers: uart: async_dual: Add testing of UARTE120 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use multi-instance testing and add UARTE120 configuration to nrf54h20 overlays. Signed-off-by: Krzysztof Chruściński --- .../boards/nrf54h20dk_nrf54h20_common.dtsi | 31 +++++++++++++++++++ .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 8 +++++ .../boards/nrf54h20dk_nrf54h20_cpuppr.overlay | 4 +++ .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 8 +++++ tests/drivers/uart/uart_async_dual/src/main.c | 6 ++-- 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi index 36d09322a544..f4b9df95aa2b 100644 --- a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -36,6 +36,28 @@ low-power-enable; }; }; + + uart120_default_alt: uart120_default_alt { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart120_sleep_alt: uart120_sleep_alt { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; }; dut: &uart134 { @@ -56,6 +78,15 @@ dut_aux: &uart137 { hw-flow-control; }; +dut2: &uart120 { + status = "okay"; + pinctrl-0 = <&uart120_default_alt>; + pinctrl-1 = <&uart120_sleep_alt>; + pinctrl-names = "default", "sleep"; + current-speed = <115200>; + hw-flow-control; +}; + &timer137 { status = "okay"; interrupts = <467 0>; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index 3ef13b2ae0dc..23ab89a1b8b1 100644 --- a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -9,3 +9,11 @@ &dut_aux { memory-regions = <&cpuapp_dma_region>; }; + +&dma_fast_region { + status = "okay"; +}; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuppr.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuppr.overlay index 5217f2dd7e92..1121082094b7 100644 --- a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuppr.overlay +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuppr.overlay @@ -5,3 +5,7 @@ &timer137 { interrupts = <467 (NRF_DEFAULT_IRQ_PRIORITY + 1)>; }; + +&dut2 { + status = "disabled"; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.overlay index abc5944565f3..b177bf8d102e 100644 --- a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -15,6 +15,14 @@ memory-regions = <&cpurad_dma_region>; }; +&dma_fast_region { + status = "okay"; +}; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; + &timer131 { status = "okay"; prescaler = <0>; diff --git a/tests/drivers/uart/uart_async_dual/src/main.c b/tests/drivers/uart/uart_async_dual/src/main.c index 5a9483c83c75..7f82e2807dfd 100644 --- a/tests/drivers/uart/uart_async_dual/src/main.c +++ b/tests/drivers/uart/uart_async_dual/src/main.c @@ -45,18 +45,16 @@ ZTEST_DMEM struct dut_data duts[] = { .name_aux = DT_SAME_NODE(DUT_NODE, DUT_AUX_NODE) ? NULL : DT_NODE_FULL_NAME(DUT_AUX_NODE), }, -#if 0 -#if DT_NODE_EXISTS(DT_NODELABEL(dut2)) +#if DT_NODE_EXISTS(DT_NODELABEL(dut2)) && DT_NODE_HAS_STATUS(DT_NODELABEL(dut2), okay) { .dev = DEVICE_DT_GET(DT_NODELABEL(dut2)), .name = DT_NODE_FULL_NAME(DT_NODELABEL(dut2)), -#if DT_NODE_EXISTS(DT_NODELABEL(dut_aux2)) +#if DT_NODE_EXISTS(DT_NODELABEL(dut_aux2)) && DT_NODE_HAS_STATUS(DT_NODELABEL(dut_aux2), okay) .dev_aux = DEVICE_DT_GET(DT_NODELABEL(dut_aux2)), .name_aux = DT_NODE_FULL_NAME(DT_NODELABEL(dut_aux2)), #endif }, #endif -#endif }; static const struct device *rx_dev; From b20c15b4128f713efa67223ac1c7bc727a73df3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 17 Sep 2024 11:43:35 +0200 Subject: [PATCH 04/15] tests: drivers: uart: async_dual: Add test cases with runtime PM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add configurations in which runtime PM is enabled. There are 2 configurations: - Test does not call PM API for getting and putting the device. In that configuration UART device shall be suspended whenever not active. - Test is calling PM API which should keep device active as long as requested (e.g. during packet reception which consists of multiple chunks). Signed-off-by: Krzysztof Chruściński --- tests/drivers/uart/uart_async_dual/Kconfig | 5 ++ .../uart_async_dual/boards/nrf52_bsim.overlay | 1 + .../boards/nrf54h20dk_nrf54h20_common.dtsi | 3 + .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 2 + tests/drivers/uart/uart_async_dual/src/main.c | 83 +++++++++++++++++++ .../uart/uart_async_dual/testcase.yaml | 29 +++++++ 6 files changed, 123 insertions(+) diff --git a/tests/drivers/uart/uart_async_dual/Kconfig b/tests/drivers/uart/uart_async_dual/Kconfig index d1c5ad6134b2..6e80ec3a7957 100644 --- a/tests/drivers/uart/uart_async_dual/Kconfig +++ b/tests/drivers/uart/uart_async_dual/Kconfig @@ -11,5 +11,10 @@ config UART_ASYNC_DUAL_TEST_TIMEOUT For how many loops will the stress test run. The higher this number the longer the test and therefore the higher likelihood an unlikely race/event will be triggered. +config PM_RUNTIME_IN_TEST + bool "Use runtime PM in the test" + select PM_DEVICE + select PM_DEVICE_RUNTIME + # Include Zephyr's Kconfig source "Kconfig" diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf52_bsim.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf52_bsim.overlay index afd9264d1901..ddae6f682f97 100644 --- a/tests/drivers/uart/uart_async_dual/boards/nrf52_bsim.overlay +++ b/tests/drivers/uart/uart_async_dual/boards/nrf52_bsim.overlay @@ -28,6 +28,7 @@ dut: &uart0 { pinctrl-1 = <&uart0_sleep>; pinctrl-names = "default", "sleep"; hw-flow-control; + zephyr,pm-device-runtime-auto; }; &timer0 { diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi index f4b9df95aa2b..28c3879984aa 100644 --- a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -67,6 +67,7 @@ dut: &uart134 { pinctrl-1 = <&uart134_alt_sleep>; pinctrl-names = "default", "sleep"; hw-flow-control; + zephyr,pm-device-runtime-auto; }; dut_aux: &uart137 { @@ -76,6 +77,7 @@ dut_aux: &uart137 { pinctrl-1 = <&uart137_alt_sleep>; pinctrl-names = "default", "sleep"; hw-flow-control; + zephyr,pm-device-runtime-auto; }; dut2: &uart120 { @@ -85,6 +87,7 @@ dut2: &uart120 { pinctrl-names = "default", "sleep"; current-speed = <115200>; hw-flow-control; + zephyr,pm-device-runtime-auto; }; &timer137 { diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay index cd0649411531..fe79690cbbad 100644 --- a/tests/drivers/uart/uart_async_dual/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -45,6 +45,7 @@ dut: &uart21 { pinctrl-1 = <&uart21_sleep>; pinctrl-names = "default", "sleep"; hw-flow-control; + zephyr,pm-device-runtime-auto; }; dut_aux: &uart22 { @@ -54,6 +55,7 @@ dut_aux: &uart22 { pinctrl-1 = <&uart22_sleep>; pinctrl-names = "default", "sleep"; hw-flow-control; + zephyr,pm-device-runtime-auto; }; &timer20 { diff --git a/tests/drivers/uart/uart_async_dual/src/main.c b/tests/drivers/uart/uart_async_dual/src/main.c index 7f82e2807dfd..02f148eef677 100644 --- a/tests/drivers/uart/uart_async_dual/src/main.c +++ b/tests/drivers/uart/uart_async_dual/src/main.c @@ -5,6 +5,8 @@ */ #include +#include +#include #include #include #include @@ -57,6 +59,40 @@ ZTEST_DMEM struct dut_data duts[] = { #endif }; +static void pm_check(const struct device *dev, const struct device *second_dev, bool exp_on, + int line) +{ + if (!IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + return; + } + + if (dev == second_dev) { + return; + } + + enum pm_device_state state; + int err; + int cnt; + + cnt = pm_device_runtime_usage(dev); + err = pm_device_state_get(dev, &state); + zassert_equal(err, 0); + + if (exp_on) { + zassert_not_equal(cnt, 0, "Wrong PM cnt:%d, line:%d", cnt, line); + zassert_equal(state, PM_DEVICE_STATE_ACTIVE, + "Wrong PM state %s, line:%d", pm_device_state_str(state), line); + return; + } + + /* Expect device to be off. */ + zassert_equal(cnt, 0, "Wrong PM count:%d, line:%d", cnt, line); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDED, + "Wrong PM state %s, line:%d", pm_device_state_str(state), line); +} + +#define PM_CHECK(dev, second_dev, exp_on) pm_check(dev, second_dev, exp_on, __LINE__) + static const struct device *rx_dev; static const struct device *tx_dev; @@ -452,11 +488,20 @@ static void hci_like_callback(const struct device *dev, struct uart_event *evt, { switch (evt->type) { case UART_TX_DONE: + zassert_true(dev == tx_dev); + if (IS_ENABLED(CONFIG_PM_RUNTIME_IN_TEST)) { + PM_CHECK(tx_dev, rx_dev, true); + pm_device_runtime_put(tx_dev); + } + PM_CHECK(tx_dev, rx_dev, false); k_sem_give(&tx_data.sem); break; case UART_TX_ABORTED: zassert_true(dev == tx_dev); + if (IS_ENABLED(CONFIG_PM_RUNTIME_IN_TEST)) { + pm_device_runtime_put(tx_dev); + } zassert_false(tx_data.cont, "Unexpected TX abort, receiver not reading data on time"); break; @@ -568,6 +613,10 @@ static void hci_like_tx(struct test_tx_data *tx_data) uint8_t len = buf[4] + 5; int err; + if (IS_ENABLED(CONFIG_PM_RUNTIME_IN_TEST)) { + pm_device_runtime_get(tx_dev); + } + err = uart_tx(tx_dev, buf, len, TX_TIMEOUT); zassert_equal(err, 0, "Unexpected err:%d", err); } @@ -595,25 +644,57 @@ static void hci_like_rx(void) uint8_t last_hdr = 0xff; uint8_t len; bool cont; + bool explicit_pm = IS_ENABLED(CONFIG_PM_RUNTIME_IN_TEST); while (1) { + if (explicit_pm) { + pm_device_runtime_get(rx_dev); + } + cont = rx(rx_data.buf, 1); if (!cont) { + if (explicit_pm) { + pm_device_runtime_put(rx_dev); + } break; } check_pre_hdr(rx_data.buf, last_hdr); last_hdr = rx_data.buf[0]; + /* If explicitly requested device to stay on in should be on. + * If application did not touch PM, device should be off. + */ + PM_CHECK(rx_dev, tx_dev, explicit_pm); + cont = rx(rx_data.buf, 4); if (!cont) { + if (explicit_pm) { + pm_device_runtime_put(rx_dev); + } break; } len = get_len(rx_data.buf); + /* If explicitly requested device to stay on in should be on. + * If application did not touch PM, device should be off. + */ + PM_CHECK(rx_dev, tx_dev, explicit_pm); + cont = rx(rx_data.buf, len); if (!cont) { + if (explicit_pm) { + pm_device_runtime_put(rx_dev); + } break; } + + if (explicit_pm) { + pm_device_runtime_put(rx_dev); + } + + /* Device shall be released and off. */ + PM_CHECK(rx_dev, tx_dev, false); + check_payload(rx_data.buf, len); } } @@ -677,6 +758,8 @@ static void hci_like_test(uint32_t baudrate) /* Flush data. */ (void)uart_tx_abort(tx_dev); k_msleep(10); + PM_CHECK(tx_dev, rx_dev, false); + (void)uart_rx_enable(rx_dev, rx_data.buf, sizeof(rx_data.buf), RX_TIMEOUT); k_msleep(1); (void)uart_rx_disable(rx_dev); diff --git a/tests/drivers/uart/uart_async_dual/testcase.yaml b/tests/drivers/uart/uart_async_dual/testcase.yaml index c202cdad577d..9c9b4fcde5a5 100644 --- a/tests/drivers/uart/uart_async_dual/testcase.yaml +++ b/tests/drivers/uart/uart_async_dual/testcase.yaml @@ -29,3 +29,32 @@ tests: - nrf52_bsim extra_configs: - CONFIG_TEST_BUSY_SIM=y + drivers.uart.async_dual.pm_runtime: + harness: ztest + harness_config: + fixture: uart_loopback + depends_on: gpio + platform_allow: + - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad + - nrf54h20dk/nrf54h20/cpuppr + - nrf9160dk/nrf9160 + - nrf52_bsim + extra_configs: + - CONFIG_PM_DEVICE_RUNTIME=y + - CONFIG_PM_DEVICE=y + drivers.uart.async_dual.pm_runtime.explicit: + harness: ztest + harness_config: + fixture: uart_loopback + depends_on: gpio + platform_allow: + - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad + - nrf54h20dk/nrf54h20/cpuppr + - nrf9160dk/nrf9160 + - nrf52_bsim + extra_configs: + - CONFIG_PM_RUNTIME_IN_TEST=y From d465dfc5fd9d83127ece7213cafb89a4542a9e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 26 Jun 2024 15:44:09 +0200 Subject: [PATCH 05/15] tests: drivers: uart: async_api: Add nrf54h20 cpuppr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add configuration for nrf54h20dk/nrf54h20/cpuppr. Signed-off-by: Krzysztof Chruściński --- .../boards/nrf54h20dk_nrf54h20_cpuppr.overlay | 3 +++ .../vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 6 ++++++ .../uart/uart_async_api/sysbuild/vpr_launcher/prj.conf | 1 + 3 files changed, 10 insertions(+) create mode 100644 tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuppr.overlay create mode 100644 tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay create mode 100644 tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/prj.conf diff --git a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuppr.overlay b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuppr.overlay new file mode 100644 index 000000000000..f65b4dd3b0ba --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuppr.overlay @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" diff --git a/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 000000000000..a1b825882f50 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,6 @@ +#include "../../../boards/nrf54h20dk_nrf54h20_common.dtsi" + +&dut { + status = "reserved"; + interrupt-parent = <&cpuppr_clic>; +}; diff --git a/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/prj.conf b/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/prj.conf new file mode 100644 index 000000000000..b2a4ba591044 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/prj.conf @@ -0,0 +1 @@ +# nothing here From fd30871653ae8340176cca85b56fd9f227840505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 18 Jul 2024 14:37:44 +0200 Subject: [PATCH 06/15] tests: drivers: uart: async_api: Add missing static keyword MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Multiple variable in the test were missing static keyword. Signed-off-by: Krzysztof Chruściński --- .../uart/uart_async_api/src/test_uart_async.c | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/drivers/uart/uart_async_api/src/test_uart_async.c b/tests/drivers/uart/uart_async_api/src/test_uart_async.c index 2feb201d94c6..6ab3a837af2f 100644 --- a/tests/drivers/uart/uart_async_api/src/test_uart_async.c +++ b/tests/drivers/uart/uart_async_api/src/test_uart_async.c @@ -24,12 +24,12 @@ K_SEM_DEFINE(rx_buf_coherency, 0, 255); K_SEM_DEFINE(rx_buf_released, 0, 1); K_SEM_DEFINE(rx_disabled, 0, 1); -ZTEST_BMEM volatile bool failed_in_isr; +static ZTEST_BMEM volatile bool failed_in_isr; static ZTEST_BMEM const struct device *const uart_dev = DEVICE_DT_GET(UART_NODE); static void read_abort_timeout(struct k_timer *timer); -K_TIMER_DEFINE(read_abort_timer, read_abort_timeout, NULL); +static K_TIMER_DEFINE(read_abort_timer, read_abort_timeout, NULL); static void init_test(void) @@ -100,7 +100,7 @@ struct test_data { #if NOCACHE_MEM static struct test_data tdata __used __NOCACHE; #else -ZTEST_BMEM struct test_data tdata; +static ZTEST_BMEM struct test_data tdata; #endif /* NOCACHE_MEM */ static void test_single_read_callback(const struct device *dev, @@ -330,10 +330,10 @@ static __aligned(32) uint8_t chained_cpy_buf[10] __used __NOCACHE; ZTEST_BMEM uint8_t chained_read_buf[2][8]; ZTEST_BMEM uint8_t chained_cpy_buf[10]; #endif /* NOCACHE_MEM */ -ZTEST_BMEM volatile uint8_t rx_data_idx; -ZTEST_BMEM uint8_t rx_buf_idx; +static ZTEST_BMEM volatile uint8_t rx_data_idx; +static ZTEST_BMEM uint8_t rx_buf_idx; -ZTEST_BMEM uint8_t *read_ptr; +static ZTEST_BMEM uint8_t *read_ptr; static void test_chained_read_callback(const struct device *dev, struct uart_event *evt, void *user_data) @@ -417,9 +417,9 @@ ZTEST_USER(uart_async_chain_read, test_chained_read) #if NOCACHE_MEM static __aligned(32) uint8_t double_buffer[2][12] __used __NOCACHE; #else -ZTEST_BMEM uint8_t double_buffer[2][12]; +static ZTEST_BMEM uint8_t double_buffer[2][12]; #endif /* NOCACHE_MEM */ -ZTEST_DMEM uint8_t *next_buf = double_buffer[1]; +static ZTEST_DMEM uint8_t *next_buf = double_buffer[1]; static void test_double_buffer_callback(const struct device *dev, struct uart_event *evt, void *user_data) @@ -492,10 +492,10 @@ ZTEST_USER(uart_async_double_buf, test_double_buffer) static __aligned(32) uint8_t test_read_abort_rx_buf[2][100] __used __NOCACHE; static __aligned(32) uint8_t test_read_abort_read_buf[100] __used __NOCACHE; #else -ZTEST_BMEM uint8_t test_read_abort_rx_buf[2][100]; -ZTEST_BMEM uint8_t test_read_abort_read_buf[100]; +static ZTEST_BMEM uint8_t test_read_abort_rx_buf[2][100]; +static ZTEST_BMEM uint8_t test_read_abort_read_buf[100]; #endif /* NOCACHE_MEM */ -ZTEST_BMEM int test_read_abort_rx_cnt; +static ZTEST_BMEM int test_read_abort_rx_cnt; static void test_read_abort_callback(const struct device *dev, struct uart_event *evt, void *user_data) @@ -608,12 +608,12 @@ ZTEST_USER(uart_async_read_abort, test_read_abort) } -ZTEST_BMEM volatile size_t sent; -ZTEST_BMEM volatile size_t received; +static ZTEST_BMEM volatile size_t sent; +static ZTEST_BMEM volatile size_t received; #if NOCACHE_MEM static __aligned(32) uint8_t test_rx_buf[2][100] __used __NOCACHE; #else -ZTEST_BMEM uint8_t test_rx_buf[2][100]; +static ZTEST_BMEM uint8_t test_rx_buf[2][100]; #endif /* NOCACHE_MEM */ static void test_write_abort_callback(const struct device *dev, @@ -771,12 +771,12 @@ ZTEST_USER(uart_async_timeout, test_forever_timeout) #if NOCACHE_MEM -const uint8_t chained_write_tx_bufs[2][10] = {"Message 1", "Message 2"}; +static const uint8_t chained_write_tx_bufs[2][10] = {"Message 1", "Message 2"}; #else -ZTEST_DMEM uint8_t chained_write_tx_bufs[2][10] = {"Message 1", "Message 2"}; +static ZTEST_DMEM uint8_t chained_write_tx_bufs[2][10] = {"Message 1", "Message 2"}; #endif /* NOCACHE_MEM */ -ZTEST_DMEM bool chained_write_next_buf = true; -ZTEST_BMEM volatile uint8_t tx_sent; +static ZTEST_DMEM bool chained_write_next_buf = true; +static ZTEST_BMEM volatile uint8_t tx_sent; static void test_chained_write_callback(const struct device *dev, struct uart_event *evt, void *user_data) @@ -862,8 +862,8 @@ ZTEST_BMEM uint8_t long_rx_buf[RX_LONG_BUFFER]; ZTEST_BMEM uint8_t long_rx_buf2[RX_LONG_BUFFER]; ZTEST_BMEM uint8_t long_tx_buf[TX_LONG_BUFFER]; #endif /* NOCACHE_MEM */ -ZTEST_BMEM volatile uint8_t evt_num; -ZTEST_BMEM size_t long_received[2]; +static ZTEST_BMEM volatile uint8_t evt_num; +static ZTEST_BMEM size_t long_received[2]; static void test_long_buffers_callback(const struct device *dev, struct uart_event *evt, void *user_data) From c2267174d49dd4463f1a7fb5dfebf3ecc20d71d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 18 Jul 2024 14:28:51 +0200 Subject: [PATCH 07/15] tests: drivers: uart: async_api: Rework for multi instance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework the test to be able to run on multiple instances. Signed-off-by: Krzysztof Chruściński --- .../uart/uart_async_api/src/test_uart_async.c | 106 ++++++++++++------ 1 file changed, 73 insertions(+), 33 deletions(-) diff --git a/tests/drivers/uart/uart_async_api/src/test_uart_async.c b/tests/drivers/uart/uart_async_api/src/test_uart_async.c index 6ab3a837af2f..cf7cd78822e4 100644 --- a/tests/drivers/uart/uart_async_api/src/test_uart_async.c +++ b/tests/drivers/uart/uart_async_api/src/test_uart_async.c @@ -25,39 +25,49 @@ K_SEM_DEFINE(rx_buf_released, 0, 1); K_SEM_DEFINE(rx_disabled, 0, 1); static ZTEST_BMEM volatile bool failed_in_isr; -static ZTEST_BMEM const struct device *const uart_dev = - DEVICE_DT_GET(UART_NODE); + +struct dut_data { + const struct device *dev; + const char *name; +}; + +static ZTEST_DMEM struct dut_data duts[] = { + { + .dev = DEVICE_DT_GET(UART_NODE), + .name = DT_NODE_FULL_NAME(UART_NODE), + }, + /* More instances can be added here. */ +}; + +static ZTEST_BMEM const struct device *uart_dev; +static ZTEST_BMEM const char *uart_name; static void read_abort_timeout(struct k_timer *timer); static K_TIMER_DEFINE(read_abort_timer, read_abort_timeout, NULL); -static void init_test(void) -{ - __ASSERT_NO_MSG(device_is_ready(uart_dev)); - uart_rx_disable(uart_dev); - uart_tx_abort(uart_dev); - k_sem_reset(&tx_done); - k_sem_reset(&tx_aborted); - k_sem_reset(&rx_rdy); - k_sem_reset(&rx_buf_released); - k_sem_reset(&rx_disabled); -} - #ifdef CONFIG_USERSPACE static void set_permissions(void) { k_thread_access_grant(k_current_get(), &tx_done, &tx_aborted, &rx_rdy, &rx_buf_coherency, &rx_buf_released, &rx_disabled, uart_dev, &read_abort_timer); + + for (size_t i = 0; i < ARRAY_SIZE(duts); i++) { + k_thread_access_grant(k_current_get(), duts[i].dev); + } } #endif -static void uart_async_test_init(void) +static void uart_async_test_init(int idx) { static bool initialized; + uart_dev = duts[idx].dev; + uart_name = duts[idx].name; + __ASSERT_NO_MSG(device_is_ready(uart_dev)); + TC_PRINT("UART instance:%s\n", uart_name); uart_rx_disable(uart_dev); uart_tx_abort(uart_dev); k_sem_reset(&tx_done); @@ -79,7 +89,6 @@ static void uart_async_test_init(void) #endif if (!initialized) { - init_test(); initialized = true; #ifdef CONFIG_USERSPACE set_permissions(); @@ -143,11 +152,13 @@ static void test_single_read_callback(const struct device *dev, } } -ZTEST_BMEM volatile uint32_t tx_aborted_count; +static ZTEST_BMEM volatile uint32_t tx_aborted_count; static void *single_read_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); memset(&tdata, 0, sizeof(tdata)); tdata.supply_second_buffer = true; @@ -228,7 +239,9 @@ ZTEST_USER(uart_async_single_read, test_single_read) static void *multiple_rx_enable_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); memset(&tdata, 0, sizeof(tdata)); /* Reuse the callback from the single_read test case, as this test case @@ -369,7 +382,9 @@ static void test_chained_read_callback(const struct device *dev, static void *chained_read_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); uart_callback_set(uart_dev, test_chained_read_callback, NULL); @@ -450,7 +465,9 @@ static void test_double_buffer_callback(const struct device *dev, static void *double_buffer_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); uart_callback_set(uart_dev, test_double_buffer_callback, NULL); @@ -496,6 +513,7 @@ static ZTEST_BMEM uint8_t test_read_abort_rx_buf[2][100]; static ZTEST_BMEM uint8_t test_read_abort_read_buf[100]; #endif /* NOCACHE_MEM */ static ZTEST_BMEM int test_read_abort_rx_cnt; +static ZTEST_BMEM bool test_read_abort_rx_buf_req_once; static void test_read_abort_callback(const struct device *dev, struct uart_event *evt, void *user_data) @@ -510,14 +528,12 @@ static void test_read_abort_callback(const struct device *dev, break; case UART_RX_BUF_REQUEST: { - static bool once; - - if (!once) { + if (!test_read_abort_rx_buf_req_once) { k_sem_give(&rx_buf_coherency); uart_rx_buf_rsp(dev, test_read_abort_rx_buf[1], sizeof(test_read_abort_rx_buf[1])); - once = true; + test_read_abort_rx_buf_req_once = true; } break; } @@ -553,8 +569,11 @@ static void read_abort_timeout(struct k_timer *timer) static void *read_abort_setup(void) { - uart_async_test_init(); + static int idx; + uart_async_test_init(idx++); + + test_read_abort_rx_buf_req_once = false; failed_in_isr = false; uart_callback_set(uart_dev, test_read_abort_callback, NULL); @@ -649,7 +668,9 @@ static void test_write_abort_callback(const struct device *dev, static void *write_abort_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); uart_callback_set(uart_dev, test_write_abort_callback, NULL); @@ -722,7 +743,9 @@ static void test_forever_timeout_callback(const struct device *dev, static void *forever_timeout_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); uart_callback_set(uart_dev, test_forever_timeout_callback, NULL); @@ -811,8 +834,12 @@ static void test_chained_write_callback(const struct device *dev, static void *chained_write_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); + tx_sent = 0; + chained_write_next_buf = true; uart_callback_set(uart_dev, test_chained_write_callback, NULL); return NULL; @@ -864,11 +891,11 @@ ZTEST_BMEM uint8_t long_tx_buf[TX_LONG_BUFFER]; #endif /* NOCACHE_MEM */ static ZTEST_BMEM volatile uint8_t evt_num; static ZTEST_BMEM size_t long_received[2]; +static ZTEST_BMEM uint8_t *long_next_buffer; static void test_long_buffers_callback(const struct device *dev, struct uart_event *evt, void *user_data) { - static uint8_t *next_buffer = long_rx_buf2; switch (evt->type) { case UART_TX_DONE: @@ -890,8 +917,8 @@ static void test_long_buffers_callback(const struct device *dev, k_sem_give(&rx_disabled); break; case UART_RX_BUF_REQUEST: - uart_rx_buf_rsp(dev, next_buffer, RX_LONG_BUFFER); - next_buffer = (next_buffer == long_rx_buf2) ? long_rx_buf : long_rx_buf2; + uart_rx_buf_rsp(dev, long_next_buffer, RX_LONG_BUFFER); + long_next_buffer = (long_next_buffer == long_rx_buf2) ? long_rx_buf : long_rx_buf2; break; default: break; @@ -900,8 +927,12 @@ static void test_long_buffers_callback(const struct device *dev, static void *long_buffers_setup(void) { - uart_async_test_init(); + static int idx; + uart_async_test_init(idx++); + + evt_num = 0; + long_next_buffer = long_rx_buf2; uart_callback_set(uart_dev, test_long_buffers_callback, NULL); return NULL; @@ -983,3 +1014,12 @@ ZTEST_SUITE(uart_async_write_abort, NULL, write_abort_setup, ZTEST_SUITE(uart_async_timeout, NULL, forever_timeout_setup, NULL, NULL, NULL); + +void test_main(void) +{ + /* Run all suites for each dut UART. Setup function for each suite is picking + * next UART from the array. + */ + ztest_run_all(NULL, false, ARRAY_SIZE(duts), 1); + ztest_verify_all_test_suites_ran(); +} From c6ccc48509ab6aad03e509be9a00e929348d5e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 19 Jul 2024 14:52:43 +0200 Subject: [PATCH 08/15] tests: drivers: uart: async_api: Fix nrf54h20dk cpurad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix target which was failing due to lack of memory for DMA buffers. Signed-off-by: Krzysztof Chruściński --- .../uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay index beca628a2f08..87da56b19e70 100644 --- a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -2,6 +2,10 @@ #include "nrf54h20dk_nrf54h20_common.dtsi" +&cpurad_dma_region { + reg = <0xe80 DT_SIZE_K(4)>; +}; + &dut { memory-regions = <&cpurad_dma_region>; }; From 247ea3d04a8adc99744c27395403ed3efe1d26f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 18 Jul 2024 14:20:33 +0200 Subject: [PATCH 09/15] tests: drivers: uart: async_api: Add uart120 instance to nrf54h20dk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add second instance to be tested on nrf54h20dk. uart120 is a fast UARTE which works on fixed pin locations. It is not available for cpuppr core. Signed-off-by: Krzysztof Chruściński --- .../boards/nrf54h20dk_nrf54h20_common.dtsi | 32 +++++++++++++++++-- .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 8 +++++ .../boards/nrf54h20dk_nrf54h20_cpuppr.overlay | 4 +++ .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 8 +++++ .../uart/uart_async_api/src/test_uart_async.c | 9 ++++-- 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_common.dtsi index 9aa338deaad7..ecfbef2d9d63 100644 --- a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_common.dtsi +++ b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -3,8 +3,11 @@ &pinctrl { uart137_default_alt: uart137_default_alt { group1 { - psels = , - ; + psels = ; + }; + group2 { + psels = ; + bias-pull-up; }; }; @@ -15,6 +18,23 @@ low-power-enable; }; }; + uart120_default_alt: uart120_default_alt { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart120_sleep_alt: uart120_sleep_alt { + group1 { + psels = , + ; + low-power-enable; + }; + }; }; dut: &uart137 { @@ -24,3 +44,11 @@ dut: &uart137 { pinctrl-names = "default", "sleep"; current-speed = <115200>; }; + +dut2: &uart120 { + status = "okay"; + pinctrl-0 = <&uart120_default_alt>; + pinctrl-1 = <&uart120_sleep_alt>; + pinctrl-names = "default", "sleep"; + current-speed = <115200>; +}; diff --git a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index be5897fd0516..386782a4e79e 100644 --- a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -5,3 +5,11 @@ &dut { memory-regions = <&cpuapp_dma_region>; }; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; + +&dma_fast_region { + status = "okay"; +}; diff --git a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuppr.overlay b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuppr.overlay index f65b4dd3b0ba..8dd36819dff5 100644 --- a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuppr.overlay +++ b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuppr.overlay @@ -1,3 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include "nrf54h20dk_nrf54h20_common.dtsi" + +dut2: &uart120 { + status = "disabled"; +}; diff --git a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay index 87da56b19e70..8881f7abc47f 100644 --- a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -9,3 +9,11 @@ &dut { memory-regions = <&cpurad_dma_region>; }; + +&dma_fast_region { + status = "okay"; +}; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; diff --git a/tests/drivers/uart/uart_async_api/src/test_uart_async.c b/tests/drivers/uart/uart_async_api/src/test_uart_async.c index cf7cd78822e4..e93850d2bc1d 100644 --- a/tests/drivers/uart/uart_async_api/src/test_uart_async.c +++ b/tests/drivers/uart/uart_async_api/src/test_uart_async.c @@ -31,12 +31,17 @@ struct dut_data { const char *name; }; -static ZTEST_DMEM struct dut_data duts[] = { +ZTEST_DMEM struct dut_data duts[] = { { .dev = DEVICE_DT_GET(UART_NODE), .name = DT_NODE_FULL_NAME(UART_NODE), }, - /* More instances can be added here. */ +#if DT_NODE_EXISTS(DT_NODELABEL(dut2)) && DT_NODE_HAS_STATUS(DT_NODELABEL(dut2), okay) + { + .dev = DEVICE_DT_GET(DT_NODELABEL(dut2)), + .name = DT_NODE_FULL_NAME(DT_NODELABEL(dut2)), + }, +#endif }; static ZTEST_BMEM const struct device *uart_dev; From 2cd23741bc6b629cd61a20b48541a2bc36c98499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 4 Jul 2024 13:27:45 +0200 Subject: [PATCH 10/15] tests: drivers: uart: mix_fifo_poll: Add nrf54h20 cpuppr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add configuration for nrf54h20dk/nrf54h20/cpuppr. Signed-off-by: Krzysztof Chruściński --- .../boards/nrf54h20dk_nrf54h20_cpuppr.overlay | 11 ++++ .../drivers/uart/uart_mix_fifo_poll/prj.conf | 10 +++- .../uart/uart_mix_fifo_poll/src/main.c | 29 ++++++++-- .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 13 +++++ .../sysbuild/vpr_launcher/prj.conf | 1 + .../uart/uart_mix_fifo_poll/testcase.yaml | 53 +++---------------- 6 files changed, 63 insertions(+), 54 deletions(-) create mode 100644 tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuppr.overlay create mode 100644 tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay create mode 100644 tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/prj.conf diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuppr.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuppr.overlay new file mode 100644 index 000000000000..178aea353d51 --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuppr.overlay @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&timer137 { + interrupts = <467 (NRF_DEFAULT_IRQ_PRIORITY + 1)>; +}; + +&dut { + interrupts = <470 (NRF_DEFAULT_IRQ_PRIORITY + 1)>; +}; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/prj.conf b/tests/drivers/uart/uart_mix_fifo_poll/prj.conf index fa22b3a47b89..41c7920a1f8a 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/prj.conf +++ b/tests/drivers/uart/uart_mix_fifo_poll/prj.conf @@ -1,11 +1,17 @@ CONFIG_SERIAL=y CONFIG_ZTEST=y -CONFIG_TEST_USERSPACE=y +CONFIG_TEST_USERSPACE=n CONFIG_ZTEST_THREAD_PRIORITY=5 CONFIG_MAIN_STACK_SIZE=2048 CONFIG_ZTEST_STACK_SIZE=2048 CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_COUNTER=y -# CONFIG_NO_OPTIMIZATIONS=y +CONFIG_OUTPUT_DISASSEMBLY=y +#CONFIG_NO_OPTIMIZATIONS=y # CONFIG_LOG_MODE_MINIMAL=n +#CONFIG_LOG=y +#CONFIG_LOG_BUFFER_SIZE=16384 +#CONFIG_TEST_LOGGING_DEFAULTS=n + +CONFIG_TEST_EXTRA_STACK_SIZE=2048 diff --git a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c index eaebe8e132e5..23a5eb50613b 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c +++ b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c @@ -15,6 +15,8 @@ #include #include #include +#include +LOG_MODULE_REGISTER(test, 0); /* RX and TX pins have to be connected together*/ #if DT_NODE_EXISTS(DT_NODELABEL(dut)) @@ -71,6 +73,7 @@ static const struct device *const uart_dev = static bool async; static bool int_driven; +static volatile bool error_found; static volatile bool async_rx_enabled; static struct k_sem async_tx_sem; @@ -84,6 +87,10 @@ static void process_byte(uint8_t b) struct rx_source *src = &source[base]; bool ok; + if (error_found) { + return; + } + b &= 0x0F; src->cnt++; @@ -94,6 +101,12 @@ static void process_byte(uint8_t b) ok = ((b - src->prev) == 1) || (!b && (src->prev == 0x0F)); + if (!ok) { + error_found = true; + LOG_ERR("Unexpected byte received:0x%02x, prev:0x%02x", + (base << 4) | b, (base << 4) | src->prev); + }; + zassert_true(ok, "Unexpected byte received:0x%02x, prev:0x%02x", (base << 4) | b, (base << 4) | src->prev); src->prev = b; @@ -224,6 +237,10 @@ static void bulk_poll_out(struct test_data *data, int wait_base, int wait_range) { for (int i = 0; i < data->max; i++) { + if (error_found) { + goto bail; + } + data->cnt++; uart_poll_out(uart_dev, data->buf[i % BUF_SIZE]); if (wait_base) { @@ -232,7 +249,7 @@ static void bulk_poll_out(struct test_data *data, int wait_base, int wait_range) k_sleep(K_USEC(wait_base + (r % wait_range))); } } - +bail: k_sem_give(&data->sem); } @@ -241,10 +258,10 @@ static void poll_out_thread(void *data, void *unused0, void *unused1) bulk_poll_out((struct test_data *)data, 200, 600); } -K_THREAD_STACK_DEFINE(high_poll_out_thread_stack, 1024); +K_THREAD_STACK_DEFINE(high_poll_out_thread_stack, 2048); static struct k_thread high_poll_out_thread; -K_THREAD_STACK_DEFINE(int_async_thread_stack, 1024); +K_THREAD_STACK_DEFINE(int_async_thread_stack, 2048); static struct k_thread int_async_thread; static void int_async_thread_func(void *p_data, void *base, void *range) @@ -255,7 +272,7 @@ static void int_async_thread_func(void *p_data, void *base, void *range) k_sem_init(&async_tx_sem, 1, 1); - while (data->cnt < data->max) { + while (!error_found && (data->cnt < data->max)) { if (async) { int err; @@ -287,7 +304,9 @@ static void poll_out_timer_handler(struct k_timer *timer) { struct test_data *data = k_timer_user_data_get(timer); - uart_poll_out(uart_dev, data->buf[data->cnt % BUF_SIZE]); + if (!error_found) { + uart_poll_out(uart_dev, data->buf[data->cnt % BUF_SIZE]); + } data->cnt++; if (data->cnt == data->max) { diff --git a/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 000000000000..9e38ed36b133 --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "../../../boards/nrf54h20dk_nrf54h20_common.dtsi" + +&dut { + status = "reserved"; + interrupt-parent = <&cpuppr_clic>; +}; + +&timer137 { + status = "reserved"; + interrupt-parent = <&cpuppr_clic>; +}; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/prj.conf b/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/prj.conf new file mode 100644 index 000000000000..b2a4ba591044 --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/prj.conf @@ -0,0 +1 @@ +# nothing here diff --git a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml index 1b13bc571662..18056b7000d3 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml +++ b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml @@ -22,32 +22,22 @@ tests: - CONFIG_UART_INTERRUPT_DRIVEN=n - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n drivers.uart.uart_mix_poll_fifo: extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=y - - CONFIG_UART_0_INTERRUPT_DRIVEN=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n drivers.uart.uart_mix_poll_async_api: extra_configs: - CONFIG_UART_ASYNC_API=y - - CONFIG_UART_0_INTERRUPT_DRIVEN=n - - CONFIG_UART_0_ASYNC=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n drivers.uart.uart_mix_poll_async_api_const: extra_args: TEST_CONST_BUFFER=1 extra_configs: - CONFIG_UART_ASYNC_API=y - - CONFIG_UART_0_INTERRUPT_DRIVEN=n - - CONFIG_UART_0_ASYNC=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_0_TX_CACHE_SIZE=2 - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n tags: bsim_skip_CI # We skip a few tests to save CI time, as they give little extra coverage drivers.uart.uart_mix_poll_with_ppi: @@ -55,59 +45,28 @@ tests: - CONFIG_UART_INTERRUPT_DRIVEN=n - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=y - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n tags: bsim_skip_CI - - drivers.uart.uart_mix_poll_fifo_with_ppi: - extra_configs: - - CONFIG_UART_INTERRUPT_DRIVEN=y - - CONFIG_UART_0_INTERRUPT_DRIVEN=y - - CONFIG_UART_0_ENHANCED_POLL_OUT=y - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n - tags: bsim_skip_CI - - drivers.uart.uart_mix_poll_async_api_with_ppi: - extra_configs: - - CONFIG_UART_ASYNC_API=y - - CONFIG_UART_0_INTERRUPT_DRIVEN=n - - CONFIG_UART_0_ASYNC=y - - CONFIG_UART_0_ENHANCED_POLL_OUT=y - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n - tags: bsim_skip_CI - - drivers.uart.legacy.uart_mix_poll: - extra_configs: - - CONFIG_UART_INTERRUPT_DRIVEN=n - - CONFIG_UART_ASYNC_API=n - - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y platform_exclude: - - nrf54l15dk/nrf54l15/cpuapp - nrf54h20dk/nrf54h20/cpuapp - nrf54h20dk/nrf54h20/cpurad - drivers.uart.legacy.uart_mix_poll_fifo: + drivers.uart.uart_mix_poll_fifo_with_ppi: extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=y - CONFIG_UART_0_INTERRUPT_DRIVEN=y - - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y + - CONFIG_UART_0_ENHANCED_POLL_OUT=y + tags: bsim_skip_CI platform_exclude: - - nrf54l15dk/nrf54l15/cpuapp - nrf54h20dk/nrf54h20/cpuapp - nrf54h20dk/nrf54h20/cpurad - drivers.uart.legacy.uart_mix_poll_async_api: + drivers.uart.uart_mix_poll_async_api_with_ppi: extra_configs: - CONFIG_UART_ASYNC_API=y - CONFIG_UART_0_INTERRUPT_DRIVEN=n - CONFIG_UART_0_ASYNC=y - - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_0_NRF_HW_ASYNC=y - - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - - CONFIG_NRFX_TIMER2=y - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y + - CONFIG_UART_0_ENHANCED_POLL_OUT=y + tags: bsim_skip_CI platform_exclude: - - nrf54l15dk/nrf54l15/cpuapp - nrf54h20dk/nrf54h20/cpuapp - nrf54h20dk/nrf54h20/cpurad From 9e3e077dfae5b66655cb6de518f817a56e8f040f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 19 Jul 2024 08:19:16 +0200 Subject: [PATCH 11/15] tests: drivers: uart: mix_fifo_poll: Rework to support multi-instance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework test to allow testing multiple UART instances in a single run. Signed-off-by: Krzysztof Chruściński --- .../uart/uart_mix_fifo_poll/src/main.c | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c index 23a5eb50613b..37c3685d071c 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c +++ b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c @@ -42,6 +42,18 @@ struct rx_source { uint8_t prev; }; +struct dut_data { + const struct device *dev; + const char *name; +}; + +static struct dut_data duts[] = { + { + .dev = DEVICE_DT_GET(UART_NODE), + .name = DT_NODE_FULL_NAME(UART_NODE), + }, +}; + #define BUF_SIZE 16 /* Buffer used for polling. */ @@ -68,8 +80,7 @@ static struct test_data int_async_data; static const struct device *const counter_dev = DEVICE_DT_GET(COUNTER_NODE); -static const struct device *const uart_dev = - DEVICE_DT_GET(UART_NODE); +static const struct device *uart_dev; static bool async; static bool int_driven; @@ -112,8 +123,10 @@ static void process_byte(uint8_t b) src->prev = b; } +static volatile bool in_counter_isr; static void counter_top_handler(const struct device *dev, void *user_data) { + in_counter_isr = true; static bool enable = true; static uint8_t async_rx_buf[4]; @@ -139,9 +152,10 @@ static void counter_top_handler(const struct device *dev, void *user_data) process_byte(c); } } + in_counter_isr = false; } -static void init_test(void) +static void init_test(int idx) { int err; struct counter_top_cfg top_cfg = { @@ -150,6 +164,12 @@ static void init_test(void) .flags = 0 }; + memset(source, 0, sizeof(source)); + error_found = false; + async_rx_enabled = false; + uart_dev = duts[idx].dev; + TC_PRINT("UART instance:%s\n", duts[idx].name); + zassert_true(device_is_ready(uart_dev), "uart device is not ready"); if (uart_callback_set(uart_dev, async_callback, NULL) == 0) { @@ -388,10 +408,21 @@ ZTEST(uart_mix_fifo_poll, test_mixed_uart_access) void *uart_mix_setup(void) { - init_test(); + static int idx; + + init_test(idx++); return NULL; } ZTEST_SUITE(uart_mix_fifo_poll, NULL, uart_mix_setup, NULL, NULL, NULL); + +void test_main(void) +{ + /* Run all suites for each dut UART. Setup function for each suite is picking + * next UART from the array. + */ + ztest_run_all(NULL, false, ARRAY_SIZE(duts), 1); + ztest_verify_all_test_suites_ran(); +} From 79ad9244d8406b86159d7ae6c1318b3932473d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 19 Jul 2024 08:43:16 +0200 Subject: [PATCH 12/15] tests: drivers: uart: mix_fifo_poll: Add UARTE120 to nrf54h20dk test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add configuration for UARTE120 fast instance. Use multi-instance capability of the test to run same test on UARTE120 and slow UARTE peripheral. Signed-off-by: Krzysztof Chruściński --- .../boards/nrf54h20dk_nrf54h20_common.dtsi | 31 ++++++++++++++++++- .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 8 +++++ .../boards/nrf54h20dk_nrf54h20_cpuppr.overlay | 5 +++ .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 8 +++++ .../uart/uart_mix_fifo_poll/src/main.c | 6 ++++ 5 files changed, 57 insertions(+), 1 deletion(-) diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_common.dtsi index c102d617f900..7a76d46f3f07 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_common.dtsi +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -19,6 +19,27 @@ low-power-enable; }; }; + uart120_default_alt: uart120_default_alt { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart120_sleep_alt: uart120_sleep_alt { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; }; dut: &uart137 { @@ -30,7 +51,15 @@ dut: &uart137 { hw-flow-control; }; -/* Use timer137 as only this one can generate interrupts on cpusys. */ +dut2: &uart120 { + status = "okay"; + pinctrl-0 = <&uart120_default_alt>; + pinctrl-1 = <&uart120_sleep_alt>; + pinctrl-names = "default", "sleep"; + current-speed = <115200>; + hw-flow-control; +}; + counter_dev: &timer137 { status = "okay"; }; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index c6ff4eb77af3..18889762fb71 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -6,6 +6,14 @@ memory-regions = <&cpuapp_dma_region>; }; +&dma_fast_region { + status = "okay"; +}; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; + &grtc { interrupts = <109 2>; }; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuppr.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuppr.overlay index 178aea353d51..d846a5debd78 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuppr.overlay +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuppr.overlay @@ -9,3 +9,8 @@ &dut { interrupts = <470 (NRF_DEFAULT_IRQ_PRIORITY + 1)>; }; + +/* PPR cannot use that instance. */ +&uart120 { + status = "disabled" +}; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpurad.overlay index 0ded983c2af8..fb124227771b 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -6,6 +6,14 @@ memory-regions = <&cpurad_dma_region>; }; +&dma_fast_region { + status = "okay"; +}; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; + &grtc { interrupts = <109 2>; }; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c index 37c3685d071c..e3935372dce4 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c +++ b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c @@ -52,6 +52,12 @@ static struct dut_data duts[] = { .dev = DEVICE_DT_GET(UART_NODE), .name = DT_NODE_FULL_NAME(UART_NODE), }, +#if DT_NODE_EXISTS(DT_NODELABEL(dut2)) + { + .dev = DEVICE_DT_GET(DT_NODELABEL(dut2)), + .name = DT_NODE_FULL_NAME(DT_NODELABEL(dut2)), + }, +#endif }; #define BUF_SIZE 16 From 5842b0a31d9f1b71fec5c9ef52783de04bd632f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 12 Nov 2024 12:37:18 +0100 Subject: [PATCH 13/15] drivers: serial: nrfx_uarte: Fix pin retention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit b6d45423c60b Added support for pin retention but it was added only to the case when device PM is used. There is another mode in which UARTE is disabled when idle (low power mode) and in that case pin retention must also be added. Signed-off-by: Krzysztof Chruściński --- drivers/serial/uart_nrfx_uarte.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 452307acaa83..6acb6e44fbd8 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -590,6 +590,9 @@ static void uarte_periph_enable(const struct device *dev) (void)data; nrf_uarte_enable(uarte); +#ifdef CONFIG_SOC_NRF54H20_GPD + nrf_gpd_retain_pins_set(config->pcfg, false); +#endif #if UARTE_BAUDRATE_RETENTION_WORKAROUND nrf_uarte_baudrate_set(uarte, COND_CODE_1(CONFIG_UART_USE_RUNTIME_CONFIGURE, @@ -702,6 +705,11 @@ static void uarte_disable_locked(const struct device *dev, uint32_t dis_mask) } #endif +#ifdef CONFIG_SOC_NRF54H20_GPD + const struct uarte_nrfx_config *cfg = dev->config; + + nrf_gpd_retain_pins_set(cfg->pcfg, true); +#endif nrf_uarte_disable(get_uarte_instance(dev)); } @@ -2103,9 +2111,6 @@ static void uarte_pm_resume(const struct device *dev) if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) || !LOW_POWER_ENABLED(cfg)) { uarte_periph_enable(dev); -#ifdef CONFIG_SOC_NRF54H20_GPD - nrf_gpd_retain_pins_set(cfg->pcfg, false); -#endif } } From 409bd99fe9b1c121ffc557b60063b5b428ce68b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 12 Nov 2024 12:48:49 +0100 Subject: [PATCH 14/15] dts: bindings: serial: nrfx_uarte: Add pin-retention property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add property to nrfx_uarte which indicates that pins must be retained for the given instance when it is disabled. Add that property to uart120 instances as those always require that since pins are routed through CTRLSEL. For other instances there are exceptions when CTRLSEL is used (see the specification). Signed-off-by: Krzysztof Chruściński --- dts/bindings/serial/nordic,nrf-uarte.yaml | 6 ++++++ dts/common/nordic/nrf54h20.dtsi | 1 + dts/common/nordic/nrf9280.dtsi | 1 + 3 files changed, 8 insertions(+) diff --git a/dts/bindings/serial/nordic,nrf-uarte.yaml b/dts/bindings/serial/nordic,nrf-uarte.yaml index e6ba4c0b2147..6d1c0f70eab3 100644 --- a/dts/bindings/serial/nordic,nrf-uarte.yaml +++ b/dts/bindings/serial/nordic,nrf-uarte.yaml @@ -14,3 +14,9 @@ properties: type: boolean description: | UARTE has RX frame timeout HW feature. + pin-retention: + type: boolean + description: | + UARTE pin states must be retained when peripheral is disabled. + It is required when CTRLSEL is used to route UARTE pins. It is always the + case for fast peripheral and in special cases for slow peripherals. diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index b28ddb83fdb3..14d73f0eb3bf 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -669,6 +669,7 @@ power-domains = <&gpd NRF_GPD_FAST_ACTIVE1>; endtx-stoptx-supported; frame-timeout-supported; + pin-retention; }; spi121: spi@8e7000 { diff --git a/dts/common/nordic/nrf9280.dtsi b/dts/common/nordic/nrf9280.dtsi index 45b05f9262ee..9d00dddb052e 100644 --- a/dts/common/nordic/nrf9280.dtsi +++ b/dts/common/nordic/nrf9280.dtsi @@ -508,6 +508,7 @@ interrupts = <230 NRF_DEFAULT_IRQ_PRIORITY>; endtx-stoptx-supported; frame-timeout-supported; + pin-retention; }; spi121: spi@8e7000 { From e7dcac655e8fd6145ee12f134edb3887c77fdf04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 12 Nov 2024 12:50:34 +0100 Subject: [PATCH 15/15] drivers: serial: nrfx_uarte: Retain pins only when needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since pin retantion is done as a part of suspend/resume which is done in the critical section, it shall be done only when needed. Use DT flag to determine which UARTE instance needs it. Signed-off-by: Krzysztof Chruściński --- drivers/serial/uart_nrfx_uarte.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 6acb6e44fbd8..c2bb35a82148 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -242,6 +242,9 @@ struct uarte_nrfx_data { /* If enabled then UARTE peripheral is using memory which is cacheable. */ #define UARTE_CFG_FLAG_CACHEABLE BIT(3) +/* If enabled then pins must be retained when UARTE is disabled. */ +#define UARTE_CFG_FLAG_RETAIN_PINS BIT(4) + /* Macro for converting numerical baudrate to register value. It is convenient * to use this approach because for constant input it can calculate nrf setting * at compile time. @@ -591,7 +594,9 @@ static void uarte_periph_enable(const struct device *dev) (void)data; nrf_uarte_enable(uarte); #ifdef CONFIG_SOC_NRF54H20_GPD - nrf_gpd_retain_pins_set(config->pcfg, false); + if (config->flags & UARTE_CFG_FLAG_RETAIN_PINS) { + nrf_gpd_retain_pins_set(config->pcfg, false); + } #endif #if UARTE_BAUDRATE_RETENTION_WORKAROUND nrf_uarte_baudrate_set(uarte, @@ -708,7 +713,9 @@ static void uarte_disable_locked(const struct device *dev, uint32_t dis_mask) #ifdef CONFIG_SOC_NRF54H20_GPD const struct uarte_nrfx_config *cfg = dev->config; - nrf_gpd_retain_pins_set(cfg->pcfg, true); + if (cfg->flags & UARTE_CFG_FLAG_RETAIN_PINS) { + nrf_gpd_retain_pins_set(cfg->pcfg, true); + } #endif nrf_uarte_disable(get_uarte_instance(dev)); } @@ -2174,7 +2181,9 @@ static void uarte_pm_suspend(const struct device *dev) } #ifdef CONFIG_SOC_NRF54H20_GPD - nrf_gpd_retain_pins_set(cfg->pcfg, true); + if (cfg->flags & UARTE_CFG_FLAG_RETAIN_PINS) { + nrf_gpd_retain_pins_set(cfg->pcfg, true); + } #endif nrf_uarte_disable(uarte); @@ -2388,6 +2397,8 @@ static int uarte_instance_init(const struct device *dev, (!IS_ENABLED(CONFIG_HAS_NORDIC_DMM) ? 0 : \ (UARTE_IS_CACHEABLE(idx) ? \ UARTE_CFG_FLAG_CACHEABLE : 0)) | \ + (UARTE_PROP(idx, pin_retention) ? \ + UARTE_CFG_FLAG_RETAIN_PINS : 0) | \ USE_LOW_POWER(idx), \ UARTE_DISABLE_RX_INIT(UARTE(idx)), \ .poll_out_byte = &uarte##idx##_poll_out_byte, \