tests: drivers: uart: Add test for uart power management
Added test which validates that uart device correctly handles going to and from low power state. Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
parent
7d61be9e79
commit
eb949d01d3
6 changed files with 383 additions and 0 deletions
9
tests/drivers/uart/uart_pm/CMakeLists.txt
Normal file
9
tests/drivers/uart/uart_pm/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.13.1)
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(uart_basic_api)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
src/main.c
|
||||
)
|
|
@ -0,0 +1,26 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zephyr,console = &uart1;
|
||||
};
|
||||
};
|
||||
|
||||
&uart1 {
|
||||
current-speed = <115200>;
|
||||
status = "okay";
|
||||
tx-pin = <6>;
|
||||
rx-pin = <8>;
|
||||
rts-pin = <0>;
|
||||
cts-pin = <0>;
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
compatible = "nordic,nrf-uarte";
|
||||
current-speed = <115200>;
|
||||
status = "okay";
|
||||
tx-pin = <33>;
|
||||
rx-pin = <34>;
|
||||
rts-pin = <5>;
|
||||
cts-pin = <7>;
|
||||
};
|
5
tests/drivers/uart/uart_pm/nrf_no_rx_pin.overlay
Normal file
5
tests/drivers/uart/uart_pm/nrf_no_rx_pin.overlay
Normal file
|
@ -0,0 +1,5 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
&uart0 {
|
||||
/delete-property/rx-pin;
|
||||
};
|
5
tests/drivers/uart/uart_pm/prj.conf
Normal file
5
tests/drivers/uart/uart_pm/prj.conf
Normal file
|
@ -0,0 +1,5 @@
|
|||
CONFIG_ZTEST=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_NATIVE_UART_0_ON_STDINOUT=y
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_DEVICE=y
|
267
tests/drivers/uart/uart_pm/src/main.c
Normal file
267
tests/drivers/uart/uart_pm/src/main.c
Normal file
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <drivers/uart.h>
|
||||
#include <device.h>
|
||||
#include <pm/device.h>
|
||||
#include <ztest.h>
|
||||
|
||||
#if defined(CONFIG_BOARD_NRF52840DK_NRF52840)
|
||||
#define LABEL uart0
|
||||
#endif
|
||||
|
||||
#define UART_DEVICE_NAME DT_LABEL(DT_NODELABEL(LABEL))
|
||||
#define HAS_RX DT_NODE_HAS_PROP(DT_NODELABEL(LABEL), rx_pin)
|
||||
|
||||
static const struct device *exp_dev;
|
||||
static uint32_t exp_state;
|
||||
static void *exp_arg;
|
||||
static volatile int callback_cnt;
|
||||
|
||||
static void polling_verify(const struct device *dev, bool is_async, bool active)
|
||||
{
|
||||
char c;
|
||||
char outs[] = "abc";
|
||||
int err;
|
||||
|
||||
if (!HAS_RX || is_async) {
|
||||
/* If no RX pin just run few poll outs to check that it does
|
||||
* not hang.
|
||||
*/
|
||||
for (int i = 0; i < ARRAY_SIZE(outs); i++) {
|
||||
uart_poll_out(dev, outs[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
err = uart_poll_in(dev, &c);
|
||||
zassert_equal(err, -1, NULL);
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(outs); i++) {
|
||||
uart_poll_out(dev, outs[i]);
|
||||
k_busy_wait(1000);
|
||||
|
||||
if (active) {
|
||||
err = uart_poll_in(dev, &c);
|
||||
zassert_equal(err, 0, "Unexpected err: %d", err);
|
||||
zassert_equal(c, outs[i], NULL);
|
||||
}
|
||||
|
||||
err = uart_poll_in(dev, &c);
|
||||
zassert_equal(err, -1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void async_callback(const struct device *dev, struct uart_event *evt, void *ctx)
|
||||
{
|
||||
bool *done = ctx;
|
||||
|
||||
switch (evt->type) {
|
||||
case UART_TX_DONE:
|
||||
*done = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool async_verify(const struct device *dev, bool active)
|
||||
{
|
||||
char txbuf[] = "test";
|
||||
uint8_t rxbuf[32];
|
||||
volatile bool tx_done = false;
|
||||
int err;
|
||||
|
||||
err = uart_callback_set(dev, async_callback, (void *)&tx_done);
|
||||
if (err == -ENOTSUP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!active) {
|
||||
return true;
|
||||
}
|
||||
|
||||
zassert_equal(err, 0, "Unexpected err: %d", err);
|
||||
|
||||
if (HAS_RX) {
|
||||
err = uart_rx_enable(dev, rxbuf, sizeof(rxbuf), 1);
|
||||
zassert_equal(err, 0, "Unexpected err: %d", err);
|
||||
}
|
||||
|
||||
err = uart_tx(dev, txbuf, sizeof(txbuf), 10);
|
||||
zassert_equal(err, 0, "Unexpected err: %d", err);
|
||||
|
||||
k_busy_wait(10000);
|
||||
|
||||
if (HAS_RX) {
|
||||
err = uart_rx_disable(dev);
|
||||
zassert_equal(err, 0, "Unexpected err: %d", err);
|
||||
|
||||
k_busy_wait(10000);
|
||||
|
||||
err = memcmp(txbuf, rxbuf, sizeof(txbuf));
|
||||
zassert_equal(err, 0, "Unexpected err: %d", err);
|
||||
}
|
||||
|
||||
zassert_true(tx_done, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void communication_verify(const struct device *dev, bool active)
|
||||
{
|
||||
bool is_async = async_verify(dev, active);
|
||||
|
||||
polling_verify(dev, is_async, active);
|
||||
}
|
||||
|
||||
#define state_verify(dev, exp_state) do {\
|
||||
uint32_t power_state; \
|
||||
int err = pm_device_state_get(dev, &power_state); \
|
||||
zassert_equal(err, 0, "Unexpected err: %d", err); \
|
||||
zassert_equal(power_state, exp_state, NULL); \
|
||||
} while (0)
|
||||
|
||||
static void pm_callback(const struct device *dev,
|
||||
int status, uint32_t *state, void *arg)
|
||||
{
|
||||
zassert_equal(dev, exp_dev, NULL);
|
||||
zassert_equal(status, 0, NULL);
|
||||
zassert_equal(*state, exp_state, NULL);
|
||||
zassert_equal(arg, exp_arg, NULL);
|
||||
callback_cnt++;
|
||||
}
|
||||
|
||||
static void state_set(const struct device *dev, uint32_t state, int exp_err, bool cb)
|
||||
{
|
||||
int err;
|
||||
uint32_t prev_state;
|
||||
|
||||
err = pm_device_state_get(dev, &prev_state);
|
||||
zassert_equal(err, 0, "Unexpected err: %d", err);
|
||||
|
||||
if (cb) {
|
||||
callback_cnt = 0;
|
||||
exp_dev = dev;
|
||||
exp_arg = &state;
|
||||
exp_state = state;
|
||||
|
||||
err = pm_device_state_set(dev, state, pm_callback, exp_arg);
|
||||
zassert_equal(err, exp_err, "Unexpected err: %d", err);
|
||||
zassert_equal(callback_cnt, 1, NULL);
|
||||
} else {
|
||||
err = pm_device_state_set(dev, state, NULL, NULL);
|
||||
zassert_equal(err, exp_err, "Unexpected err: %d", err);
|
||||
}
|
||||
|
||||
uint32_t exp_state = err == 0 ? state : prev_state;
|
||||
|
||||
state_verify(dev, exp_state);
|
||||
}
|
||||
|
||||
static void test_uart_pm_in_idle(void)
|
||||
{
|
||||
const struct device *dev;
|
||||
|
||||
dev = device_get_binding(UART_DEVICE_NAME);
|
||||
zassert_true(dev != NULL, NULL);
|
||||
|
||||
state_verify(dev, PM_DEVICE_STATE_ACTIVE);
|
||||
communication_verify(dev, true);
|
||||
|
||||
state_set(dev, PM_DEVICE_STATE_LOW_POWER, 0, false);
|
||||
communication_verify(dev, false);
|
||||
|
||||
state_set(dev, PM_DEVICE_STATE_ACTIVE, 0, false);
|
||||
communication_verify(dev, true);
|
||||
|
||||
state_set(dev, PM_DEVICE_STATE_LOW_POWER, 0, true);
|
||||
communication_verify(dev, false);
|
||||
|
||||
state_set(dev, PM_DEVICE_STATE_ACTIVE, 0, true);
|
||||
communication_verify(dev, true);
|
||||
}
|
||||
|
||||
static void test_uart_pm_poll_tx(void)
|
||||
{
|
||||
const struct device *dev;
|
||||
|
||||
dev = device_get_binding(UART_DEVICE_NAME);
|
||||
zassert_true(dev != NULL, NULL);
|
||||
|
||||
communication_verify(dev, true);
|
||||
|
||||
uart_poll_out(dev, 'a');
|
||||
state_set(dev, PM_DEVICE_STATE_LOW_POWER, 0, false);
|
||||
|
||||
communication_verify(dev, false);
|
||||
|
||||
state_set(dev, PM_DEVICE_STATE_ACTIVE, 0, false);
|
||||
|
||||
communication_verify(dev, true);
|
||||
|
||||
/* Now same thing but with callback */
|
||||
uart_poll_out(dev, 'a');
|
||||
state_set(dev, PM_DEVICE_STATE_LOW_POWER, 0, true);
|
||||
|
||||
communication_verify(dev, false);
|
||||
|
||||
state_set(dev, PM_DEVICE_STATE_ACTIVE, 0, true);
|
||||
|
||||
communication_verify(dev, true);
|
||||
}
|
||||
|
||||
static void timeout(struct k_timer *timer)
|
||||
{
|
||||
const struct device *uart = k_timer_user_data_get(timer);
|
||||
|
||||
state_set(uart, PM_DEVICE_STATE_LOW_POWER, 0, false);
|
||||
}
|
||||
|
||||
static K_TIMER_DEFINE(pm_timer, timeout, NULL);
|
||||
|
||||
/* Test going into low power state after interrupting poll out. Use various
|
||||
* delays to test interruption at multiple places.
|
||||
*/
|
||||
static void test_uart_pm_poll_tx_interrupted(void)
|
||||
{
|
||||
const struct device *dev;
|
||||
char str[] = "test";
|
||||
|
||||
dev = device_get_binding(UART_DEVICE_NAME);
|
||||
zassert_true(dev != NULL, NULL);
|
||||
|
||||
k_timer_user_data_set(&pm_timer, (void *)dev);
|
||||
|
||||
for (int i = 1; i < 100; i++) {
|
||||
k_timer_start(&pm_timer, K_USEC(i * 10), K_NO_WAIT);
|
||||
|
||||
for (int j = 0; j < sizeof(str); j++) {
|
||||
uart_poll_out(dev, str[j]);
|
||||
}
|
||||
|
||||
k_timer_status_sync(&pm_timer);
|
||||
|
||||
state_set(dev, PM_DEVICE_STATE_ACTIVE, 0, false);
|
||||
|
||||
communication_verify(dev, true);
|
||||
}
|
||||
}
|
||||
|
||||
void test_main(void)
|
||||
{
|
||||
if (!HAS_RX) {
|
||||
PRINT("No RX pin\n");
|
||||
}
|
||||
|
||||
ztest_test_suite(uart_pm,
|
||||
ztest_unit_test(test_uart_pm_in_idle),
|
||||
ztest_unit_test(test_uart_pm_poll_tx),
|
||||
ztest_unit_test(test_uart_pm_poll_tx_interrupted)
|
||||
);
|
||||
ztest_run_test_suite(uart_pm);
|
||||
}
|
71
tests/drivers/uart/uart_pm/testcase.yaml
Normal file
71
tests/drivers/uart/uart_pm/testcase.yaml
Normal file
|
@ -0,0 +1,71 @@
|
|||
common:
|
||||
harness: ztest
|
||||
harness_config:
|
||||
fixture: gpio_loopback
|
||||
tests:
|
||||
drivers.uart:
|
||||
tags: drivers
|
||||
platform_allow: nrf52840dk_nrf52840
|
||||
extra_configs:
|
||||
- CONFIG_UART_INTERRUPT_DRIVEN=n
|
||||
- CONFIG_UART_ASYNC_API=n
|
||||
- CONFIG_UART_0_ENHANCED_POLL_OUT=n
|
||||
|
||||
drivers.uart_no_rxpin:
|
||||
tags: drivers
|
||||
platform_allow: nrf52840dk_nrf52840
|
||||
extra_configs:
|
||||
- CONFIG_UART_INTERRUPT_DRIVEN=n
|
||||
- CONFIG_UART_ASYNC_API=n
|
||||
- CONFIG_UART_0_ENHANCED_POLL_OUT=n
|
||||
extra_args: DTC_OVERLAY_FILE="boards/nrf52840dk_nrf52840.overlay;nrf_no_rx_pin.overlay"
|
||||
|
||||
drivers.uart_enhanced_poll:
|
||||
tags: drivers
|
||||
platform_allow: nrf52840dk_nrf52840
|
||||
extra_configs:
|
||||
- CONFIG_UART_INTERRUPT_DRIVEN=n
|
||||
- CONFIG_UART_ASYNC_API=n
|
||||
- CONFIG_UART_0_ENHANCED_POLL_OUT=y
|
||||
|
||||
drivers.uart_int_driven:
|
||||
tags: drivers
|
||||
platform_allow: nrf52840dk_nrf52840
|
||||
extra_configs:
|
||||
- CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||
- CONFIG_UART_0_INTERRUPT_DRIVEN=y
|
||||
- CONFIG_UART_ASYNC_API=n
|
||||
- CONFIG_UART_0_ENHANCED_POLL_OUT=n
|
||||
|
||||
drivers.uart_int_driven_enhanced_poll:
|
||||
tags: drivers
|
||||
platform_allow: nrf52840dk_nrf52840
|
||||
extra_configs:
|
||||
- CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||
- CONFIG_UART_0_INTERRUPT_DRIVEN=y
|
||||
- CONFIG_UART_ASYNC_API=n
|
||||
- CONFIG_UART_0_ENHANCED_POLL_OUT=y
|
||||
|
||||
drivers.uart_async:
|
||||
tags: drivers
|
||||
platform_allow: nrf52840dk_nrf52840
|
||||
extra_configs:
|
||||
- CONFIG_UART_INTERRUPT_DRIVEN=n
|
||||
- CONFIG_UART_ASYNC_API=y
|
||||
- CONFIG_UART_0_ASYNC=y
|
||||
- CONFIG_UART_0_NRF_HW_ASYNC=y
|
||||
- CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2
|
||||
- CONFIG_NRFX_TIMER2=y
|
||||
- CONFIG_UART_0_ENHANCED_POLL_OUT=n
|
||||
|
||||
drivers.uart_async_enhanced_poll:
|
||||
tags: drivers
|
||||
platform_allow: nrf52840dk_nrf52840
|
||||
extra_configs:
|
||||
- CONFIG_UART_INTERRUPT_DRIVEN=n
|
||||
- CONFIG_UART_ASYNC_API=y
|
||||
- CONFIG_UART_0_ASYNC=y
|
||||
- CONFIG_UART_0_NRF_HW_ASYNC=y
|
||||
- CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2
|
||||
- CONFIG_NRFX_TIMER2=y
|
||||
- CONFIG_UART_0_ENHANCED_POLL_OUT=y
|
Loading…
Add table
Add a link
Reference in a new issue