From 6c515dd5fc7c777e0105cf5bb66c51b036f8b6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C5=82=C4=85b?= Date: Tue, 16 Apr 2024 09:21:25 +0200 Subject: [PATCH] [nrf fromtree] tests: drivers: spi: Add negative test cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend test coverage by adding tests that check invalid use of the SPI API. Signed-off-by: Sebastian Głąb (cherry picked from commit 5e4bbd5c7c37b55b9b6df63ba7165f0b8ff6506c) --- .../spi/spi_error_cases/CMakeLists.txt | 10 + .../boards/nrf52840dk_nrf52840.overlay | 72 +++++ .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 78 ++++++ tests/drivers/spi/spi_error_cases/prj.conf | 7 + tests/drivers/spi/spi_error_cases/src/main.c | 263 ++++++++++++++++++ .../drivers/spi/spi_error_cases/testcase.yaml | 12 + 6 files changed, 442 insertions(+) create mode 100644 tests/drivers/spi/spi_error_cases/CMakeLists.txt create mode 100644 tests/drivers/spi/spi_error_cases/boards/nrf52840dk_nrf52840.overlay create mode 100644 tests/drivers/spi/spi_error_cases/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay create mode 100644 tests/drivers/spi/spi_error_cases/prj.conf create mode 100644 tests/drivers/spi/spi_error_cases/src/main.c create mode 100644 tests/drivers/spi/spi_error_cases/testcase.yaml diff --git a/tests/drivers/spi/spi_error_cases/CMakeLists.txt b/tests/drivers/spi/spi_error_cases/CMakeLists.txt new file mode 100644 index 00000000000..2ac4bdbef4d --- /dev/null +++ b/tests/drivers/spi/spi_error_cases/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(spi_error_cases) + +FILE(GLOB app_sources src/*.c) + +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/spi/spi_error_cases/boards/nrf52840dk_nrf52840.overlay b/tests/drivers/spi/spi_error_cases/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 00000000000..183d6da9967 --- /dev/null +++ b/tests/drivers/spi/spi_error_cases/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + spi3_default_alt: spi3_default_alt { + group1 { + psels = , + , + ; + }; + }; + + spi3_sleep_alt: spi3_sleep_alt { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + spi1_default_alt: spi1_default_alt { + group1 { + psels = , + , + , + ; + }; + }; + + spi1_sleep_alt: spi1_sleep_alt { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + +}; + +dut_spi: &spi3 { + status = "okay"; + pinctrl-0 = <&spi3_default_alt>; + pinctrl-1 = <&spi3_sleep_alt>; + pinctrl-names = "default", "sleep"; + overrun-character = <0x00>; + cs-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + dut_spi_dt: test-spi-dev@0 { + compatible = "vnd,spi-device"; + reg = <0>; + spi-max-frequency = <200000>; + }; +}; + +dut_spis: &spi1 { + compatible = "nordic,nrf-spis"; + status = "okay"; + def-char = <0x00>; + pinctrl-0 = <&spi1_default_alt>; + pinctrl-1 = <&spi1_sleep_alt>; + pinctrl-names = "default", "sleep"; + dut_spis_dt: test-spis-dev@0 { + compatible = "vnd,spi-device"; + reg = <0>; + spi-max-frequency = <200000>; + }; +}; diff --git a/tests/drivers/spi/spi_error_cases/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/spi/spi_error_cases/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..2a0394c3f60 --- /dev/null +++ b/tests/drivers/spi/spi_error_cases/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + spi22_default_alt: spi22_default_alt { + group1 { + psels = , + , + ; + }; + }; + + spi22_sleep_alt: spi22_sleep_alt { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + spi21_default_alt: spi21_default_alt { + group1 { + psels = , + , + , + ; + }; + }; + + spi21_sleep_alt: spi21_sleep_alt { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + +}; + +&gpio2 { + status = "okay"; +}; + +dut_spi: &spi22 { + status = "okay"; + pinctrl-0 = <&spi22_default_alt>; + pinctrl-1 = <&spi22_sleep_alt>; + pinctrl-names = "default", "sleep"; + overrun-character = <0x00>; + cs-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; + dut_spi_dt: test-spi-dev@0 { + compatible = "vnd,spi-device"; + reg = <0>; + spi-max-frequency = <200000>; + }; +}; + +dut_spis: &spi21 { + compatible = "nordic,nrf-spis"; + status = "okay"; + def-char = <0x00>; + pinctrl-0 = <&spi21_default_alt>; + pinctrl-1 = <&spi21_sleep_alt>; + pinctrl-names = "default", "sleep"; + dut_spis_dt: test-spis-dev@0 { + compatible = "vnd,spi-device"; + reg = <0>; + spi-max-frequency = <200000>; + }; + /delete-property/rx-delay-supported; + /delete-property/rx-delay; +}; diff --git a/tests/drivers/spi/spi_error_cases/prj.conf b/tests/drivers/spi/spi_error_cases/prj.conf new file mode 100644 index 00000000000..1161e03f477 --- /dev/null +++ b/tests/drivers/spi/spi_error_cases/prj.conf @@ -0,0 +1,7 @@ +CONFIG_SPI=y +CONFIG_SPI_SLAVE=y +CONFIG_GPIO=y +CONFIG_POLL=y +CONFIG_SPI_ASYNC=y +CONFIG_SPI_EXTENDED_MODES=y +CONFIG_ZTEST=y diff --git a/tests/drivers/spi/spi_error_cases/src/main.c b/tests/drivers/spi/spi_error_cases/src/main.c new file mode 100644 index 00000000000..0b44812db84 --- /dev/null +++ b/tests/drivers/spi/spi_error_cases/src/main.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define SPI_MODE (SPI_MODE_CPOL | SPI_WORD_SET(8) | SPI_LINES_SINGLE) +#define SPIM_OP (SPI_OP_MODE_MASTER | SPI_MODE) +#define SPIS_OP (SPI_OP_MODE_SLAVE | SPI_MODE) + +static struct spi_dt_spec spim = SPI_DT_SPEC_GET(DT_NODELABEL(dut_spi_dt), SPIM_OP, 0); +static struct spi_dt_spec spis = SPI_DT_SPEC_GET(DT_NODELABEL(dut_spis_dt), SPIS_OP, 0); + +#define MEMORY_SECTION(node) \ + COND_CODE_1(DT_NODE_HAS_PROP(node, memory_regions), \ + (__attribute__((__section__( \ + LINKER_DT_NODE_REGION_NAME(DT_PHANDLE(node, memory_regions)))))), \ + ()) + +static uint8_t spim_buffer[32] MEMORY_SECTION(DT_NODELABEL(dut_spi)); +static uint8_t spis_buffer[32] MEMORY_SECTION(DT_NODELABEL(dut_spis)); + +struct test_data { + int spim_alloc_idx; + int spis_alloc_idx; + struct spi_buf_set sets[4]; + struct spi_buf_set *mtx_set; + struct spi_buf_set *mrx_set; + struct spi_buf_set *stx_set; + struct spi_buf_set *srx_set; + struct spi_buf bufs[4]; +}; + +static struct test_data tdata; + +/* Allocate buffer from spim or spis space. */ +static uint8_t *buf_alloc(size_t len, bool spim) +{ + int *idx = spim ? &tdata.spim_alloc_idx : &tdata.spis_alloc_idx; + uint8_t *buf = spim ? spim_buffer : spis_buffer; + size_t total = spim ? sizeof(spim_buffer) : sizeof(spis_buffer); + uint8_t *rv; + + if (*idx + len > total) { + zassert_false(true); + + return NULL; + } + + rv = &buf[*idx]; + *idx += len; + + return rv; +} + +ZTEST(spi_error_cases, test_SPI_HALF_DUPLEX_not_supported) +{ + int rv; + int slave_rv; + struct spi_dt_spec spim_invalid = spim; + struct spi_dt_spec spis_invalid = spis; + + spim_invalid.config.operation |= SPI_HALF_DUPLEX; + spis_invalid.config.operation |= SPI_HALF_DUPLEX; + + rv = spi_transceive_dt(&spim_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(rv, -ENOTSUP, "Got %d instead", rv); + slave_rv = spi_transceive_dt(&spis_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -ENOTSUP, "Got %d instead", slave_rv); +} + +ZTEST(spi_error_cases, test_SPI_OP_MODE_invalid) +{ + int rv; + int slave_rv; + struct spi_dt_spec spim_invalid = spim; + struct spi_dt_spec spis_invalid = spis; + + spim_invalid.config.operation |= SPI_OP_MODE_SLAVE; + spis_invalid.config.operation &= !SPI_OP_MODE_SLAVE; + + /* Check that Operation Mode Slave on spim is not supported */ + rv = spi_transceive_dt(&spim_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(rv, -EINVAL, "Got %d instead", rv); + /* Check that Operation Mode Master on spis is not supported */ + slave_rv = spi_transceive_dt(&spis_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -EINVAL, "Got %d instead", slave_rv); +} + +ZTEST(spi_error_cases, test_SPI_MODE_LOOP_not_supported) +{ + int rv; + int slave_rv; + struct spi_dt_spec spim_invalid = spim; + struct spi_dt_spec spis_invalid = spis; + + spim_invalid.config.operation |= SPI_MODE_LOOP; + spis_invalid.config.operation |= SPI_MODE_LOOP; + + rv = spi_transceive_dt(&spim_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(rv, -EINVAL, "Got %d instead", rv); + slave_rv = spi_transceive_dt(&spis_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -EINVAL, "Got %d instead", slave_rv); +} + +ZTEST(spi_error_cases, test_only_SPI_LINES_SINGLE_supported) +{ + int rv; + int slave_rv; + struct spi_dt_spec spim_invalid = spim; + struct spi_dt_spec spis_invalid = spis; + + spim_invalid.config.operation |= SPI_LINES_DUAL; + spis_invalid.config.operation |= SPI_LINES_DUAL; + + rv = spi_transceive_dt(&spim_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(rv, -EINVAL, "Got %d instead", rv); + slave_rv = spi_transceive_dt(&spis_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -EINVAL, "Got %d instead", slave_rv); + + spim_invalid = spim; + spis_invalid = spis; + spim_invalid.config.operation |= SPI_LINES_QUAD; + spis_invalid.config.operation |= SPI_LINES_QUAD; + + rv = spi_transceive_dt(&spim_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(rv, -EINVAL, "Got %d instead", rv); + slave_rv = spi_transceive_dt(&spis_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -EINVAL, "Got %d instead", slave_rv); + + spim_invalid = spim; + spis_invalid = spis; + spim_invalid.config.operation |= SPI_LINES_OCTAL; + spis_invalid.config.operation |= SPI_LINES_OCTAL; + + rv = spi_transceive_dt(&spim_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(rv, -EINVAL, "Got %d instead", rv); + slave_rv = spi_transceive_dt(&spis_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -EINVAL, "Got %d instead", slave_rv); +} + +ZTEST(spi_error_cases, test_only_8BIT_supported) +{ + int rv; + int slave_rv; + struct spi_dt_spec spim_invalid = spim; + struct spi_dt_spec spis_invalid = spis; + + spim_invalid.config.operation |= SPI_WORD_SET(16); + spis_invalid.config.operation |= SPI_WORD_SET(16); + + rv = spi_transceive_dt(&spim_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(rv, -EINVAL, "Got %d instead", rv); + slave_rv = spi_transceive_dt(&spis_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -EINVAL, "Got %d instead", slave_rv); +} + +ZTEST(spi_error_cases, test_unsupported_frequency) +{ + int rv; + struct spi_dt_spec spim_invalid = spim; + + spim_invalid.config.frequency = 124999; + + rv = spi_transceive_dt(&spim_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(rv, -EINVAL, "Got %d instead", rv); +} + +ZTEST(spi_error_cases, test_CS_unsupported_on_slave) +{ + int slave_rv; + struct spi_dt_spec spis_invalid = spis; + struct gpio_dt_spec test_gpio = { DEVICE_DT_GET(DT_NODELABEL(gpio1)), 10, GPIO_ACTIVE_LOW }; + + spis_invalid.config.cs.gpio = test_gpio; + + slave_rv = spi_transceive_dt(&spis_invalid, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -EINVAL, "Got %d instead", slave_rv); +} + +ZTEST(spi_error_cases, test_spis_scattered_tx_buf_not_supported) +{ + int slave_rv; + + tdata.sets[2].count = 2; + slave_rv = spi_transceive_dt(&spis, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -ENOTSUP, "Got %d instead", slave_rv); +} + +ZTEST(spi_error_cases, test_spis_scattered_rx_buf_not_supported) +{ + int slave_rv; + + tdata.sets[3].count = 2; + slave_rv = spi_transceive_dt(&spis, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -ENOTSUP, "Got %d instead", slave_rv); +} + +ZTEST(spi_error_cases, test_spis_tx_buf_too_big) +{ + int slave_rv; + + tdata.bufs[2].len = (size_t)65536; + slave_rv = spi_transceive_dt(&spis, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -EINVAL, "Got %d instead", slave_rv); +} + +ZTEST(spi_error_cases, test_spis_rx_buf_too_big) +{ + int slave_rv; + + tdata.bufs[3].len = (size_t)65536; + slave_rv = spi_transceive_dt(&spis, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -EINVAL, "Got %d instead", slave_rv); +} + +ZTEST(spi_error_cases, test_spis_tx_buf_not_in_ram) +{ + int slave_rv; + + tdata.bufs[2].buf = (void *)0x12345678; + slave_rv = spi_transceive_dt(&spis, tdata.stx_set, tdata.srx_set); + zassert_equal(slave_rv, -ENOTSUP, "Got %d instead", slave_rv); +} + +static void before(void *not_used) +{ + ARG_UNUSED(not_used); + size_t len = 16; + + memset(&tdata, 0, sizeof(tdata)); + for (size_t i = 0; i < sizeof(spim_buffer); i++) { + spim_buffer[i] = (uint8_t)i; + } + for (size_t i = 0; i < sizeof(spis_buffer); i++) { + spis_buffer[i] = (uint8_t)i; + } + + for (int i = 0; i < 4; i++) { + tdata.bufs[i].buf = buf_alloc(len, i < 2); + tdata.bufs[i].len = len; + tdata.sets[i].buffers = &tdata.bufs[i]; + tdata.sets[i].count = 1; + } + + tdata.mtx_set = &tdata.sets[0]; + tdata.mrx_set = &tdata.sets[1]; + tdata.stx_set = &tdata.sets[2]; + tdata.srx_set = &tdata.sets[3]; +} + +static void *suite_setup(void) +{ + return NULL; +} + +ZTEST_SUITE(spi_error_cases, NULL, suite_setup, before, NULL, NULL); diff --git a/tests/drivers/spi/spi_error_cases/testcase.yaml b/tests/drivers/spi/spi_error_cases/testcase.yaml new file mode 100644 index 00000000000..17cee921111 --- /dev/null +++ b/tests/drivers/spi/spi_error_cases/testcase.yaml @@ -0,0 +1,12 @@ +tests: + drivers.spi.spi_error_cases: + depends_on: spi + tags: drivers spi + harness: ztest + harness_config: + fixture: gpio_spi_loopback + platform_allow: + - nrf52840dk_nrf52840 + - nrf54l15pdk_nrf54l15_cpuapp + integration_platforms: + - nrf52840dk_nrf52840