tests: drivers: i2s_api: Allow testing on nRF52840 DK and nRF5340 DK
Provide configurations for the nRF52840 DK and nRF5340 DK boards. Adjust the test to cover specifics of I2S peripherals on nRF SoCs (need of starting RX and TX simultaneously, lack of internal loopback). Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no>
This commit is contained in:
parent
5dcc876e0b
commit
954dfa755b
15 changed files with 867 additions and 268 deletions
|
@ -17,6 +17,7 @@ supported:
|
||||||
- counter
|
- counter
|
||||||
- gpio
|
- gpio
|
||||||
- i2c
|
- i2c
|
||||||
|
- i2s
|
||||||
- ieee802154
|
- ieee802154
|
||||||
- pwm
|
- pwm
|
||||||
- spi
|
- spi
|
||||||
|
|
|
@ -11,6 +11,7 @@ flash: 1024
|
||||||
supported:
|
supported:
|
||||||
- gpio
|
- gpio
|
||||||
- i2c
|
- i2c
|
||||||
|
- i2s
|
||||||
- pwm
|
- pwm
|
||||||
- watchdog
|
- watchdog
|
||||||
- usb_cdc
|
- usb_cdc
|
||||||
|
|
|
@ -12,3 +12,25 @@ config I2S_TEST_SEPARATE_DEVICES
|
||||||
bool "Use two separate I2S ports for loopback"
|
bool "Use two separate I2S ports for loopback"
|
||||||
help
|
help
|
||||||
Use separate I2S ports for transmit and receive.
|
Use separate I2S ports for transmit and receive.
|
||||||
|
|
||||||
|
config I2S_TEST_USE_I2S_DIR_BOTH
|
||||||
|
bool "Use I2S_DIR_BOTH value to perform RX/TX transfers"
|
||||||
|
help
|
||||||
|
Use the I2S_DIR_BOTH enumeration value to trigger commands in test
|
||||||
|
cases involving both reception and transmission. Use of this option
|
||||||
|
is essential for devices that cannot independently start and stop
|
||||||
|
the RX and TX streams.
|
||||||
|
|
||||||
|
config I2S_TEST_USE_GPIO_LOOPBACK
|
||||||
|
bool "Use GPIO loopback"
|
||||||
|
help
|
||||||
|
Use wiring between the data-out and data-in pins for looping back
|
||||||
|
data. This option is intended to be used for devices that do not
|
||||||
|
provide the internal loopback functionality.
|
||||||
|
|
||||||
|
config I2S_TEST_ALLOWED_DATA_OFFSET
|
||||||
|
int "Allowed offset in received data"
|
||||||
|
default 0
|
||||||
|
help
|
||||||
|
Maximum allowed offset between sent and received samples. Non-zero
|
||||||
|
value of this option may be needed when GPIO loopback is used.
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
CONFIG_I2S_TEST_USE_I2S_DIR_BOTH=y
|
||||||
|
CONFIG_I2S_TEST_USE_GPIO_LOOPBACK=y
|
||||||
|
CONFIG_I2S_TEST_ALLOWED_DATA_OFFSET=2
|
11
tests/drivers/i2s/i2s_api/boards/nrf52840dk_nrf52840.overlay
Normal file
11
tests/drivers/i2s/i2s_api/boards/nrf52840dk_nrf52840.overlay
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
&uart1 {
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
&i2s0 {
|
||||||
|
status = "okay";
|
||||||
|
sck-pin = <36>;
|
||||||
|
lrck-pin = <35>;
|
||||||
|
sdout-pin = <34>;
|
||||||
|
sdin-pin = <33>;
|
||||||
|
};
|
|
@ -0,0 +1,3 @@
|
||||||
|
CONFIG_I2S_TEST_USE_I2S_DIR_BOTH=y
|
||||||
|
CONFIG_I2S_TEST_USE_GPIO_LOOPBACK=y
|
||||||
|
CONFIG_I2S_TEST_ALLOWED_DATA_OFFSET=2
|
|
@ -0,0 +1,11 @@
|
||||||
|
&uart1 {
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
&i2s0 {
|
||||||
|
status = "okay";
|
||||||
|
sck-pin = <37>;
|
||||||
|
lrck-pin = <36>;
|
||||||
|
sdout-pin = <33>;
|
||||||
|
sdin-pin = <32>;
|
||||||
|
};
|
|
@ -9,6 +9,9 @@
|
||||||
#include <drivers/i2s.h>
|
#include <drivers/i2s.h>
|
||||||
#include "i2s_api_test.h"
|
#include "i2s_api_test.h"
|
||||||
|
|
||||||
|
K_MEM_SLAB_DEFINE(rx_mem_slab, BLOCK_SIZE, NUM_RX_BLOCKS, 32);
|
||||||
|
K_MEM_SLAB_DEFINE(tx_mem_slab, BLOCK_SIZE, NUM_TX_BLOCKS, 32);
|
||||||
|
|
||||||
/* The data_l represent a sine wave */
|
/* The data_l represent a sine wave */
|
||||||
ZTEST_DMEM int16_t data_l[SAMPLE_NO] = {
|
ZTEST_DMEM int16_t data_l[SAMPLE_NO] = {
|
||||||
6392, 12539, 18204, 23169, 27244, 30272, 32137, 32767, 32137,
|
6392, 12539, 18204, 23169, 27244, 30272, 32137, 32767, 32137,
|
||||||
|
@ -35,7 +38,28 @@ static void fill_buf(int16_t *tx_block, int att)
|
||||||
|
|
||||||
static int verify_buf(int16_t *rx_block, int att)
|
static int verify_buf(int16_t *rx_block, int att)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < SAMPLE_NO; i++) {
|
int sample_no = SAMPLE_NO;
|
||||||
|
|
||||||
|
#if (CONFIG_I2S_TEST_ALLOWED_DATA_OFFSET > 0)
|
||||||
|
static ZTEST_DMEM int offset = -1;
|
||||||
|
|
||||||
|
if (offset < 0) {
|
||||||
|
do {
|
||||||
|
++offset;
|
||||||
|
if (offset > CONFIG_I2S_TEST_ALLOWED_DATA_OFFSET) {
|
||||||
|
TC_PRINT("Allowed data offset exceeded\n");
|
||||||
|
return -TC_FAIL;
|
||||||
|
}
|
||||||
|
} while (rx_block[2 * offset] != data_l[0] >> att);
|
||||||
|
|
||||||
|
TC_PRINT("Using data offset: %d\n", offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_block += 2 * offset;
|
||||||
|
sample_no -= offset;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (int i = 0; i < sample_no; i++) {
|
||||||
if (rx_block[2 * i] != data_l[i] >> att) {
|
if (rx_block[2 * i] != data_l[i] >> att) {
|
||||||
TC_PRINT("Error: att %d: data_l mismatch at position "
|
TC_PRINT("Error: att %d: data_l mismatch at position "
|
||||||
"%d, expected %d, actual %d\n",
|
"%d, expected %d, actual %d\n",
|
||||||
|
@ -81,7 +105,7 @@ int verify_buf_const(int16_t *rx_block, int16_t val_l, int16_t val_r)
|
||||||
return TC_PASS;
|
return TC_PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tx_block_write_slab(const struct device *dev_i2s, int att, int err,
|
static int tx_block_write_slab(const struct device *dev_i2s, int att, int err,
|
||||||
struct k_mem_slab *slab)
|
struct k_mem_slab *slab)
|
||||||
{
|
{
|
||||||
char tx_block[BLOCK_SIZE];
|
char tx_block[BLOCK_SIZE];
|
||||||
|
@ -98,7 +122,12 @@ int tx_block_write_slab(const struct device *dev_i2s, int att, int err,
|
||||||
return TC_PASS;
|
return TC_PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rx_block_read_slab(const struct device *dev_i2s, int att,
|
int tx_block_write(const struct device *dev_i2s, int att, int err)
|
||||||
|
{
|
||||||
|
return tx_block_write_slab(dev_i2s, att, err, &tx_mem_slab);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rx_block_read_slab(const struct device *dev_i2s, int att,
|
||||||
struct k_mem_slab *slab)
|
struct k_mem_slab *slab)
|
||||||
{
|
{
|
||||||
char rx_block[BLOCK_SIZE];
|
char rx_block[BLOCK_SIZE];
|
||||||
|
@ -118,3 +147,60 @@ int rx_block_read_slab(const struct device *dev_i2s, int att,
|
||||||
|
|
||||||
return TC_PASS;
|
return TC_PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rx_block_read(const struct device *dev_i2s, int att)
|
||||||
|
{
|
||||||
|
return rx_block_read_slab(dev_i2s, att, &rx_mem_slab);
|
||||||
|
}
|
||||||
|
|
||||||
|
int configure_stream(const struct device *dev_i2s, enum i2s_dir dir)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct i2s_config i2s_cfg;
|
||||||
|
|
||||||
|
i2s_cfg.word_size = 16U;
|
||||||
|
i2s_cfg.channels = 2U;
|
||||||
|
i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
|
||||||
|
i2s_cfg.frame_clk_freq = FRAME_CLK_FREQ;
|
||||||
|
i2s_cfg.block_size = BLOCK_SIZE;
|
||||||
|
i2s_cfg.timeout = TIMEOUT;
|
||||||
|
|
||||||
|
if (dir == I2S_DIR_TX) {
|
||||||
|
/* Configure the Transmit port as Master */
|
||||||
|
i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER
|
||||||
|
| I2S_OPT_BIT_CLK_MASTER;
|
||||||
|
} else if (dir == I2S_DIR_RX) {
|
||||||
|
/* Configure the Receive port as Slave */
|
||||||
|
i2s_cfg.options = I2S_OPT_FRAME_CLK_SLAVE
|
||||||
|
| I2S_OPT_BIT_CLK_SLAVE;
|
||||||
|
} else { /* dir == I2S_DIR_BOTH */
|
||||||
|
i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER
|
||||||
|
| I2S_OPT_BIT_CLK_MASTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_I2S_TEST_USE_GPIO_LOOPBACK)) {
|
||||||
|
i2s_cfg.options |= I2S_OPT_LOOPBACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) {
|
||||||
|
i2s_cfg.mem_slab = &tx_mem_slab;
|
||||||
|
ret = i2s_configure(dev_i2s, I2S_DIR_TX, &i2s_cfg);
|
||||||
|
if (ret < 0) {
|
||||||
|
TC_PRINT("Failed to configure I2S TX stream (%d)\n",
|
||||||
|
ret);
|
||||||
|
return -TC_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) {
|
||||||
|
i2s_cfg.mem_slab = &rx_mem_slab;
|
||||||
|
ret = i2s_configure(dev_i2s, I2S_DIR_RX, &i2s_cfg);
|
||||||
|
if (ret < 0) {
|
||||||
|
TC_PRINT("Failed to configure I2S RX stream (%d)\n",
|
||||||
|
ret);
|
||||||
|
return -TC_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TC_PASS;
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#define I2S_API_TEST_H
|
#define I2S_API_TEST_H
|
||||||
|
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
|
#include <drivers/i2s.h>
|
||||||
|
|
||||||
void test_i2s_tx_transfer_configure_0(void);
|
void test_i2s_tx_transfer_configure_0(void);
|
||||||
void test_i2s_rx_transfer_configure_0(void);
|
void test_i2s_rx_transfer_configure_0(void);
|
||||||
|
@ -28,10 +29,21 @@ void test_i2s_state_running_neg(void);
|
||||||
void test_i2s_state_stopping_neg(void);
|
void test_i2s_state_stopping_neg(void);
|
||||||
void test_i2s_state_error_neg(void);
|
void test_i2s_state_error_neg(void);
|
||||||
|
|
||||||
extern struct k_mem_slab rx_0_mem_slab;
|
void test_i2s_dir_both_transfer_configure_0(void);
|
||||||
extern struct k_mem_slab tx_0_mem_slab;
|
void test_i2s_dir_both_transfer_short(void);
|
||||||
extern struct k_mem_slab rx_1_mem_slab;
|
void test_i2s_dir_both_transfer_long(void);
|
||||||
extern struct k_mem_slab tx_1_mem_slab;
|
void test_i2s_dir_both_rx_empty_timeout(void);
|
||||||
|
void test_i2s_dir_both_transfer_restart(void);
|
||||||
|
void test_i2s_dir_both_transfer_rx_overrun(void);
|
||||||
|
void test_i2s_dir_both_transfer_tx_underrun(void);
|
||||||
|
|
||||||
|
void test_i2s_dir_both_transfer_configure_1(void);
|
||||||
|
void test_i2s_dir_both_state_running_neg(void);
|
||||||
|
void test_i2s_dir_both_state_stopping_neg(void);
|
||||||
|
void test_i2s_dir_both_state_error_neg(void);
|
||||||
|
|
||||||
|
extern struct k_mem_slab rx_mem_slab;
|
||||||
|
extern struct k_mem_slab tx_mem_slab;
|
||||||
|
|
||||||
#define SAMPLE_NO 32
|
#define SAMPLE_NO 32
|
||||||
#define TIMEOUT 2000
|
#define TIMEOUT 2000
|
||||||
|
@ -48,12 +60,15 @@ extern int16_t data_r[SAMPLE_NO];
|
||||||
#endif
|
#endif
|
||||||
#define BLOCK_SIZE (2 * sizeof(data_l))
|
#define BLOCK_SIZE (2 * sizeof(data_l))
|
||||||
|
|
||||||
int rx_block_read_slab(const struct device *dev_i2s, int att,
|
#define NUM_RX_BLOCKS 4
|
||||||
struct k_mem_slab *slab);
|
#define NUM_TX_BLOCKS 4
|
||||||
int tx_block_write_slab(const struct device *dev_i2s, int att, int err,
|
|
||||||
struct k_mem_slab *slab);
|
int tx_block_write(const struct device *dev_i2s, int att, int err);
|
||||||
|
int rx_block_read(const struct device *dev_i2s, int att);
|
||||||
|
|
||||||
void fill_buf_const(int16_t *tx_block, int16_t val_l, int16_t val_r);
|
void fill_buf_const(int16_t *tx_block, int16_t val_l, int16_t val_r);
|
||||||
int verify_buf_const(int16_t *rx_block, int16_t val_l, int16_t val_r);
|
int verify_buf_const(int16_t *rx_block, int16_t val_l, int16_t val_r);
|
||||||
|
|
||||||
|
int configure_stream(const struct device *dev_i2s, enum i2s_dir dir);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,8 +16,8 @@ void test_main(void)
|
||||||
const struct device *dev_i2s_tx;
|
const struct device *dev_i2s_tx;
|
||||||
|
|
||||||
k_thread_access_grant(k_current_get(),
|
k_thread_access_grant(k_current_get(),
|
||||||
&rx_0_mem_slab, &tx_0_mem_slab,
|
&rx_mem_slab, &tx_mem_slab);
|
||||||
&rx_1_mem_slab, &tx_1_mem_slab);
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
||||||
if (dev_i2s_rx != NULL) {
|
if (dev_i2s_rx != NULL) {
|
||||||
k_object_access_grant(dev_i2s_rx, k_current_get());
|
k_object_access_grant(dev_i2s_rx, k_current_get());
|
||||||
|
@ -50,6 +50,22 @@ void test_main(void)
|
||||||
ztest_unit_test(test_i2s_state_error_neg));
|
ztest_unit_test(test_i2s_state_error_neg));
|
||||||
ztest_run_test_suite(i2s_states_test);
|
ztest_run_test_suite(i2s_states_test);
|
||||||
|
|
||||||
|
ztest_test_suite(i2s_dir_both_loopback_test,
|
||||||
|
ztest_unit_test(test_i2s_dir_both_transfer_configure_0),
|
||||||
|
ztest_unit_test(test_i2s_dir_both_transfer_short),
|
||||||
|
ztest_unit_test(test_i2s_dir_both_transfer_long),
|
||||||
|
ztest_unit_test(test_i2s_dir_both_transfer_restart),
|
||||||
|
ztest_unit_test(test_i2s_dir_both_transfer_rx_overrun),
|
||||||
|
ztest_unit_test(test_i2s_dir_both_transfer_tx_underrun));
|
||||||
|
ztest_run_test_suite(i2s_dir_both_loopback_test);
|
||||||
|
|
||||||
|
ztest_test_suite(i2s_dir_both_states_test,
|
||||||
|
ztest_unit_test(test_i2s_dir_both_transfer_configure_1),
|
||||||
|
ztest_unit_test(test_i2s_dir_both_state_running_neg),
|
||||||
|
ztest_unit_test(test_i2s_dir_both_state_stopping_neg),
|
||||||
|
ztest_unit_test(test_i2s_dir_both_state_error_neg));
|
||||||
|
ztest_run_test_suite(i2s_dir_both_states_test);
|
||||||
|
|
||||||
/* Now run all tests in user mode */
|
/* Now run all tests in user mode */
|
||||||
ztest_test_suite(i2s_user_loopback_test,
|
ztest_test_suite(i2s_user_loopback_test,
|
||||||
ztest_user_unit_test(test_i2s_tx_transfer_configure_0),
|
ztest_user_unit_test(test_i2s_tx_transfer_configure_0),
|
||||||
|
@ -72,4 +88,20 @@ void test_main(void)
|
||||||
ztest_user_unit_test(test_i2s_state_stopping_neg),
|
ztest_user_unit_test(test_i2s_state_stopping_neg),
|
||||||
ztest_user_unit_test(test_i2s_state_error_neg));
|
ztest_user_unit_test(test_i2s_state_error_neg));
|
||||||
ztest_run_test_suite(i2s_user_states_test);
|
ztest_run_test_suite(i2s_user_states_test);
|
||||||
|
|
||||||
|
ztest_test_suite(i2s_dir_both_user_loopback_test,
|
||||||
|
ztest_user_unit_test(test_i2s_dir_both_transfer_configure_0),
|
||||||
|
ztest_user_unit_test(test_i2s_dir_both_transfer_short),
|
||||||
|
ztest_user_unit_test(test_i2s_dir_both_transfer_long),
|
||||||
|
ztest_user_unit_test(test_i2s_dir_both_transfer_restart),
|
||||||
|
ztest_user_unit_test(test_i2s_dir_both_transfer_rx_overrun),
|
||||||
|
ztest_user_unit_test(test_i2s_dir_both_transfer_tx_underrun));
|
||||||
|
ztest_run_test_suite(i2s_dir_both_user_loopback_test);
|
||||||
|
|
||||||
|
ztest_test_suite(i2s_dir_both_user_states_test,
|
||||||
|
ztest_user_unit_test(test_i2s_dir_both_transfer_configure_1),
|
||||||
|
ztest_user_unit_test(test_i2s_dir_both_state_running_neg),
|
||||||
|
ztest_user_unit_test(test_i2s_dir_both_state_stopping_neg),
|
||||||
|
ztest_user_unit_test(test_i2s_dir_both_state_error_neg));
|
||||||
|
ztest_run_test_suite(i2s_dir_both_user_states_test);
|
||||||
}
|
}
|
||||||
|
|
330
tests/drivers/i2s/i2s_api/src/test_i2s_dir_both_loopback.c
Normal file
330
tests/drivers/i2s/i2s_api/src/test_i2s_dir_both_loopback.c
Normal file
|
@ -0,0 +1,330 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 comsuisse AG
|
||||||
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <ztest.h>
|
||||||
|
#include <drivers/i2s.h>
|
||||||
|
#include "i2s_api_test.h"
|
||||||
|
|
||||||
|
/* The test cases here are copied from test_i2s_loopback.c and adapted for use
|
||||||
|
* on devices that cannot independently start and stop the RX and TX streams
|
||||||
|
* and require the use of the I2S_DIR_BOTH value for RX/TX transfers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static ZTEST_DMEM const struct device *dev_i2s;
|
||||||
|
static ZTEST_DMEM bool dir_both_supported;
|
||||||
|
|
||||||
|
void test_i2s_dir_both_transfer_configure_0(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dev_i2s = device_get_binding(I2S_DEV_NAME_RX);
|
||||||
|
zassert_not_null(dev_i2s, "device " I2S_DEV_NAME_RX " not found");
|
||||||
|
|
||||||
|
ret = configure_stream(dev_i2s, I2S_DIR_BOTH);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
/* Check if the tested driver supports the I2S_DIR_BOTH value.
|
||||||
|
* Use the DROP trigger for this, as in the current state of the driver
|
||||||
|
* (READY, both TX and RX queues empty) it is actually a no-op.
|
||||||
|
*/
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DROP);
|
||||||
|
dir_both_supported = (ret == 0);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_I2S_TEST_USE_I2S_DIR_BOTH)) {
|
||||||
|
zassert_true(dir_both_supported,
|
||||||
|
"I2S_DIR_BOTH value is supposed to be supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Short I2S transfer.
|
||||||
|
*
|
||||||
|
* - START trigger starts both the transmission and reception.
|
||||||
|
* - Sending / receiving a short sequence of data returns success.
|
||||||
|
* - DRAIN trigger empties the transmit queue and stops both streams.
|
||||||
|
*/
|
||||||
|
void test_i2s_dir_both_transfer_short(void)
|
||||||
|
{
|
||||||
|
if (!dir_both_supported) {
|
||||||
|
TC_PRINT("I2S_DIR_BOTH value is not supported.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Prefill TX queue */
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d->OK\n", 1);
|
||||||
|
|
||||||
|
ret = tx_block_write(dev_i2s, 1, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d->OK\n", 2);
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed\n");
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d<-OK\n", 1);
|
||||||
|
|
||||||
|
ret = tx_block_write(dev_i2s, 2, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d->OK\n", 3);
|
||||||
|
|
||||||
|
/* All data written, drain TX queue and stop both streams. */
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN);
|
||||||
|
zassert_equal(ret, 0, "RX/TX DRAIN trigger failed");
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 1);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d<-OK\n", 2);
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 2);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d<-OK\n", 3);
|
||||||
|
|
||||||
|
/* TODO: Verify the interface is in READY state when i2s_state_get
|
||||||
|
* function is available.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TEST_I2S_TRANSFER_LONG_REPEAT_COUNT 100
|
||||||
|
|
||||||
|
/** @brief Long I2S transfer.
|
||||||
|
*
|
||||||
|
* - START trigger starts both the transmission and reception.
|
||||||
|
* - Sending / receiving a long sequence of data returns success.
|
||||||
|
* - DRAIN trigger empties the transmit queue and stops both streams.
|
||||||
|
*/
|
||||||
|
void test_i2s_dir_both_transfer_long(void)
|
||||||
|
{
|
||||||
|
if (!dir_both_supported) {
|
||||||
|
TC_PRINT("I2S_DIR_BOTH value is not supported.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Prefill TX queue */
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < TEST_I2S_TRANSFER_LONG_REPEAT_COUNT; i++) {
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All data written, all but one data block read, flush TX queue
|
||||||
|
* and stop both streams.
|
||||||
|
*/
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN);
|
||||||
|
zassert_equal(ret, 0, "RX/TX DRAIN trigger failed");
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
/* TODO: Verify the interface is in READY state when i2s_state_get
|
||||||
|
* function is available.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Re-start I2S transfer.
|
||||||
|
*
|
||||||
|
* - STOP trigger stops transfer / reception at the end of the current block,
|
||||||
|
* consecutive START trigger restarts transfer / reception with the next data
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
void test_i2s_dir_both_transfer_restart(void)
|
||||||
|
{
|
||||||
|
if (!dir_both_supported) {
|
||||||
|
TC_PRINT("I2S_DIR_BOTH value is not supported.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Prefill TX queue */
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d->OK\n", 1);
|
||||||
|
|
||||||
|
ret = tx_block_write(dev_i2s, 1, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d->OK\n", 2);
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed\n");
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_STOP);
|
||||||
|
zassert_equal(ret, 0, "RX/TX STOP trigger failed");
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d<-OK\n", 1);
|
||||||
|
|
||||||
|
TC_PRINT("Stop transmission\n");
|
||||||
|
|
||||||
|
/* Keep interface inactive */
|
||||||
|
k_sleep(K_MSEC(1000));
|
||||||
|
|
||||||
|
TC_PRINT("Start transmission\n");
|
||||||
|
|
||||||
|
/* Prefill TX queue */
|
||||||
|
ret = tx_block_write(dev_i2s, 2, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d->OK\n", 3);
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed\n");
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN);
|
||||||
|
zassert_equal(ret, 0, "RX/TX DRAIN trigger failed");
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 1);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d<-OK\n", 2);
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 2);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
TC_PRINT("%d<-OK\n", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief RX buffer overrun.
|
||||||
|
*
|
||||||
|
* - In case of RX buffer overrun it is possible to read out RX data blocks
|
||||||
|
* that are stored in the RX queue.
|
||||||
|
* - Reading from an empty RX queue when the RX buffer overrun occurred results
|
||||||
|
* in an error.
|
||||||
|
* - Sending PREPARE trigger after the RX buffer overrun occurred changes
|
||||||
|
* the interface state to READY.
|
||||||
|
*/
|
||||||
|
void test_i2s_dir_both_transfer_rx_overrun(void)
|
||||||
|
{
|
||||||
|
if (!dir_both_supported) {
|
||||||
|
TC_PRINT("I2S_DIR_BOTH value is not supported.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t rx_size;
|
||||||
|
int ret;
|
||||||
|
char rx_buf[BLOCK_SIZE];
|
||||||
|
|
||||||
|
/* Prefill TX queue */
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_RX_BLOCKS; i++) {
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All data written, flush TX queue and stop the transmission */
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN);
|
||||||
|
zassert_equal(ret, 0, "RX/TX DRAIN trigger failed");
|
||||||
|
|
||||||
|
/* Wait for transmission to finish */
|
||||||
|
k_sleep(K_MSEC(200));
|
||||||
|
|
||||||
|
/* Read one data block, expect success even if RX queue is already in
|
||||||
|
* the error state.
|
||||||
|
*/
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
/* Attempt to read more data blocks than are available in the RX queue */
|
||||||
|
for (int i = 0; i < NUM_RX_BLOCKS; i++) {
|
||||||
|
ret = i2s_buf_read(dev_i2s, rx_buf, &rx_size);
|
||||||
|
if (ret != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zassert_equal(ret, -EIO, "RX overrun error not detected");
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_RX, I2S_TRIGGER_PREPARE);
|
||||||
|
zassert_equal(ret, 0, "RX PREPARE trigger failed");
|
||||||
|
|
||||||
|
/* Transmit and receive one more data block */
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed\n");
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN);
|
||||||
|
zassert_equal(ret, 0, "RX/TX DRAIN trigger failed");
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
k_sleep(K_MSEC(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief TX buffer underrun.
|
||||||
|
*
|
||||||
|
* - An attempt to write to the TX queue when TX buffer underrun has occurred
|
||||||
|
* results in an error.
|
||||||
|
* - Sending PREPARE trigger after the TX buffer underrun occurred changes
|
||||||
|
* the interface state to READY.
|
||||||
|
*/
|
||||||
|
void test_i2s_dir_both_transfer_tx_underrun(void)
|
||||||
|
{
|
||||||
|
if (!dir_both_supported) {
|
||||||
|
TC_PRINT("I2S_DIR_BOTH value is not supported.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Prefill TX queue */
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed\n");
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
k_sleep(K_MSEC(200));
|
||||||
|
|
||||||
|
/* Write one more TX data block, expect an error */
|
||||||
|
ret = tx_block_write(dev_i2s, 2, -EIO);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_PREPARE);
|
||||||
|
zassert_equal(ret, 0, "RX/TX PREPARE trigger failed");
|
||||||
|
|
||||||
|
k_sleep(K_MSEC(200));
|
||||||
|
|
||||||
|
/* Transmit and receive two more data blocks */
|
||||||
|
ret = tx_block_write(dev_i2s, 1, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
ret = tx_block_write(dev_i2s, 1, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed\n");
|
||||||
|
ret = rx_block_read(dev_i2s, 1);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN);
|
||||||
|
zassert_equal(ret, 0, "RX/TX DRAIN trigger failed");
|
||||||
|
ret = rx_block_read(dev_i2s, 1);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
k_sleep(K_MSEC(200));
|
||||||
|
}
|
216
tests/drivers/i2s/i2s_api/src/test_i2s_dir_both_states.c
Normal file
216
tests/drivers/i2s/i2s_api/src/test_i2s_dir_both_states.c
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 comsuisse AG
|
||||||
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <ztest.h>
|
||||||
|
#include <drivers/i2s.h>
|
||||||
|
#include "i2s_api_test.h"
|
||||||
|
|
||||||
|
/* The test cases here are copied from test_i2s_states.c and adapted for use
|
||||||
|
* on devices that cannot independently start and stop the RX and TX streams
|
||||||
|
* and require the use of the I2S_DIR_BOTH value for RX/TX transfers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static ZTEST_DMEM const struct device *dev_i2s;
|
||||||
|
static ZTEST_DMEM bool dir_both_supported;
|
||||||
|
|
||||||
|
void test_i2s_dir_both_transfer_configure_1(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dev_i2s = device_get_binding(I2S_DEV_NAME_RX);
|
||||||
|
zassert_not_null(dev_i2s, "device " I2S_DEV_NAME_RX " not found");
|
||||||
|
|
||||||
|
ret = configure_stream(dev_i2s, I2S_DIR_BOTH);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
/* Check if the tested driver supports the I2S_DIR_BOTH value.
|
||||||
|
* Use the DROP trigger for this, as in the current state of the driver
|
||||||
|
* (READY, both TX and RX queues empty) it is actually a no-op.
|
||||||
|
*/
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DROP);
|
||||||
|
dir_both_supported = (ret == 0);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_I2S_TEST_USE_I2S_DIR_BOTH)) {
|
||||||
|
zassert_true(dir_both_supported,
|
||||||
|
"I2S_DIR_BOTH value is supposed to be supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TEST_I2S_STATE_RUNNING_NEG_REPEAT_COUNT 5
|
||||||
|
|
||||||
|
/** @brief Verify all failure cases in RUNNING state.
|
||||||
|
*
|
||||||
|
* - Sending START, PREPARE trigger in RUNNING state returns failure.
|
||||||
|
*/
|
||||||
|
void test_i2s_dir_both_state_running_neg(void)
|
||||||
|
{
|
||||||
|
if (!dir_both_supported) {
|
||||||
|
TC_PRINT("I2S_DIR_BOTH value is not supported.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Prefill TX queue */
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < TEST_I2S_STATE_RUNNING_NEG_REPEAT_COUNT; i++) {
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
/* Send invalid triggers, expect failure */
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, -EIO, NULL);
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_PREPARE);
|
||||||
|
zassert_equal(ret, -EIO, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All data written, drain TX queue and stop both streams. */
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN);
|
||||||
|
zassert_equal(ret, 0, "RX/TX DRAIN trigger failed");
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Verify all failure cases in STOPPING state.
|
||||||
|
*
|
||||||
|
* - Sending START, STOP, DRAIN, PREPARE trigger in STOPPING state returns
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
void test_i2s_dir_both_state_stopping_neg(void)
|
||||||
|
{
|
||||||
|
if (!dir_both_supported) {
|
||||||
|
TC_PRINT("I2S_DIR_BOTH value is not supported.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Prefill TX queue */
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed\n");
|
||||||
|
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
/* All data written, all but one data block read, flush TX queue and
|
||||||
|
* stop both streams.
|
||||||
|
*/
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN);
|
||||||
|
zassert_equal(ret, 0, "RX/TX DRAIN trigger failed");
|
||||||
|
|
||||||
|
/* Send invalid triggers, expect failure */
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, -EIO, NULL);
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_STOP);
|
||||||
|
zassert_equal(ret, -EIO, NULL);
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN);
|
||||||
|
zassert_equal(ret, -EIO, NULL);
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_PREPARE);
|
||||||
|
zassert_equal(ret, -EIO, NULL);
|
||||||
|
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
/* This is incase the RX channel is stuck in STOPPING state.
|
||||||
|
* Clear out the state before running the next test.
|
||||||
|
*/
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DROP);
|
||||||
|
zassert_equal(ret, 0, "RX/TX DROP trigger failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Verify all failure cases in ERROR state.
|
||||||
|
*
|
||||||
|
* - Sending START, STOP, DRAIN trigger in ERROR state returns failure.
|
||||||
|
*/
|
||||||
|
void test_i2s_dir_both_state_error_neg(void)
|
||||||
|
{
|
||||||
|
if (!dir_both_supported) {
|
||||||
|
TC_PRINT("I2S_DIR_BOTH value is not supported.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t rx_size;
|
||||||
|
int ret;
|
||||||
|
char rx_buf[BLOCK_SIZE];
|
||||||
|
|
||||||
|
/* Prefill TX queue */
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_RX_BLOCKS; i++) {
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for transmission to finish */
|
||||||
|
k_sleep(K_MSEC(200));
|
||||||
|
|
||||||
|
/* Read one data block, expect success even if RX queue is already in
|
||||||
|
* the error state.
|
||||||
|
*/
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
/* Attempt to read more data blocks than are available in the RX queue */
|
||||||
|
for (int i = 0; i < NUM_RX_BLOCKS; i++) {
|
||||||
|
ret = i2s_buf_read(dev_i2s, rx_buf, &rx_size);
|
||||||
|
if (ret != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zassert_equal(ret, -EIO, "RX overrun error not detected");
|
||||||
|
|
||||||
|
/* Write one more TX data block, expect an error */
|
||||||
|
ret = tx_block_write(dev_i2s, 2, -EIO);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
/* Send invalid triggers, expect failure */
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, -EIO, NULL);
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_STOP);
|
||||||
|
zassert_equal(ret, -EIO, NULL);
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN);
|
||||||
|
zassert_equal(ret, -EIO, NULL);
|
||||||
|
|
||||||
|
/* Recover from ERROR state */
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_PREPARE);
|
||||||
|
zassert_equal(ret, 0, "RX/TX PREPARE trigger failed");
|
||||||
|
|
||||||
|
/* Transmit and receive one more data block */
|
||||||
|
ret = tx_block_write(dev_i2s, 0, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START);
|
||||||
|
zassert_equal(ret, 0, "RX/TX START trigger failed");
|
||||||
|
ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN);
|
||||||
|
zassert_equal(ret, 0, "RX/TX DRAIN trigger failed");
|
||||||
|
ret = rx_block_read(dev_i2s, 0);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
||||||
|
k_sleep(K_MSEC(200));
|
||||||
|
}
|
|
@ -10,72 +10,31 @@
|
||||||
#include <drivers/i2s.h>
|
#include <drivers/i2s.h>
|
||||||
#include "i2s_api_test.h"
|
#include "i2s_api_test.h"
|
||||||
|
|
||||||
#define NUM_RX_BLOCKS 4
|
static ZTEST_DMEM const struct device *dev_i2s_rx;
|
||||||
#define NUM_TX_BLOCKS 4
|
static ZTEST_DMEM const struct device *dev_i2s_tx;
|
||||||
K_MEM_SLAB_DEFINE(rx_0_mem_slab, BLOCK_SIZE, NUM_RX_BLOCKS, 32);
|
|
||||||
K_MEM_SLAB_DEFINE(tx_0_mem_slab, BLOCK_SIZE, NUM_TX_BLOCKS, 32);
|
|
||||||
|
|
||||||
static int tx_block_write(const struct device *dev_i2s, int att, int err)
|
|
||||||
{
|
|
||||||
return tx_block_write_slab(dev_i2s, att, err, &tx_0_mem_slab);
|
|
||||||
}
|
|
||||||
static int rx_block_read(const struct device *dev_i2s, int att)
|
|
||||||
{
|
|
||||||
return rx_block_read_slab(dev_i2s, att, &rx_0_mem_slab);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Configure I2S TX transfer. */
|
/** Configure I2S TX transfer. */
|
||||||
void test_i2s_tx_transfer_configure_0(void)
|
void test_i2s_tx_transfer_configure_0(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s;
|
|
||||||
struct i2s_config i2s_cfg;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_i2s = device_get_binding(I2S_DEV_NAME_TX);
|
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
||||||
zassert_not_null(dev_i2s, "device " I2S_DEV_NAME_TX " not found");
|
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
||||||
|
|
||||||
/* Configure */
|
ret = configure_stream(dev_i2s_tx, I2S_DIR_TX);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
i2s_cfg.word_size = 16U;
|
|
||||||
i2s_cfg.channels = 2U;
|
|
||||||
i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
|
|
||||||
/* Configure the Transmit port as Master */
|
|
||||||
i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER | I2S_OPT_BIT_CLK_MASTER;
|
|
||||||
i2s_cfg.frame_clk_freq = FRAME_CLK_FREQ;
|
|
||||||
i2s_cfg.block_size = BLOCK_SIZE;
|
|
||||||
i2s_cfg.mem_slab = &tx_0_mem_slab;
|
|
||||||
i2s_cfg.timeout = TIMEOUT;
|
|
||||||
i2s_cfg.options |= I2S_OPT_LOOPBACK;
|
|
||||||
|
|
||||||
ret = i2s_configure(dev_i2s, I2S_DIR_TX, &i2s_cfg);
|
|
||||||
zassert_equal(ret, 0, "Failed to configure I2S TX stream");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Configure I2S RX transfer. */
|
/** Configure I2S RX transfer. */
|
||||||
void test_i2s_rx_transfer_configure_0(void)
|
void test_i2s_rx_transfer_configure_0(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s;
|
|
||||||
struct i2s_config i2s_cfg;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_i2s = device_get_binding(I2S_DEV_NAME_RX);
|
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
||||||
zassert_not_null(dev_i2s, "device " I2S_DEV_NAME_RX " not found");
|
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
||||||
|
|
||||||
/* Configure */
|
ret = configure_stream(dev_i2s_rx, I2S_DIR_RX);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
i2s_cfg.word_size = 16U;
|
|
||||||
i2s_cfg.channels = 2U;
|
|
||||||
i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
|
|
||||||
/* Configure the Receive port as Slave */
|
|
||||||
i2s_cfg.options = I2S_OPT_FRAME_CLK_SLAVE | I2S_OPT_BIT_CLK_SLAVE;
|
|
||||||
i2s_cfg.frame_clk_freq = FRAME_CLK_FREQ;
|
|
||||||
i2s_cfg.block_size = BLOCK_SIZE;
|
|
||||||
i2s_cfg.mem_slab = &rx_0_mem_slab;
|
|
||||||
i2s_cfg.timeout = TIMEOUT;
|
|
||||||
i2s_cfg.options |= I2S_OPT_LOOPBACK;
|
|
||||||
|
|
||||||
ret = i2s_configure(dev_i2s, I2S_DIR_RX, &i2s_cfg);
|
|
||||||
zassert_equal(ret, 0, "Failed to configure I2S RX stream");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Short I2S transfer.
|
/** @brief Short I2S transfer.
|
||||||
|
@ -88,16 +47,14 @@ void test_i2s_rx_transfer_configure_0(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_transfer_short(void)
|
void test_i2s_transfer_short(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s_rx;
|
if (IS_ENABLED(CONFIG_I2S_TEST_USE_I2S_DIR_BOTH)) {
|
||||||
const struct device *dev_i2s_tx;
|
TC_PRINT("RX/TX transfer requires use of I2S_DIR_BOTH.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
|
||||||
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
|
||||||
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
|
||||||
|
|
||||||
/* Prefill TX queue */
|
/* Prefill TX queue */
|
||||||
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
||||||
zassert_equal(ret, TC_PASS, NULL);
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
@ -156,16 +113,14 @@ void test_i2s_transfer_short(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_transfer_long(void)
|
void test_i2s_transfer_long(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s_rx;
|
if (IS_ENABLED(CONFIG_I2S_TEST_USE_I2S_DIR_BOTH)) {
|
||||||
const struct device *dev_i2s_tx;
|
TC_PRINT("RX/TX transfer requires use of I2S_DIR_BOTH.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
|
||||||
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
|
||||||
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
|
||||||
|
|
||||||
/* Prefill TX queue */
|
/* Prefill TX queue */
|
||||||
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
||||||
zassert_equal(ret, TC_PASS, NULL);
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
@ -212,18 +167,16 @@ void test_i2s_transfer_long(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_rx_sync_start(void)
|
void test_i2s_rx_sync_start(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s_rx;
|
if (IS_ENABLED(CONFIG_I2S_TEST_USE_I2S_DIR_BOTH)) {
|
||||||
const struct device *dev_i2s_tx;
|
TC_PRINT("RX/TX transfer requires use of I2S_DIR_BOTH.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t rx_size;
|
size_t rx_size;
|
||||||
int ret;
|
int ret;
|
||||||
char buf[BLOCK_SIZE];
|
char buf[BLOCK_SIZE];
|
||||||
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
|
||||||
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
|
||||||
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
|
||||||
|
|
||||||
/* Prefill TX queue */
|
/* Prefill TX queue */
|
||||||
for (int n = 0; n < NUM_TX_BLOCKS; n++) {
|
for (int n = 0; n < NUM_TX_BLOCKS; n++) {
|
||||||
fill_buf_const((uint16_t *)buf, 1, 2);
|
fill_buf_const((uint16_t *)buf, 1, 2);
|
||||||
|
@ -266,15 +219,11 @@ void test_i2s_rx_sync_start(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_rx_empty_timeout(void)
|
void test_i2s_rx_empty_timeout(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s;
|
|
||||||
size_t rx_size;
|
size_t rx_size;
|
||||||
int ret;
|
int ret;
|
||||||
char buf[BLOCK_SIZE];
|
char buf[BLOCK_SIZE];
|
||||||
|
|
||||||
dev_i2s = device_get_binding(I2S_DEV_NAME_RX);
|
ret = i2s_buf_read(dev_i2s_rx, buf, &rx_size);
|
||||||
zassert_not_null(dev_i2s, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
ret = i2s_buf_read(dev_i2s, buf, &rx_size);
|
|
||||||
zassert_equal(ret, -EAGAIN, "i2s_read did not timed out");
|
zassert_equal(ret, -EAGAIN, "i2s_read did not timed out");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,16 +235,14 @@ void test_i2s_rx_empty_timeout(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_transfer_restart(void)
|
void test_i2s_transfer_restart(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s_rx;
|
if (IS_ENABLED(CONFIG_I2S_TEST_USE_I2S_DIR_BOTH)) {
|
||||||
const struct device *dev_i2s_tx;
|
TC_PRINT("RX/TX transfer requires use of I2S_DIR_BOTH.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
|
||||||
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
|
||||||
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
|
||||||
|
|
||||||
/* Prefill TX queue */
|
/* Prefill TX queue */
|
||||||
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
||||||
zassert_equal(ret, TC_PASS, NULL);
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
@ -373,18 +320,16 @@ void test_i2s_transfer_restart(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_transfer_rx_overrun(void)
|
void test_i2s_transfer_rx_overrun(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s_rx;
|
if (IS_ENABLED(CONFIG_I2S_TEST_USE_I2S_DIR_BOTH)) {
|
||||||
const struct device *dev_i2s_tx;
|
TC_PRINT("RX/TX transfer requires use of I2S_DIR_BOTH.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t rx_size;
|
size_t rx_size;
|
||||||
int ret;
|
int ret;
|
||||||
char rx_buf[BLOCK_SIZE];
|
char rx_buf[BLOCK_SIZE];
|
||||||
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
|
||||||
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
|
||||||
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
|
||||||
|
|
||||||
/* Prefill TX queue */
|
/* Prefill TX queue */
|
||||||
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
||||||
zassert_equal(ret, TC_PASS, NULL);
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
@ -453,16 +398,14 @@ void test_i2s_transfer_rx_overrun(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_transfer_tx_underrun(void)
|
void test_i2s_transfer_tx_underrun(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s_rx;
|
if (IS_ENABLED(CONFIG_I2S_TEST_USE_I2S_DIR_BOTH)) {
|
||||||
const struct device *dev_i2s_tx;
|
TC_PRINT("RX/TX transfer requires use of I2S_DIR_BOTH.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
|
||||||
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
|
||||||
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
|
||||||
|
|
||||||
/* Prefill TX queue */
|
/* Prefill TX queue */
|
||||||
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
||||||
zassert_equal(ret, TC_PASS, NULL);
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
|
@ -9,73 +9,31 @@
|
||||||
#include <drivers/i2s.h>
|
#include <drivers/i2s.h>
|
||||||
#include "i2s_api_test.h"
|
#include "i2s_api_test.h"
|
||||||
|
|
||||||
#define NUM_RX_BLOCKS 4
|
static ZTEST_DMEM const struct device *dev_i2s_rx;
|
||||||
#define NUM_TX_BLOCKS 4
|
static ZTEST_DMEM const struct device *dev_i2s_tx;
|
||||||
|
|
||||||
K_MEM_SLAB_DEFINE(rx_1_mem_slab, BLOCK_SIZE, NUM_RX_BLOCKS, 32);
|
|
||||||
K_MEM_SLAB_DEFINE(tx_1_mem_slab, BLOCK_SIZE, NUM_TX_BLOCKS, 32);
|
|
||||||
|
|
||||||
static int tx_block_write(const struct device *dev_i2s, int att, int err)
|
|
||||||
{
|
|
||||||
return tx_block_write_slab(dev_i2s, att, err, &tx_1_mem_slab);
|
|
||||||
}
|
|
||||||
static int rx_block_read(const struct device *dev_i2s, int att)
|
|
||||||
{
|
|
||||||
return rx_block_read_slab(dev_i2s, att, &rx_1_mem_slab);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Configure I2S TX transfer. */
|
/** Configure I2S TX transfer. */
|
||||||
void test_i2s_tx_transfer_configure_1(void)
|
void test_i2s_tx_transfer_configure_1(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s;
|
|
||||||
struct i2s_config i2s_cfg;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_i2s = device_get_binding(I2S_DEV_NAME_TX);
|
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
||||||
zassert_not_null(dev_i2s, "device " I2S_DEV_NAME_TX " not found");
|
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
||||||
|
|
||||||
/* Configure */
|
ret = configure_stream(dev_i2s_tx, I2S_DIR_TX);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
i2s_cfg.word_size = 16U;
|
|
||||||
i2s_cfg.channels = 2U;
|
|
||||||
i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
|
|
||||||
/* Configure the Transmit port as Master */
|
|
||||||
i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER | I2S_OPT_BIT_CLK_MASTER;
|
|
||||||
i2s_cfg.frame_clk_freq = FRAME_CLK_FREQ;
|
|
||||||
i2s_cfg.block_size = BLOCK_SIZE;
|
|
||||||
i2s_cfg.mem_slab = &tx_1_mem_slab;
|
|
||||||
i2s_cfg.timeout = TIMEOUT;
|
|
||||||
i2s_cfg.options |= I2S_OPT_LOOPBACK;
|
|
||||||
|
|
||||||
ret = i2s_configure(dev_i2s, I2S_DIR_TX, &i2s_cfg);
|
|
||||||
zassert_equal(ret, 0, "Failed to configure I2S TX stream");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Configure I2S RX transfer. */
|
/** Configure I2S RX transfer. */
|
||||||
void test_i2s_rx_transfer_configure_1(void)
|
void test_i2s_rx_transfer_configure_1(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s;
|
|
||||||
struct i2s_config i2s_cfg;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_i2s = device_get_binding(I2S_DEV_NAME_RX);
|
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
||||||
zassert_not_null(dev_i2s, "device " I2S_DEV_NAME_RX " not found");
|
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
||||||
|
|
||||||
/* Configure */
|
ret = configure_stream(dev_i2s_rx, I2S_DIR_RX);
|
||||||
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
i2s_cfg.word_size = 16U;
|
|
||||||
i2s_cfg.channels = 2U;
|
|
||||||
i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
|
|
||||||
/* Configure the Receive port as Slave */
|
|
||||||
i2s_cfg.options = I2S_OPT_FRAME_CLK_SLAVE | I2S_OPT_BIT_CLK_SLAVE;
|
|
||||||
i2s_cfg.frame_clk_freq = FRAME_CLK_FREQ;
|
|
||||||
i2s_cfg.block_size = BLOCK_SIZE;
|
|
||||||
i2s_cfg.mem_slab = &rx_1_mem_slab;
|
|
||||||
i2s_cfg.timeout = TIMEOUT;
|
|
||||||
i2s_cfg.options |= I2S_OPT_LOOPBACK;
|
|
||||||
|
|
||||||
ret = i2s_configure(dev_i2s, I2S_DIR_RX, &i2s_cfg);
|
|
||||||
zassert_equal(ret, 0, "Failed to configure I2S RX stream");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Verify all failure cases in NOT_READY state.
|
/** @brief Verify all failure cases in NOT_READY state.
|
||||||
|
@ -87,21 +45,13 @@ void test_i2s_rx_transfer_configure_1(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_state_not_ready_neg(void)
|
void test_i2s_state_not_ready_neg(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s_rx;
|
|
||||||
const struct device *dev_i2s_tx;
|
|
||||||
struct i2s_config i2s_cfg;
|
struct i2s_config i2s_cfg;
|
||||||
size_t rx_size;
|
size_t rx_size;
|
||||||
int ret;
|
int ret;
|
||||||
char rx_buf[BLOCK_SIZE];
|
char rx_buf[BLOCK_SIZE];
|
||||||
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
|
||||||
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
|
||||||
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
|
||||||
|
|
||||||
i2s_cfg.frame_clk_freq = 0U;
|
i2s_cfg.frame_clk_freq = 0U;
|
||||||
i2s_cfg.mem_slab = &rx_1_mem_slab;
|
i2s_cfg.mem_slab = &rx_mem_slab;
|
||||||
|
|
||||||
ret = i2s_configure(dev_i2s_rx, I2S_DIR_RX, &i2s_cfg);
|
ret = i2s_configure(dev_i2s_rx, I2S_DIR_RX, &i2s_cfg);
|
||||||
zassert_equal(ret, 0, "Failed to configure I2S RX stream");
|
zassert_equal(ret, 0, "Failed to configure I2S RX stream");
|
||||||
|
@ -125,7 +75,7 @@ void test_i2s_state_not_ready_neg(void)
|
||||||
zassert_equal(ret, -EIO, NULL);
|
zassert_equal(ret, -EIO, NULL);
|
||||||
|
|
||||||
i2s_cfg.frame_clk_freq = 0U;
|
i2s_cfg.frame_clk_freq = 0U;
|
||||||
i2s_cfg.mem_slab = &tx_1_mem_slab;
|
i2s_cfg.mem_slab = &tx_mem_slab;
|
||||||
|
|
||||||
ret = i2s_configure(dev_i2s_tx, I2S_DIR_TX, &i2s_cfg);
|
ret = i2s_configure(dev_i2s_tx, I2S_DIR_TX, &i2s_cfg);
|
||||||
zassert_equal(ret, 0, "Failed to configure I2S TX stream");
|
zassert_equal(ret, 0, "Failed to configure I2S TX stream");
|
||||||
|
@ -155,31 +105,11 @@ void test_i2s_state_not_ready_neg(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_state_ready_neg(void)
|
void test_i2s_state_ready_neg(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s_rx;
|
|
||||||
const struct device *dev_i2s_tx;
|
|
||||||
struct i2s_config i2s_cfg;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
|
||||||
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
|
||||||
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
|
||||||
|
|
||||||
/* Configure RX stream changing its state to READY */
|
/* Configure RX stream changing its state to READY */
|
||||||
|
ret = configure_stream(dev_i2s_rx, I2S_DIR_RX);
|
||||||
i2s_cfg.word_size = 16U;
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
i2s_cfg.channels = 2U;
|
|
||||||
i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
|
|
||||||
/* Configure the Receive port as Slave */
|
|
||||||
i2s_cfg.options = I2S_OPT_FRAME_CLK_SLAVE | I2S_OPT_BIT_CLK_SLAVE;
|
|
||||||
i2s_cfg.frame_clk_freq = 8000U;
|
|
||||||
i2s_cfg.block_size = BLOCK_SIZE;
|
|
||||||
i2s_cfg.mem_slab = &rx_1_mem_slab;
|
|
||||||
i2s_cfg.timeout = TIMEOUT;
|
|
||||||
|
|
||||||
ret = i2s_configure(dev_i2s_rx, I2S_DIR_RX, &i2s_cfg);
|
|
||||||
zassert_equal(ret, 0, "Failed to configure I2S RX stream");
|
|
||||||
|
|
||||||
/* Send RX stream triggers */
|
/* Send RX stream triggers */
|
||||||
|
|
||||||
|
@ -193,15 +123,8 @@ void test_i2s_state_ready_neg(void)
|
||||||
zassert_equal(ret, -EIO, NULL);
|
zassert_equal(ret, -EIO, NULL);
|
||||||
|
|
||||||
/* Configure TX stream changing its state to READY */
|
/* Configure TX stream changing its state to READY */
|
||||||
|
ret = configure_stream(dev_i2s_rx, I2S_DIR_TX);
|
||||||
/* Configure the Transmit port as Master */
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER | I2S_OPT_BIT_CLK_MASTER;
|
|
||||||
|
|
||||||
i2s_cfg.options |= I2S_OPT_LOOPBACK;
|
|
||||||
i2s_cfg.mem_slab = &tx_1_mem_slab;
|
|
||||||
|
|
||||||
ret = i2s_configure(dev_i2s_tx, I2S_DIR_TX, &i2s_cfg);
|
|
||||||
zassert_equal(ret, 0, "Failed to configure I2S RX stream");
|
|
||||||
|
|
||||||
/* Send TX stream triggers */
|
/* Send TX stream triggers */
|
||||||
|
|
||||||
|
@ -223,16 +146,14 @@ void test_i2s_state_ready_neg(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_state_running_neg(void)
|
void test_i2s_state_running_neg(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s_rx;
|
if (IS_ENABLED(CONFIG_I2S_TEST_USE_I2S_DIR_BOTH)) {
|
||||||
const struct device *dev_i2s_tx;
|
TC_PRINT("RX/TX transfer requires use of I2S_DIR_BOTH.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
|
||||||
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
|
||||||
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
|
||||||
|
|
||||||
/* Prefill TX queue */
|
/* Prefill TX queue */
|
||||||
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
||||||
zassert_equal(ret, TC_PASS, NULL);
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
@ -282,16 +203,14 @@ void test_i2s_state_running_neg(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_state_stopping_neg(void)
|
void test_i2s_state_stopping_neg(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s_rx;
|
if (IS_ENABLED(CONFIG_I2S_TEST_USE_I2S_DIR_BOTH)) {
|
||||||
const struct device *dev_i2s_tx;
|
TC_PRINT("RX/TX transfer requires use of I2S_DIR_BOTH.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
|
||||||
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
|
||||||
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
|
||||||
|
|
||||||
/* Prefill TX queue */
|
/* Prefill TX queue */
|
||||||
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
||||||
zassert_equal(ret, TC_PASS, NULL);
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
@ -354,18 +273,16 @@ void test_i2s_state_stopping_neg(void)
|
||||||
*/
|
*/
|
||||||
void test_i2s_state_error_neg(void)
|
void test_i2s_state_error_neg(void)
|
||||||
{
|
{
|
||||||
const struct device *dev_i2s_rx;
|
if (IS_ENABLED(CONFIG_I2S_TEST_USE_I2S_DIR_BOTH)) {
|
||||||
const struct device *dev_i2s_tx;
|
TC_PRINT("RX/TX transfer requires use of I2S_DIR_BOTH.\n");
|
||||||
|
ztest_test_skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t rx_size;
|
size_t rx_size;
|
||||||
int ret;
|
int ret;
|
||||||
char rx_buf[BLOCK_SIZE];
|
char rx_buf[BLOCK_SIZE];
|
||||||
|
|
||||||
dev_i2s_rx = device_get_binding(I2S_DEV_NAME_RX);
|
|
||||||
zassert_not_null(dev_i2s_rx, "device " I2S_DEV_NAME_RX " not found");
|
|
||||||
|
|
||||||
dev_i2s_tx = device_get_binding(I2S_DEV_NAME_TX);
|
|
||||||
zassert_not_null(dev_i2s_tx, "device " I2S_DEV_NAME_TX " not found");
|
|
||||||
|
|
||||||
/* Prefill TX queue */
|
/* Prefill TX queue */
|
||||||
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
ret = tx_block_write(dev_i2s_tx, 0, 0);
|
||||||
zassert_equal(ret, TC_PASS, NULL);
|
zassert_equal(ret, TC_PASS, NULL);
|
||||||
|
|
|
@ -2,3 +2,11 @@ tests:
|
||||||
drivers.i2s:
|
drivers.i2s:
|
||||||
depends_on: i2s
|
depends_on: i2s
|
||||||
tags: drivers userspace
|
tags: drivers userspace
|
||||||
|
filter: not CONFIG_I2S_TEST_USE_GPIO_LOOPBACK
|
||||||
|
drivers.i2s.gpio_loopback:
|
||||||
|
depends_on: i2s
|
||||||
|
tags: drivers userspace
|
||||||
|
filter: CONFIG_I2S_TEST_USE_GPIO_LOOPBACK
|
||||||
|
harness: ztest
|
||||||
|
harness_config:
|
||||||
|
fixture: gpio_loopback
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue