/* * Copyright (c) 2019 Piotr Mienkowski * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include "test_gpio_api.h" struct gpio_callback gpio_cb; static int cb_count; static int cb_count_target; static void callback_edge(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins) { zassert_equal(pins, BIT(TEST_PIN), "Detected interrupt on an invalid pin"); cb_count++; } static void callback_level(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins) { int ret; zassert_equal(pins, BIT(TEST_PIN), "Detected interrupt on an invalid pin"); cb_count++; if (cb_count % cb_count_target == 0) { ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE); zassert_equal(ret, 0, "Failed to disable pin interrupt in the callback"); } } static void pin_set_and_verify(const struct device *port, unsigned int pin, int val, int idx) { zassert_equal(gpio_pin_set(port, pin, val), 0, "Test point %d: failed to set logical pin value", idx); k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); } void test_gpio_pin_interrupt_edge(unsigned int cfg_flags, unsigned int int_flags) { const struct device *port; int cb_count_expected; unsigned int cfg_out_flag; int ret; port = DEVICE_DT_GET(TEST_NODE); zassert_true(device_is_ready(port), "GPIO dev is not ready"); TC_PRINT("Running test on port=%s, pin=%d\n", port->name, TEST_PIN); ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | GPIO_OUTPUT); if (ret == -ENOTSUP) { TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); ztest_test_skip(); return; } zassert_equal(ret, 0, "Failed to configure the pin"); if ((cfg_flags & GPIO_ACTIVE_LOW) != 0) { cfg_out_flag = GPIO_OUTPUT_HIGH; } else { cfg_out_flag = GPIO_OUTPUT_LOW; } ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | cfg_out_flag | cfg_flags); zassert_equal(ret, 0, "Failed to configure the pin"); cb_count = 0; cb_count_expected = 0; gpio_init_callback(&gpio_cb, callback_edge, BIT(TEST_PIN)); ret = gpio_add_callback(port, &gpio_cb); ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags); if (ret == -ENOTSUP) { TC_PRINT("Pin interrupt is not supported.\n"); ztest_test_skip(); return; } zassert_equal(ret, 0, "Failed to configure pin interrupt"); for (int i = 0; i < 6; i++) { pin_set_and_verify(port, TEST_PIN, 1, i); if (int_flags & GPIO_INT_HIGH_1) { cb_count_expected++; } zassert_equal(cb_count, cb_count_expected, "Test point %d: Pin interrupt triggered invalid " "number of times on rising/to active edge", i); pin_set_and_verify(port, TEST_PIN, 0, i); if (int_flags & GPIO_INT_LOW_0) { cb_count_expected++; } zassert_equal(cb_count, cb_count_expected, "Test point %d: Pin interrupt triggered invalid " "number of times on falling/to inactive edge", i); } ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE); zassert_equal(ret, 0, "Failed to disable pin interrupt"); for (int i = 0; i < 6; i++) { pin_set_and_verify(port, TEST_PIN, 1, i); pin_set_and_verify(port, TEST_PIN, 0, i); zassert_equal(cb_count, cb_count_expected, "Pin interrupt triggered when disabled"); } } void test_gpio_pin_interrupt_level(unsigned int cfg_flags, unsigned int int_flags, unsigned int interrupt_calls) { const struct device *port; int cb_count_expected; unsigned int cfg_out_flag; int pin_out_val; int ret; port = DEVICE_DT_GET(TEST_NODE); zassert_true(device_is_ready(port), "GPIO dev is not ready"); TC_PRINT("Running test on port=%s, pin=%d\n", port->name, TEST_PIN); ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | GPIO_OUTPUT); if (ret == -ENOTSUP) { TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); ztest_test_skip(); return; } zassert_equal(ret, 0, "Failed to configure the pin"); pin_out_val = ((int_flags & GPIO_INT_HIGH_1) != 0) ? 0 : 1; if ((cfg_flags & GPIO_ACTIVE_LOW) != 0) { cfg_out_flag = (pin_out_val != 0) ? GPIO_OUTPUT_LOW : GPIO_OUTPUT_HIGH; } else { cfg_out_flag = (pin_out_val != 0) ? GPIO_OUTPUT_HIGH : GPIO_OUTPUT_LOW; } ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | cfg_out_flag | cfg_flags); zassert_equal(ret, 0, "Failed to configure the pin"); cb_count = 0; cb_count_expected = 0; cb_count_target = interrupt_calls; gpio_init_callback(&gpio_cb, callback_level, BIT(TEST_PIN)); ret = gpio_add_callback(port, &gpio_cb); ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags); if (ret == -ENOTSUP) { TC_PRINT("Pin interrupt is not supported.\n"); ztest_test_skip(); return; } zassert_equal(ret, 0, "Failed to configure pin interrupt"); zassert_equal(cb_count, cb_count_expected, "Pin interrupt triggered on level %d", pin_out_val); for (int i = 0; i < 6; i++) { pin_out_val = (pin_out_val != 0) ? 0 : 1; pin_set_and_verify(port, TEST_PIN, pin_out_val, i); cb_count_expected += interrupt_calls; zassert_equal(cb_count, cb_count_expected, "Test point %d: Pin interrupt triggered invalid " "number of times on level %d", i, pin_out_val); pin_out_val = (pin_out_val != 0) ? 0 : 1; pin_set_and_verify(port, TEST_PIN, pin_out_val, i); zassert_equal(cb_count, cb_count_expected, "Test point %d: Pin interrupt triggered invalid " "number of times on level %d", i, pin_out_val); /* Re-enable pin level interrupt */ ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags); zassert_equal(ret, 0, "Failed to re-enable pin level interrupt"); } ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE); zassert_equal(ret, 0, "Failed to disable pin interrupt"); for (int i = 0; i < 6; i++) { pin_set_and_verify(port, TEST_PIN, 1, i); pin_set_and_verify(port, TEST_PIN, 0, i); zassert_equal(cb_count, cb_count_expected, "Pin interrupt triggered when disabled"); } } /** @brief Verify GPIO_INT_EDGE_RISING flag. */ ZTEST(gpio_api_1pin_int, test_gpio_int_edge_rising) { test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_RISING); } /** @brief Verify GPIO_INT_EDGE_FALLING flag. */ ZTEST(gpio_api_1pin_int, test_gpio_int_edge_falling) { test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_FALLING); } /** @brief Verify GPIO_INT_EDGE_BOTH flag. */ ZTEST(gpio_api_1pin_int, test_gpio_int_edge_both) { test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_BOTH); } /** @brief Verify GPIO_INT_EDGE_TO_ACTIVE flag. */ ZTEST(gpio_api_1pin_int, test_gpio_int_edge_to_active) { TC_PRINT("Step 1: Configure pin as active high\n"); test_gpio_pin_interrupt_edge(GPIO_ACTIVE_HIGH, GPIO_INT_EDGE_TO_ACTIVE); TC_PRINT("Step 2: Configure pin as active low\n"); test_gpio_pin_interrupt_edge(GPIO_ACTIVE_LOW, GPIO_INT_EDGE_TO_ACTIVE); } /** @brief Verify GPIO_INT_EDGE_TO_INACTIVE flag. */ ZTEST(gpio_api_1pin_int, test_gpio_int_edge_to_inactive) { TC_PRINT("Step 1: Configure pin as active high\n"); test_gpio_pin_interrupt_edge(GPIO_ACTIVE_HIGH, GPIO_INT_EDGE_TO_INACTIVE); TC_PRINT("Step 2: Configure pin as active low\n"); test_gpio_pin_interrupt_edge(GPIO_ACTIVE_LOW, GPIO_INT_EDGE_TO_INACTIVE); } /** @brief Verify GPIO_INT_LEVEL_HIGH flag with 1 interrupt call */ ZTEST(gpio_api_1pin_int, test_gpio_int_level_high_interrupt_count_1) { test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_HIGH, 1); } /** @brief Verify GPIO_INT_LEVEL_HIGH flag with 5 interrupt call */ ZTEST(gpio_api_1pin_int, test_gpio_int_level_high_interrupt_count_5) { test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_HIGH, 5); } /** @brief Verify GPIO_INT_LEVEL_LOW flag with 1 interrupt call */ ZTEST(gpio_api_1pin_int, test_gpio_int_level_low_interrupt_count_1) { test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_LOW, 1); } /** @brief Verify GPIO_INT_LEVEL_LOW flag with 5 interrupt call */ ZTEST(gpio_api_1pin_int, test_gpio_int_level_low_interrupt_count_5) { test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_LOW, 5); } /** @brief Verify GPIO_INT_LEVEL_ACTIVE flag. */ ZTEST(gpio_api_1pin_int, test_gpio_int_level_active) { TC_PRINT("Step 1: Configure pin as active high\n"); test_gpio_pin_interrupt_level(GPIO_ACTIVE_HIGH, GPIO_INT_LEVEL_ACTIVE, 1); TC_PRINT("Step 2: Configure pin as active low\n"); test_gpio_pin_interrupt_level(GPIO_ACTIVE_LOW, GPIO_INT_LEVEL_ACTIVE, 1); } /** @brief Verify GPIO_INT_LEVEL_INACTIVE flag. */ ZTEST(gpio_api_1pin_int, test_gpio_int_level_inactive) { TC_PRINT("Step 1: Configure pin as active high\n"); test_gpio_pin_interrupt_level(GPIO_ACTIVE_HIGH, GPIO_INT_LEVEL_INACTIVE, 1); TC_PRINT("Step 2: Configure pin as active low\n"); test_gpio_pin_interrupt_level(GPIO_ACTIVE_LOW, GPIO_INT_LEVEL_INACTIVE, 1); } ZTEST_SUITE(gpio_api_1pin_int, NULL, NULL, NULL, NULL, NULL);