|
| 1 | +/* |
| 2 | + * Copyright (c) 2024 Nordic Semiconductor ASA |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr/logging/log.h> |
| 8 | +LOG_MODULE_REGISTER(gpio_loops, LOG_LEVEL_INF); |
| 9 | + |
| 10 | +#include <zephyr/kernel.h> |
| 11 | +#include <zephyr/drivers/gpio.h> |
| 12 | +#include <zephyr/ztest.h> |
| 13 | + |
| 14 | +#if !DT_NODE_EXISTS(DT_NODELABEL(out_gpios)) || !DT_NODE_EXISTS(DT_NODELABEL(in_gpios)) |
| 15 | +#error "Unsupported board: test_gpio node is not defined" |
| 16 | +#endif |
| 17 | + |
| 18 | +/* Delay after setting GPIO ouputs. It allows signals to settle. */ |
| 19 | +#define PROPAGATION_DELAY_MS K_MSEC(1U) |
| 20 | + |
| 21 | +/* Delay between GPIO toggle. */ |
| 22 | +#define TOGGLE_DELAY_MS 500U |
| 23 | + |
| 24 | +const struct gpio_dt_spec out_pins[] = { |
| 25 | + DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(out_gpios), gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)) |
| 26 | +}; |
| 27 | +const struct gpio_dt_spec in_pins[] = { |
| 28 | + DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(in_gpios), gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)) |
| 29 | +}; |
| 30 | +BUILD_ASSERT(ARRAY_SIZE(in_pins) == ARRAY_SIZE(out_pins), "mismatched in/out pairs"); |
| 31 | +const uint8_t npairs = ARRAY_SIZE(in_pins); |
| 32 | + |
| 33 | + |
| 34 | +/* Check that input GPIOs state match with input parameter 'value'. */ |
| 35 | +static void _check_inputs(uint32_t value) |
| 36 | +{ |
| 37 | + bool current; |
| 38 | + bool expected; |
| 39 | + |
| 40 | + LOG_DBG("_check_inputs(%d)", value); |
| 41 | + |
| 42 | + /* Wait a bit to stabilize logic level. */ |
| 43 | + k_sleep(PROPAGATION_DELAY_MS); |
| 44 | + |
| 45 | + for (uint8_t i = 0; i < npairs; i++) { |
| 46 | + current = gpio_pin_get_dt(&in_pins[i]); |
| 47 | + expected = value & BIT(i); |
| 48 | + LOG_DBG("_check_inputs L[%d]: current: %d, expected: %d", i, current, expected); |
| 49 | + zassert_equal(current, expected, |
| 50 | + "IN[%d] = %d, while expected %d", i, current, expected); |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +/* Set output GPIOs with gpio_pin_set_dt() |
| 55 | + * and confirm that input GPIOs have expected state. |
| 56 | + */ |
| 57 | +static void _gpio_pin_set_dt_and_check(uint32_t value) |
| 58 | +{ |
| 59 | + int out_state; |
| 60 | + int rc; |
| 61 | + |
| 62 | + LOG_DBG("_gpio_pin_set_dt_and_check(%d)", value); |
| 63 | + |
| 64 | + for (uint8_t i = 0; i < npairs; i++) { |
| 65 | + out_state = (value & BIT(i)) >> i; |
| 66 | + rc = gpio_pin_set_dt(&out_pins[i], out_state); |
| 67 | + LOG_DBG("_gpio_pin_set_dt_and_check: setting OUT[%d] to %d", i, out_state); |
| 68 | + zassert_equal(rc, 0, "gpio_pin_set_dt(OUT[%d], %d) failed", i, out_state); |
| 69 | + } |
| 70 | + |
| 71 | + /* Check inputs. */ |
| 72 | + _check_inputs(value); |
| 73 | +} |
| 74 | + |
| 75 | +/** |
| 76 | + * @brief Test GPIOs are working for CONFIG_TEST_DURATION ms. |
| 77 | + */ |
| 78 | +ZTEST(gpio_more_loops, test_gpios_are_working) |
| 79 | +{ |
| 80 | + for (int total_delay = 0; total_delay <= CONFIG_TEST_DURATION; |
| 81 | + total_delay += (2 * TOGGLE_DELAY_MS)) { |
| 82 | + |
| 83 | + _gpio_pin_set_dt_and_check(0b01010101010101010101010101010101); |
| 84 | + k_msleep(TOGGLE_DELAY_MS); |
| 85 | + _gpio_pin_set_dt_and_check(0b10101010101010101010101010101010); |
| 86 | + k_msleep(TOGGLE_DELAY_MS); |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +static void *suite_setup(void) |
| 91 | +{ |
| 92 | + uint8_t i; |
| 93 | + int rc; |
| 94 | + |
| 95 | + TC_PRINT("Test executed on %s\n", CONFIG_BOARD_TARGET); |
| 96 | + TC_PRINT("GPIO Loops count: %d\n", npairs); |
| 97 | + TC_PRINT("===================================================================\n"); |
| 98 | + |
| 99 | + for (i = 0; i < npairs; i++) { |
| 100 | + zassert_true(gpio_is_ready_dt(&in_pins[i]), "IN[%d] is not ready", i); |
| 101 | + zassert_true(gpio_is_ready_dt(&out_pins[i]), "OUT[%d] is not ready", i); |
| 102 | + |
| 103 | + } |
| 104 | + |
| 105 | + for (i = 0; i < npairs; i++) { |
| 106 | + rc = gpio_pin_configure_dt(&in_pins[i], GPIO_INPUT | GPIO_PULL_UP); |
| 107 | + zassert_equal(rc, 0, "IN[%d] config failed", i); |
| 108 | + } |
| 109 | + _check_inputs(0b11111111111111111111111111111111); |
| 110 | + TC_PRINT("Input pull up works.\n"); |
| 111 | + |
| 112 | + for (i = 0; i < npairs; i++) { |
| 113 | + rc = gpio_pin_configure_dt(&in_pins[i], GPIO_INPUT | GPIO_PULL_DOWN); |
| 114 | + zassert_equal(rc, 0, "IN[%d] config failed", i); |
| 115 | + } |
| 116 | + _check_inputs(0b00000000000000000000000000000000); |
| 117 | + TC_PRINT("Input pull down works.\n"); |
| 118 | + |
| 119 | + for (i = 0; i < npairs; i++) { |
| 120 | + rc = gpio_pin_configure_dt(&in_pins[i], GPIO_INPUT); |
| 121 | + zassert_equal(rc, 0, "IN[%d] config failed", i); |
| 122 | + rc = gpio_pin_configure_dt(&out_pins[i], GPIO_OUTPUT); |
| 123 | + zassert_equal(rc, 0, "OUT[%d] config failed", i); |
| 124 | + LOG_DBG("IN[%d] - OUT[%d] were configured", i, i); |
| 125 | + } |
| 126 | + |
| 127 | + return NULL; |
| 128 | +} |
| 129 | + |
| 130 | +ZTEST_SUITE(gpio_more_loops, NULL, suite_setup, NULL, NULL, NULL); |
0 commit comments