From 8d84033b8c9d139b36f8b3945a9b3ba37cfde34a Mon Sep 17 00:00:00 2001 From: songruojing Date: Wed, 9 Mar 2022 14:37:41 +0800 Subject: [PATCH] gpio: Clean up unit tests and enable ci ut on some previously disabled test cases Eliminate UT_T1_GPIO runner requirement by routing internally through gpio matrix and by setting gpio pins to GPIO_MODE_INPUT_OUTPUT mode for all interrupt related test cases. --- components/driver/Kconfig | 7 + components/driver/include/driver/gpio.h | 4 + components/driver/linker.lf | 3 + .../driver/test_apps/gpio/main/test_gpio.c | 1320 ++++++++--------- .../driver/test_apps/gpio/main/test_gpio.h | 53 + .../test_apps/gpio/sdkconfig.ci.iram_safe | 2 +- components/esp_rom/include/esp32h2/rom/gpio.h | 24 +- components/hal/gpio_hal.c | 18 +- components/hal/linker.lf | 2 + .../soc/esp32c3/include/soc/io_mux_reg.h | 3 + .../soc/esp32h2/include/rev1/soc/io_mux_reg.h | 3 + .../soc/esp32h2/include/rev2/soc/io_mux_reg.h | 3 + .../soc/esp32h2/include/soc/gpio_pins.h | 25 +- .../soc/esp32s3/include/soc/io_mux_reg.h | 2 + tools/ci/check_copyright_ignore.txt | 3 - 15 files changed, 741 insertions(+), 731 deletions(-) create mode 100644 components/driver/test_apps/gpio/main/test_gpio.h diff --git a/components/driver/Kconfig b/components/driver/Kconfig index 42308eced6..a2eab3a984 100644 --- a/components/driver/Kconfig +++ b/components/driver/Kconfig @@ -185,6 +185,13 @@ menu "Driver configurations" pullup/pulldown mode in sleep. If this option is selected, chip will automatically emulate the behaviour of switching, and about 450B of source codes would be placed into IRAM. + + config GPIO_CTRL_FUNC_IN_IRAM + bool "Place GPIO control functions into IRAM" + default n + help + Place GPIO control functions (like intr_disable/set_level) into IRAM, + so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context. endmenu # GPIO Configuration menu "GDMA Configuration" diff --git a/components/driver/include/driver/gpio.h b/components/driver/include/driver/gpio.h index f71f47aa0c..1288f36852 100644 --- a/components/driver/include/driver/gpio.h +++ b/components/driver/include/driver/gpio.h @@ -94,6 +94,8 @@ esp_err_t gpio_intr_enable(gpio_num_t gpio_num); /** * @brief Disable GPIO module interrupt signal * + * @note This function is allowed to be executed when Cache is disabled within ISR context, by enabling `CONFIG_GPIO_CTRL_FUNC_IN_IRAM` + * * @param gpio_num GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); * * @return @@ -106,6 +108,8 @@ esp_err_t gpio_intr_disable(gpio_num_t gpio_num); /** * @brief GPIO set output level * + * @note This function is allowed to be executed when Cache is disabled within ISR context, by enabling `CONFIG_GPIO_CTRL_FUNC_IN_IRAM` + * * @param gpio_num GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param level Output level. 0: low ; 1: high * diff --git a/components/driver/linker.lf b/components/driver/linker.lf index 554b843a70..04052cd159 100644 --- a/components/driver/linker.lf +++ b/components/driver/linker.lf @@ -23,3 +23,6 @@ entries: pulse_cnt: pcnt_unit_stop (noflash) pulse_cnt: pcnt_unit_clear_count (noflash) pulse_cnt: pcnt_unit_get_count (noflash) + if GPIO_CTRL_FUNC_IN_IRAM = y: + gpio: gpio_set_level (noflash) + gpio: gpio_intr_disable (noflash) diff --git a/components/driver/test_apps/gpio/main/test_gpio.c b/components/driver/test_apps/gpio/main/test_gpio.c index 64f21d7016..48e4a90403 100644 --- a/components/driver/test_apps/gpio/main/test_gpio.c +++ b/components/driver/test_apps/gpio/main/test_gpio.c @@ -5,109 +5,54 @@ */ /** - * About test environment UT_T1_GPIO: - * Please connect TEST_GPIO_EXT_OUT_IO and TEST_GPIO_EXT_IN_IO + * No specific runner required to run GPIO unit test. + * TEST_GPIO_EXT_OUT_IO and TEST_GPIO_EXT_IN_IO are connected internally through gpio matrix. + * + * If wants to externally connect TEST_GPIO_EXT_OUT_IO to TEST_GPIO_EXT_IN_IO (UT_T1_GPIO), please set + * TEST_GPIO_INTERNAL_ROUTING to 0 */ + #include #include +#include "test_gpio.h" #include "esp_system.h" #include "esp_sleep.h" #include "unity.h" +#include "unity_test_utils.h" #include "driver/gpio.h" +#include "hal/gpio_ll.h" +#include "soc/gpio_periph.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" +#include "freertos/semphr.h" #include "sdkconfig.h" #include "esp_rom_uart.h" #include "esp_rom_sys.h" -#include "unity_test_utils.h" - - -#define WAKE_UP_IGNORE 1 // gpio_wakeup function development is not completed yet, set it deprecated. - -#if CONFIG_IDF_TARGET_ESP32 -#define TEST_GPIO_EXT_OUT_IO 18 // default output GPIO -#define TEST_GPIO_EXT_IN_IO 19 // default input GPIO -#define TEST_GPIO_OUTPUT_PIN 23 -#define TEST_GPIO_INPUT_ONLY_PIN 34 -#define TEST_GPIO_OUTPUT_MAX GPIO_NUM_34 -#define TEST_GPIO_INPUT_LEVEL_HIGH_PIN 2 -#define TEST_GPIO_INPUT_LEVEL_LOW_PIN 4 -#elif CONFIG_IDF_TARGET_ESP32S2 -// ESP32_S2 DEVKIC uses IO19 and IO20 as USB functions, so it is necessary to avoid using IO19, otherwise GPIO io pull up/down function cannot pass -// Also the first version of ESP32-S2-Saola has pullup issue on GPIO18, which is tied to 3V3 on the -// runner. Also avoid using GPIO18. -#define TEST_GPIO_EXT_OUT_IO 17 // default output GPIO -#define TEST_GPIO_EXT_IN_IO 21 // default input GPIO -#define TEST_GPIO_OUTPUT_PIN 12 -#define TEST_GPIO_INPUT_ONLY_PIN 46 -#define TEST_GPIO_OUTPUT_MAX GPIO_NUM_46 -#define TEST_GPIO_INPUT_LEVEL_HIGH_PIN 17 -#define TEST_GPIO_INPUT_LEVEL_LOW_PIN 1 -#elif CONFIG_IDF_TARGET_ESP32S3 -// IO19 and IO20 are connected as USB functions. -#define TEST_GPIO_EXT_OUT_IO 17 // default output GPIO -#define TEST_GPIO_EXT_IN_IO 21 // default input GPIO -#define TEST_GPIO_OUTPUT_PIN 12 -#define TEST_GPIO_OUTPUT_MAX GPIO_NUM_MAX -#define TEST_GPIO_USB_DM_IO 19 // USB D- GPIO -#define TEST_GPIO_USB_DP_IO 20 // USB D+ GPIO -#define TEST_GPIO_INPUT_LEVEL_HIGH_PIN 17 -#define TEST_GPIO_INPUT_LEVEL_LOW_PIN 1 -#elif CONFIG_IDF_TARGET_ESP32C3 -#define TEST_GPIO_EXT_OUT_IO 2 // default output GPIO -#define TEST_GPIO_EXT_IN_IO 3 // default input GPIO -#define TEST_GPIO_OUTPUT_PIN 1 -#define TEST_GPIO_OUTPUT_MAX GPIO_NUM_MAX -#define TEST_GPIO_USB_DM_IO 18 // USB D- GPIO -#define TEST_GPIO_USB_DP_IO 19 // USB D+ GPIO -#define TEST_GPIO_INPUT_LEVEL_HIGH_PIN 10 -#define TEST_GPIO_INPUT_LEVEL_LOW_PIN 1 -#elif CONFIG_IDF_TARGET_ESP32C2 -#define TEST_GPIO_EXT_OUT_IO 2 // default output GPIO -#define TEST_GPIO_EXT_IN_IO 3 // default input GPIO -#define TEST_GPIO_OUTPUT_PIN 1 -#define TEST_GPIO_OUTPUT_MAX GPIO_NUM_MAX -#define TEST_GPIO_INPUT_LEVEL_HIGH_PIN 10 -#define TEST_GPIO_INPUT_LEVEL_LOW_PIN 1 -#elif CONFIG_IDF_TARGET_ESP32H2_BETA_VERSION_2 -#define TEST_GPIO_EXT_OUT_IO 6 // default output GPIO -#define TEST_GPIO_EXT_IN_IO 7 // default input GPIO -#define TEST_GPIO_OUTPUT_PIN 1 -#define TEST_GPIO_OUTPUT_MAX GPIO_NUM_MAX -#define TEST_GPIO_USB_DM_IO 24 // USB D- GPIO -#define TEST_GPIO_USB_DP_IO 25 // USB D+ GPIO -#define TEST_GPIO_INPUT_LEVEL_HIGH_PIN 9 -#define TEST_GPIO_INPUT_LEVEL_LOW_PIN 1 -#endif - -// If there is any input-only pin, enable input-only pin part of some tests. -#define SOC_HAS_INPUT_ONLY_PIN (CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2) - -// define public test io on all boards -#define TEST_IO_9 GPIO_NUM_9 -#define TEST_IO_10 GPIO_NUM_10 +#include "esp_spi_flash.h" +#include "esp_attr.h" void test_app_include_gpio(void) { } +// Enable internal routing for the output and input gpio pins +#define TEST_GPIO_INTERNAL_ROUTING 1 + +// If there is any input-only pin, enable input-only pin part of some tests. +#define SOC_HAS_INPUT_ONLY_PIN (CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2) + static volatile int disable_intr_times = 0; // use this to calculate how many times it go into interrupt static volatile int level_intr_times = 0; // use this to get how many times the level interrupt happened static volatile int edge_intr_times = 0; // use this to get how many times the edge interrupt happened -#if !WAKE_UP_IGNORE -static bool wake_up_result = false; // use this to judge the wake up event happen or not -#endif - /** - * do some initialization operation in this function - * @param num: it is the destination GPIO wanted to be initialized - * + * Do some initialization operation in this function + * @param num it is the destination GPIO wanted to be initialized */ -static gpio_config_t init_io(gpio_num_t num) +static gpio_config_t test_init_io(gpio_num_t num) { - TEST_ASSERT(num < TEST_GPIO_OUTPUT_MAX); + TEST_ASSERT(GPIO_IS_VALID_OUTPUT_GPIO(num)); gpio_config_t io_conf = { .intr_type = GPIO_INTR_DISABLE, .mode = GPIO_MODE_OUTPUT, @@ -118,16 +63,54 @@ static gpio_config_t init_io(gpio_num_t num) return io_conf; } +/** + * Configure gpio pin as GPIO_MODE_INPUT_OUTPUT for all the interrupt related tests to avoid runner requirements + */ +static void test_gpio_config_mode_input_output(gpio_num_t num) +{ + gpio_config_t input_output_io = test_init_io(num); + input_output_io.mode = GPIO_MODE_INPUT_OUTPUT; + input_output_io.pull_up_en = 1; + TEST_ESP_OK(gpio_config(&input_output_io)); +} + +// test the basic configuration function with right parameters and error parameters +TEST_CASE("GPIO_config_parameters_test", "[gpio]") +{ + gpio_config_t io_config = { 0 }; + io_config.intr_type = GPIO_INTR_DISABLE; + + // test 0 + io_config.pin_bit_mask = 0; + TEST_ASSERT(gpio_config(&io_config) == ESP_ERR_INVALID_ARG); + + // test a non-exist pin + io_config.pin_bit_mask = ((uint64_t)1 << GPIO_NUM_MAX); + TEST_ASSERT(gpio_config(&io_config) == ESP_ERR_INVALID_ARG); + + // test an available pin + io_config.pin_bit_mask = ((uint64_t)1 << TEST_GPIO_EXT_OUT_IO); + TEST_ESP_OK(gpio_config(&io_config)); + + //This IO is just used for input, C3 and S3 doesn't have input only pin. +#if SOC_HAS_INPUT_ONLY_PIN + io_config.pin_bit_mask = ((uint64_t)1 << TEST_GPIO_INPUT_ONLY_PIN); + io_config.mode = GPIO_MODE_INPUT; + TEST_ESP_OK(gpio_config(&io_config)); + io_config.mode = GPIO_MODE_OUTPUT; + // The pin is input only, once set as output should log something + TEST_ASSERT(gpio_config(&io_config) == ESP_ERR_INVALID_ARG); +#endif // SOC_HAS_INPUT_ONLY_PIN +} + // edge interrupt event -__attribute__((unused)) static void gpio_isr_edge_handler(void *arg) +static void gpio_isr_edge_handler(void *arg) { uint32_t gpio_num = (uint32_t) arg; esp_rom_printf("GPIO[%d] intr on core %d, val: %d\n", gpio_num, cpu_hal_get_core_id(), gpio_get_level(gpio_num)); edge_intr_times++; } -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32H2) -//No runners // level interrupt event with "gpio_intr_disable" static void gpio_isr_level_handler(void *arg) { @@ -137,46 +120,545 @@ static void gpio_isr_level_handler(void *arg) gpio_intr_disable(gpio_num); } -// level interrupt event +// level interrupt event with "gpio_set_level(!gpio_get_level)" static void gpio_isr_level_handler2(void *arg) { uint32_t gpio_num = (uint32_t) arg; level_intr_times++; - esp_rom_printf("GPIO[%d] intr, val: %d\n", gpio_num, gpio_get_level(gpio_num)); - if (gpio_get_level(gpio_num)) { - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); - } else { - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); - } - esp_rom_printf("GPIO[%d] intr, val: %d, level_intr_times = %d\n", TEST_GPIO_EXT_OUT_IO, gpio_get_level(TEST_GPIO_EXT_OUT_IO), level_intr_times); esp_rom_printf("GPIO[%d] intr, val: %d, level_intr_times = %d\n", gpio_num, gpio_get_level(gpio_num), level_intr_times); -} -#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32H2) - -#if !WAKE_UP_IGNORE -// get result of waking up or not -static void sleep_wake_up(void *arg) -{ - gpio_config_t io_config = init_io(TEST_GPIO_EXT_IN_IO); - io_config.mode = GPIO_MODE_INPUT; - gpio_config(&io_config); - TEST_ESP_OK(gpio_wakeup_enable(TEST_GPIO_EXT_IN_IO, GPIO_INTR_HIGH_LEVEL)); - esp_light_sleep_start(); - wake_up_result = true; + if (gpio_get_level(gpio_num)) { + gpio_set_level(gpio_num, 0); + } else { + gpio_set_level(gpio_num, 1); + } } -// wake up light sleep event -static void trigger_wake_up(void *arg) +TEST_CASE("GPIO_rising_edge_interrupt_test", "[gpio]") { - gpio_config_t io_config = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config(&io_config); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); + edge_intr_times = 0; // set it as 0 prepare to test + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + + // Rising edge intr + TEST_ESP_OK(gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO1, GPIO_INTR_POSEDGE)); + TEST_ESP_OK(gpio_install_isr_service(0)); + gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_edge_handler, (void *) TEST_GPIO_INPUT_OUTPUT_IO1); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT(1, edge_intr_times); + gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_uninstall_isr_service(); +} + +TEST_CASE("GPIO_falling_edge_interrupt_test", "[gpio]") +{ + edge_intr_times = 0; + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1)); + + gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO1, GPIO_INTR_NEGEDGE); gpio_install_isr_service(0); - gpio_isr_handler_add(TEST_GPIO_EXT_OUT_IO, gpio_isr_level_handler, (void *) TEST_GPIO_EXT_IN_IO); + gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_edge_handler, (void *) TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT(1, edge_intr_times); + gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_uninstall_isr_service(); +} + +TEST_CASE("GPIO_both_rising_and_falling_edge_interrupt_test", "[gpio]") +{ + edge_intr_times = 0; + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + int level = 0; + + gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO1, GPIO_INTR_ANYEDGE); + gpio_install_isr_service(0); + gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_edge_handler, (void *) TEST_GPIO_INPUT_OUTPUT_IO1); + // For rising edge in GPIO_INTR_ANYEDGE + while (1) { + level = level + 1; + gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, level * 0.2); + if (level > 10) { + break; + } + vTaskDelay(100 / portTICK_PERIOD_MS); + } + vTaskDelay(100 / portTICK_PERIOD_MS); + // For falling edge in GPIO_INTR_ANYEDGE + while (1) { + level = level - 1; + gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, level / 5); + if (level < 0) { + break; + } + vTaskDelay(100 / portTICK_PERIOD_MS); + } + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT(2, edge_intr_times); + gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_uninstall_isr_service(); +} + +TEST_CASE("GPIO_input_high_level_trigger_cut_the_interrupt_source_exit_interrupt_test", "[gpio]") +{ + level_intr_times = 0; + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + + gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO1, GPIO_INTR_HIGH_LEVEL); + gpio_install_isr_service(0); + gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_level_handler2, (void *) TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, level_intr_times, "go into high-level interrupt more than once with cut interrupt source way"); + gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_uninstall_isr_service(); +} + +TEST_CASE("GPIO_low_level_interrupt_test", "[gpio]") +{ + disable_intr_times = 0; + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1)); + + gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO1, GPIO_INTR_LOW_LEVEL); + gpio_install_isr_service(0); + gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_level_handler, (void *) TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0); + printf("get level:%d\n", gpio_get_level(TEST_GPIO_INPUT_OUTPUT_IO1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, disable_intr_times, "go into low-level interrupt more than once with disable way"); + gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_uninstall_isr_service(); +} + +TEST_CASE("GPIO_multi-level_trigger_cut_the_interrupt_source_exit_interrupt_test", "[gpio]") +{ + level_intr_times = 0; + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + + gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO1, GPIO_INTR_HIGH_LEVEL); + gpio_install_isr_service(0); + gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_level_handler2, (void *) TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, level_intr_times, "go into high-level interrupt more than once with cut interrupt source way"); + gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1); + vTaskDelay(200 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(2, level_intr_times, "go into high-level interrupt more than once with cut interrupt source way"); + gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_uninstall_isr_service(); +} + +TEST_CASE("GPIO_enable_and_disable_interrupt_test", "[gpio]") +{ + disable_intr_times = 0; + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + + TEST_ESP_OK(gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO1, GPIO_INTR_HIGH_LEVEL)); + TEST_ESP_OK(gpio_install_isr_service(0)); + TEST_ESP_OK(gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_level_handler, (void *) TEST_GPIO_INPUT_OUTPUT_IO1)); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1)); + TEST_ESP_OK(gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1)); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, disable_intr_times, "go into high-level interrupt more than once with disable way"); + + // Interrupt disabled now + TEST_ESP_OK(gpio_intr_disable(TEST_GPIO_INPUT_OUTPUT_IO1)); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, disable_intr_times, "disable interrupt does not work, still go into interrupt!"); + + // Uninstall interrupt service + gpio_uninstall_isr_service(); + TEST_ASSERT(gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_level_handler, (void *) TEST_GPIO_INPUT_OUTPUT_IO1) == ESP_ERR_INVALID_STATE); + TEST_ASSERT(gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1) == ESP_ERR_INVALID_STATE); +} + +TEST_CASE("GPIO_repeatedly_call_service_and_isr_has_no_memory_leak_test", "[gpio][timeout=90]") +{ + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + + // Rising edge intr + uint32_t size = esp_get_free_heap_size(); + for (int i = 0; i < 1000; i++) { + TEST_ESP_OK(gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO1, GPIO_INTR_POSEDGE)); + TEST_ESP_OK(gpio_install_isr_service(0)); + TEST_ESP_OK(gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_edge_handler, (void *) TEST_GPIO_INPUT_OUTPUT_IO1)); + gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1); + TEST_ESP_OK(gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1)); + gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0); + gpio_uninstall_isr_service(); + } + TEST_ASSERT_INT32_WITHIN(100, size, esp_get_free_heap_size()); +} + +typedef struct { + int gpio_num; + int isr_cnt; +} gpio_isr_param_t; + +static void gpio_isr_per_pin_handler(void *arg) +{ + gpio_isr_param_t *param = (gpio_isr_param_t *)arg; + esp_rom_printf("GPIO[%d] intr, val: %d\n", param->gpio_num, gpio_get_level(param->gpio_num)); + param->isr_cnt++; +} + +/** The old GPIO interrupt service routine used to poll the interrupt raw status register to find the GPIO that + * triggered the interrupt. But this will incorrectly handle the interrupt disabled GPIOs, because the raw interrupt + * status register can still be set when the trigger signal arrives, even if the interrupt is disabled. + * + * Do the following steps: + * 1. Configure TEST_GPIO_INPUT_OUTPUT_IO1 and TEST_GPIO_INPUT_OUTPUT_IO2 input_output mode. + * 2. Enable TEST_GPIO_INPUT_OUTPUT_IO1 dual edge triggered interrupt, enable TEST_GPIO_INPUT_OUTPUT_IO2 falling edge triggered interrupt. + * 3. Trigger TEST_GPIO_INPUT_OUTPUT_IO1 interrupt, then disable TEST_GPIO_INPUT_OUTPUT_IO1 interrupt, and then trigger TEST_GPIO_INPUT_OUTPUT_IO1 interrupt again (This time will not respond to the interrupt). + * 4. Trigger TEST_GPIO_INPUT_OUTPUT_IO2 interrupt. + * + * If the bug is not fixed, you will see, in the step 4, the interrupt of TEST_GPIO_INPUT_OUTPUT_IO1 will also respond. + */ +TEST_CASE("GPIO_isr_responses_to_correct_gpios_test", "[gpio]") +{ + gpio_isr_param_t io1_param = { + .gpio_num = TEST_GPIO_INPUT_OUTPUT_IO1, + .isr_cnt = 0, + }; + gpio_isr_param_t io2_param = { + .gpio_num = TEST_GPIO_INPUT_OUTPUT_IO2, + .isr_cnt = 0, + }; + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO2); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO2, 0)); + TEST_ESP_OK(gpio_install_isr_service(0)); + TEST_ESP_OK(gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO1, GPIO_INTR_ANYEDGE)); + TEST_ESP_OK(gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO2, GPIO_INTR_NEGEDGE)); + TEST_ESP_OK(gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_per_pin_handler, (void *) &io1_param)); + TEST_ESP_OK(gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO2, gpio_isr_per_pin_handler, (void *) &io2_param)); + + printf("Triggering the interrupt of GPIO%d\n", TEST_GPIO_INPUT_OUTPUT_IO1); + // Rising edge + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + printf("Disable the interrupt of GPIO%d\n", TEST_GPIO_INPUT_OUTPUT_IO1); + // Disable TEST_GPIO_INPUT_OUTPUT_IO1 interrupt, TEST_GPIO_INPUT_OUTPUT_IO1 will not respond to the next falling edge interrupt + TEST_ESP_OK(gpio_intr_disable(TEST_GPIO_INPUT_OUTPUT_IO1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + // Falling edge + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + + printf("Triggering the interrupt of GPIO%d\n", TEST_GPIO_INPUT_OUTPUT_IO2); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO2, 1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + // Falling edge + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO2, 0)); + vTaskDelay(100 / portTICK_PERIOD_MS); + + TEST_ESP_OK(gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1)); + TEST_ESP_OK(gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO2)); + gpio_uninstall_isr_service(); + TEST_ASSERT((io1_param.isr_cnt == 1) && (io2_param.isr_cnt == 1)); +} + +#if !CONFIG_FREERTOS_UNICORE +#include "esp_ipc.h" + +static void install_isr_service_task(void *arg) +{ + uint32_t gpio_num = (uint32_t) arg; + // Rising edge intr + TEST_ESP_OK(gpio_set_intr_type(gpio_num, GPIO_INTR_POSEDGE)); + TEST_ESP_OK(gpio_install_isr_service(0)); + gpio_isr_handler_add(gpio_num, gpio_isr_edge_handler, (void *) gpio_num); + vTaskSuspend(NULL); +} + +TEST_CASE("GPIO_interrupt_on_other_CPUs_test", "[gpio]") +{ + TaskHandle_t gpio_task_handle; + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + + for (int cpu_num = 1; cpu_num < portNUM_PROCESSORS; ++cpu_num) { + // We assume unit-test task is running on core 0, so we install gpio interrupt on other cores + edge_intr_times = 0; + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + xTaskCreatePinnedToCore(install_isr_service_task, "install_isr_service_task", 2048, (void *) TEST_GPIO_INPUT_OUTPUT_IO1, 1, &gpio_task_handle, cpu_num); + + vTaskDelay(200 / portTICK_PERIOD_MS); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT(1, edge_intr_times); + gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_uninstall_isr_service(); + unity_utils_task_delete(gpio_task_handle); + } +} + +static void gpio_intr_enable_task(void *param) +{ + int gpio_num = (int) param; + TEST_ESP_OK(gpio_intr_enable(gpio_num)); +} + +/** Test the GPIO Interrupt Enable API with dual core enabled. The GPIO ISR service routine is registered on one core. + * When the GPIO interrupt on another core is enabled, the GPIO interrupt will be lost. + * Note. This is only a problem for ESP32. On ESP32S3, interrupt enable is effective to both cores, therefore, no matter + * which core the interrupt service is installed on, the GPIO interrupt won't be lost. + * + * First on the core 0, do the following steps: + * 1. Configure TEST_GPIO_INPUT_OUTPUT_IO1 input_output mode, and enable the falling edge interrupt mode. + * 2. Trigger TEST_GPIO_INPUT_OUTPUT_IO1 interrupt and check if the interrupt responds correctly. + * 3. Disable TEST_GPIO_INPUT_OUTPUT_IO1 interrupt + * Then on the core 1, do the following steps: + * 1. Enable TEST_GPIO_INPUT_OUTPUT_IO1 interrupt again. + * 2. Trigger TEST_GPIO_INPUT_OUTPUT_IO1 interrupt and check if the interrupt responds correctly. + */ +TEST_CASE("GPIO_crosscore_interrupt_test", "[gpio]") +{ + edge_intr_times = 0; + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + + TEST_ESP_OK(gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO1, GPIO_INTR_NEGEDGE)); + // GPIO interrupt service installed on core 0 + TEST_ESP_OK(gpio_install_isr_service(0)); + TEST_ESP_OK(gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_edge_handler, (void *) TEST_GPIO_INPUT_OUTPUT_IO1)); + vTaskDelay(1000 / portTICK_PERIOD_MS); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ESP_OK(gpio_intr_disable(TEST_GPIO_INPUT_OUTPUT_IO1)); + TEST_ASSERT(edge_intr_times == 1); + // Here, interrupt is enabling from core 1, but since the isr is installed on core 0, core 0 interrupt enable bit + // will still be set instead of core 1 interrupt enable bit + esp_ipc_call_blocking((xPortGetCoreID() == 0), gpio_intr_enable_task, (void *) TEST_GPIO_INPUT_OUTPUT_IO1); + vTaskDelay(1000 / portTICK_PERIOD_MS); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1)); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ESP_OK(gpio_intr_disable(TEST_GPIO_INPUT_OUTPUT_IO1)); + TEST_ESP_OK(gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1)); + gpio_uninstall_isr_service(); + TEST_ASSERT(edge_intr_times == 2); +} +#endif //!CONFIG_FREERTOS_UNICORE + +#if CONFIG_GPIO_CTRL_FUNC_IN_IRAM +static volatile DRAM_ATTR bool isr_triggered = false; + +static void IRAM_ATTR gpio_isr_level_iram_handler(void *arg) +{ + uint32_t gpio_num = (uint32_t) arg; + isr_triggered = true; + gpio_intr_disable(gpio_num); +} + +static void IRAM_ATTR gpio_wait_intr_done_task(void *arg) +{ + SemaphoreHandle_t sem = (SemaphoreHandle_t) arg; + spi_flash_guard_get()->start(); // Disables flash cache + // Since interrupt service is installed on core 0, we enable the gpio intr on core 0 + gpio_ll_intr_enable_on_core(&GPIO, 0, TEST_GPIO_INPUT_OUTPUT_IO1); + // Wait until interrupt triggered + while (!isr_triggered) { + ; + } + spi_flash_guard_get()->end(); // Re-enables flash cache + xSemaphoreGive(sem); + vTaskSuspend(NULL); +} + +TEST_CASE("GPIO_iram_interrupt_safe_test", "[gpio]") +{ + SemaphoreHandle_t done_sem = xSemaphoreCreateBinary(); + TaskHandle_t task_handle; + TEST_ASSERT_NOT_NULL(done_sem); + test_gpio_config_mode_input_output(TEST_GPIO_INPUT_OUTPUT_IO1); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 0)); + + TEST_ESP_OK(gpio_set_intr_type(TEST_GPIO_INPUT_OUTPUT_IO1, GPIO_INTR_HIGH_LEVEL)); + // We assume unit-test task is running on core 0, so interrupt service is installed on core 0 + TEST_ESP_OK(gpio_install_isr_service(ESP_INTR_FLAG_IRAM)); + TEST_ESP_OK(gpio_isr_handler_add(TEST_GPIO_INPUT_OUTPUT_IO1, gpio_isr_level_iram_handler, (void *) TEST_GPIO_INPUT_OUTPUT_IO1)); + // Disable intr and set pin level high, such that once the intr is re-enabled, it will trigger isr + TEST_ESP_OK(gpio_intr_disable(TEST_GPIO_INPUT_OUTPUT_IO1)); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_INPUT_OUTPUT_IO1, 1)); + xTaskCreate(gpio_wait_intr_done_task, "gpio_wait_intr_done_task", 2048, done_sem, 1, &task_handle); + + xSemaphoreTake(done_sem, portMAX_DELAY); + gpio_isr_handler_remove(TEST_GPIO_INPUT_OUTPUT_IO1); + gpio_uninstall_isr_service(); + vSemaphoreDelete(done_sem); + unity_utils_task_delete(task_handle); +} +#endif + +#if TEST_GPIO_INTERNAL_ROUTING +// Inter-connect input pin and output pin through an internal signal +static void gpio_interconnect_input_output_pin(uint32_t input_pin, uint32_t output_pin, uint32_t signal_idx) +{ + // signal256 -> output pin -> signal_idx -> input_pin + // Set output pin IE to be able to connect to the signal + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[output_pin]); + esp_rom_gpio_connect_in_signal(output_pin, signal_idx, 0); + // Input pin OE to be able to connect to the signal is done by the esp_rom_gpio_connect_out_signal function + esp_rom_gpio_connect_out_signal(input_pin, signal_idx, 0, 0); +} +#endif + +TEST_CASE("GPIO_set_output_level_get_input_level_test", "[gpio]") +{ + gpio_config_t output_io = test_init_io(TEST_GPIO_EXT_OUT_IO); + gpio_config(&output_io); + gpio_config_t input_io = test_init_io(TEST_GPIO_EXT_IN_IO); + input_io.mode = GPIO_MODE_INPUT; + gpio_config(&input_io); + +#if TEST_GPIO_INTERNAL_ROUTING + gpio_interconnect_input_output_pin(TEST_GPIO_EXT_IN_IO, TEST_GPIO_EXT_OUT_IO, TEST_GPIO_SIGNAL_IDX); +#endif + + gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); + vTaskDelay(100 / portTICK_PERIOD_MS); + // tested voltage is around 0v + TEST_ASSERT_EQUAL_INT_MESSAGE(0, gpio_get_level(TEST_GPIO_EXT_IN_IO), "get level error! the level should be low!"); gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); vTaskDelay(100 / portTICK_PERIOD_MS); + // tested voltage is around 3.3v + TEST_ASSERT_EQUAL_INT_MESSAGE(1, gpio_get_level(TEST_GPIO_EXT_IN_IO), "get level error! the level should be high!"); +} + +// This test routes constant-high/low signal to pins, another way is to directly connect TEST_GPIO_EXT_IN_IO to +// 3.3v or GND pin +TEST_CASE("GPIO_get_level_from_fixed_voltage_test", "[gpio]") +{ +#if !TEST_GPIO_INTERNAL_ROUTING + // If TEST_GPIO_EXT_OUT_IO is connected to TEST_GPIO_EXT_IN_IO, prevent being affected + gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_DISABLE); +#endif + gpio_config_t input_io = test_init_io(TEST_GPIO_EXT_IN_IO); + input_io.mode = GPIO_MODE_INPUT; + gpio_config(&input_io); + esp_rom_gpio_connect_out_signal(TEST_GPIO_EXT_IN_IO, TEST_GPIO_SIGNAL_IDX, 0, 0); + + // Connect TEST_GPIO_EXT_IN_IO to a constant-high signal (to simulate connection to 3.3v) + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, TEST_GPIO_SIGNAL_IDX, 0); + int level1 = gpio_get_level(TEST_GPIO_EXT_IN_IO); + printf("TEST_GPIO_EXT_IN_IO(GPIO%d)'s level is: %d\n", TEST_GPIO_EXT_IN_IO, level1); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, level1, "get level error! the level should be high!"); + + // Connect TEST_GPIO_EXT_IN_IO to a constant-low signal (to simulate connection to GND) + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, TEST_GPIO_SIGNAL_IDX, 0); + int level2 = gpio_get_level(TEST_GPIO_EXT_IN_IO); + printf("TEST_GPIO_EXT_IN_IO(GPIO%d)'s level is: %d\n", TEST_GPIO_EXT_IN_IO, level2); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, level2, "get level error! the level should be low!"); +} + +TEST_CASE("GPIO_io_pull_up/down_function", "[gpio]") +{ + // First, ensure that the output IO will not affect the level + gpio_config_t io_conf = test_init_io(TEST_GPIO_EXT_OUT_IO); + gpio_config(&io_conf); + gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_INPUT); + io_conf = test_init_io(TEST_GPIO_EXT_IN_IO); + gpio_config(&io_conf); + gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_INPUT); + TEST_ESP_OK(gpio_pullup_en(TEST_GPIO_EXT_IN_IO)); // pull up first + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, gpio_get_level(TEST_GPIO_EXT_IN_IO), "gpio_pullup_en error, it can't pull up"); + TEST_ESP_OK(gpio_pulldown_dis(TEST_GPIO_EXT_IN_IO)); //can't be pull down + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, gpio_get_level(TEST_GPIO_EXT_IN_IO), "gpio_pulldown_dis error, it can pull down"); + TEST_ESP_OK(gpio_pulldown_en(TEST_GPIO_EXT_IN_IO)); // can be pull down now + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, gpio_get_level(TEST_GPIO_EXT_IN_IO), "gpio_pulldown_en error, it can't pull down"); + TEST_ESP_OK(gpio_pullup_dis(TEST_GPIO_EXT_IN_IO)); // can't be pull up + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, gpio_get_level(TEST_GPIO_EXT_IN_IO), "gpio_pullup_dis error, it can pull up"); +} + +// This test case tests whether gpio_set_level() outputs correctly with all gpio modes (gpio_mode_t) +TEST_CASE("GPIO_mode_test", "[gpio]") +{ + gpio_config_t output_io = test_init_io(TEST_GPIO_EXT_OUT_IO); + gpio_config_t input_io = test_init_io(TEST_GPIO_EXT_IN_IO); + gpio_config(&output_io); + gpio_config(&input_io); + int level = gpio_get_level(TEST_GPIO_EXT_IN_IO); + + // Disable mode + gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_DISABLE); + gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_OUTPUT); +#if TEST_GPIO_INTERNAL_ROUTING + gpio_interconnect_input_output_pin(TEST_GPIO_EXT_IN_IO, TEST_GPIO_EXT_OUT_IO, TEST_GPIO_SIGNAL_IDX); +#endif + gpio_set_level(TEST_GPIO_EXT_OUT_IO, !level); + TEST_ASSERT_EQUAL_INT_MESSAGE(level, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_DISABLE set error, it can output"); + + // Output mode + gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_OUTPUT); + gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_INPUT); +#if TEST_GPIO_INTERNAL_ROUTING + gpio_interconnect_input_output_pin(TEST_GPIO_EXT_IN_IO, TEST_GPIO_EXT_OUT_IO, TEST_GPIO_SIGNAL_IDX); +#endif + gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_OUTPUT set error, it can't output"); + gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_OUTPUT set error, it can't output"); + + // Open drain mode(output), can just output low level + gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_OUTPUT_OD); + gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_INPUT); +#if TEST_GPIO_INTERNAL_ROUTING + gpio_interconnect_input_output_pin(TEST_GPIO_EXT_IN_IO, TEST_GPIO_EXT_OUT_IO, TEST_GPIO_SIGNAL_IDX); +#endif + // Outputs high level: w/ pull up, then must read high level; w/ pull down, then must read low level + gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); + gpio_set_pull_mode(TEST_GPIO_EXT_OUT_IO, GPIO_PULLUP_ONLY); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_OUTPUT_OD with GPIO_PULLUP_ONLY set error, it outputs low level"); + gpio_set_pull_mode(TEST_GPIO_EXT_OUT_IO, GPIO_PULLDOWN_ONLY); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_OUTPUT_OD with GPIO_PULLDOWN_ONLY set error, it outputs high level"); + // Outputs low level: must read low level + gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); + gpio_set_pull_mode(TEST_GPIO_EXT_OUT_IO, GPIO_FLOATING); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_OUTPUT_OD set error, it outputs high level"); + + // Open drain mode(output and input), can just output low level + gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_INPUT); +#if TEST_GPIO_INTERNAL_ROUTING + gpio_interconnect_input_output_pin(TEST_GPIO_EXT_IN_IO, TEST_GPIO_EXT_OUT_IO, TEST_GPIO_SIGNAL_IDX); +#endif + // Outputs high level: w/ pull up, then must read high level; w/ pull down, then must read low level + gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); + gpio_set_pull_mode(TEST_GPIO_EXT_OUT_IO, GPIO_PULLUP_ONLY); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_INPUT_OUTPUT_OD with GPIO_PULLUP_ONLY set error, it outputs low level"); + gpio_set_pull_mode(TEST_GPIO_EXT_OUT_IO, GPIO_PULLDOWN_ONLY); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_INPUT_OUTPUT_OD with GPIO_PULLDOWN_ONLY set error, it outputs high level"); + // Outputs low level: must read low level + gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); + gpio_set_pull_mode(TEST_GPIO_EXT_OUT_IO, GPIO_FLOATING); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_INPUT_OUTPUT_OD set error, it outputs high level"); + + // GPIO_MODE_INPUT_OUTPUT mode + level = gpio_get_level(TEST_GPIO_EXT_IN_IO); + gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_INPUT_OUTPUT); + gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_INPUT); +#if TEST_GPIO_INTERNAL_ROUTING + gpio_interconnect_input_output_pin(TEST_GPIO_EXT_IN_IO, TEST_GPIO_EXT_OUT_IO, TEST_GPIO_SIGNAL_IDX); +#endif + gpio_set_level(TEST_GPIO_EXT_OUT_IO, !level); + TEST_ASSERT_EQUAL_INT_MESSAGE(!level, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_INPUT_OUTPUT set error, it gives incorrect output"); } -#endif //!WAKE_UP_IGNORE static void prompt_to_continue(const char *str) { @@ -191,454 +673,12 @@ static void prompt_to_continue(const char *str) } } -static void drive_capability_set_get(gpio_num_t num, gpio_drive_cap_t capability) +// This case needs the resistance to pull up the voltage or pull down the voltage +// Ignored in CI because the voltage needs to be tested with multimeter +TEST_CASE_CI_IGNORE("GPIO_verify_only_the_gpio_with_input_ability_can_be_set_pull/down", "[gpio]") { - gpio_config_t pad_io = init_io(num); - TEST_ESP_OK(gpio_config(&pad_io)); - TEST_ASSERT(gpio_set_drive_capability(num, GPIO_DRIVE_CAP_MAX) == ESP_ERR_INVALID_ARG); - - gpio_drive_cap_t cap; - TEST_ESP_OK(gpio_set_drive_capability(num, capability)); - TEST_ESP_OK(gpio_get_drive_capability(num, &cap)); - TEST_ASSERT_EQUAL_INT(cap, capability); -} - - -// test the basic configuration function with right parameters and error parameters -TEST_CASE("GPIO_config_parameters_test", "[gpio]") -{ - //error param test - //ESP32 test 41 bit, ESP32-S2 test 48 bit, ESP32-S3 test 50 bit - gpio_config_t io_config = { 0 }; - io_config.intr_type = GPIO_INTR_DISABLE; - io_config.pin_bit_mask = ((uint64_t)1 << (GPIO_NUM_MAX + 1)); - TEST_ASSERT(gpio_config(&io_config) == ESP_ERR_INVALID_ARG); - - // test 0 - io_config.pin_bit_mask = 0; - TEST_ASSERT(gpio_config(&io_config) == ESP_ERR_INVALID_ARG); - - //ESP32 test 40 bit, ESP32-S2 test 47 bit, ESP32-S3 test 49 bit - io_config.pin_bit_mask = ((uint64_t)1 << GPIO_NUM_MAX); - TEST_ASSERT(gpio_config(&io_config) == ESP_ERR_INVALID_ARG); - - io_config.pin_bit_mask = ((uint64_t)1 << TEST_GPIO_OUTPUT_PIN); - TEST_ESP_OK(gpio_config(&io_config)); - - //This IO is just used for input, C3 and S3 doesn't have input only pin. -#if SOC_HAS_INPUT_ONLY_PIN - io_config.pin_bit_mask = ((uint64_t)1 << TEST_GPIO_INPUT_ONLY_PIN); - io_config.mode = GPIO_MODE_INPUT; - TEST_ESP_OK(gpio_config(&io_config)); - io_config.mode = GPIO_MODE_OUTPUT; - // The pin is input only, once set as output should log something - TEST_ASSERT(gpio_config(&io_config) == ESP_ERR_INVALID_ARG); -#endif // SOC_HAS_INPUT_ONLY_PIN -} - -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32H2) -//No runners -TEST_CASE("GPIO_rising_edge_interrupt_test", "[gpio][test_env=UT_T1_GPIO]") -{ - edge_intr_times = 0; // set it as 0 prepare to test - //init input and output gpio - gpio_config_t output_io = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config_t input_io = init_io(TEST_GPIO_EXT_IN_IO); - input_io.intr_type = GPIO_INTR_POSEDGE; - input_io.mode = GPIO_MODE_INPUT; - input_io.pull_up_en = 1; - TEST_ESP_OK(gpio_config(&output_io)); - TEST_ESP_OK(gpio_config(&input_io)); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0)); - - //rising edge intr - TEST_ESP_OK(gpio_set_intr_type(TEST_GPIO_EXT_IN_IO, GPIO_INTR_POSEDGE)); - TEST_ESP_OK(gpio_install_isr_service(0)); - gpio_isr_handler_add(TEST_GPIO_EXT_IN_IO, gpio_isr_edge_handler, (void *)TEST_GPIO_EXT_IN_IO); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1)); - TEST_ASSERT_EQUAL_INT(edge_intr_times, 1); - vTaskDelay(100 / portTICK_PERIOD_MS); - gpio_isr_handler_remove(TEST_GPIO_EXT_IN_IO); - gpio_uninstall_isr_service(); -} - -TEST_CASE("GPIO_falling_edge_interrupt_test", "[gpio][test_env=UT_T1_GPIO]") -{ - edge_intr_times = 0; - gpio_config_t output_io = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config_t input_io = init_io(TEST_GPIO_EXT_IN_IO); - input_io.intr_type = GPIO_INTR_POSEDGE; - input_io.mode = GPIO_MODE_INPUT; - input_io.pull_up_en = 1; - TEST_ESP_OK(gpio_config(&output_io)); - TEST_ESP_OK(gpio_config(&input_io)); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1)); - - gpio_set_intr_type(TEST_GPIO_EXT_IN_IO, GPIO_INTR_NEGEDGE); - gpio_install_isr_service(0); - gpio_isr_handler_add(TEST_GPIO_EXT_IN_IO, gpio_isr_edge_handler, (void *) TEST_GPIO_EXT_IN_IO); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_EQUAL_INT(edge_intr_times, 1); - vTaskDelay(100 / portTICK_PERIOD_MS); - gpio_isr_handler_remove(TEST_GPIO_EXT_IN_IO); - gpio_uninstall_isr_service(); -} - -TEST_CASE("GPIO_both_rising_and_falling_edge_interrupt_test", "[gpio][test_env=UT_T1_GPIO]") -{ - edge_intr_times = 0; - gpio_config_t output_io = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config_t input_io = init_io(TEST_GPIO_EXT_IN_IO); - input_io.intr_type = GPIO_INTR_POSEDGE; - input_io.mode = GPIO_MODE_INPUT; - input_io.pull_up_en = 1; - TEST_ESP_OK(gpio_config(&output_io)); - TEST_ESP_OK(gpio_config(&input_io)); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0)); - int level = 0; - - gpio_set_intr_type(TEST_GPIO_EXT_IN_IO, GPIO_INTR_ANYEDGE); - gpio_install_isr_service(0); - gpio_isr_handler_add(TEST_GPIO_EXT_IN_IO, gpio_isr_edge_handler, (void *) TEST_GPIO_EXT_IN_IO); - // for rising edge in GPIO_INTR_ANYEDGE - while (1) { - level = level + 1; - gpio_set_level(TEST_GPIO_EXT_OUT_IO, level * 0.2); - if (level > 10) { - break; - } - vTaskDelay(100 / portTICK_PERIOD_MS); - } - vTaskDelay(100 / portTICK_PERIOD_MS); - // for falling rdge in GPIO_INTR_ANYEDGE - while (1) { - level = level - 1; - gpio_set_level(TEST_GPIO_EXT_OUT_IO, level / 5); - if (level < 0) { - break; - } - vTaskDelay(100 / portTICK_PERIOD_MS); - } - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_EQUAL_INT(edge_intr_times, 2); - vTaskDelay(100 / portTICK_PERIOD_MS); - gpio_isr_handler_remove(TEST_GPIO_EXT_IN_IO); - gpio_uninstall_isr_service(); -} - -TEST_CASE("GPIO_input_high_level_trigger_cut_the_interrupt_source_exit_interrupt_test", "[gpio][test_env=UT_T1_GPIO]") -{ - level_intr_times = 0; - gpio_config_t output_io = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config_t input_io = init_io(TEST_GPIO_EXT_IN_IO); - input_io.intr_type = GPIO_INTR_POSEDGE; - input_io.mode = GPIO_MODE_INPUT; - input_io.pull_up_en = 1; - TEST_ESP_OK(gpio_config(&output_io)); - TEST_ESP_OK(gpio_config(&input_io)); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0)); - - gpio_set_intr_type(TEST_GPIO_EXT_IN_IO, GPIO_INTR_HIGH_LEVEL); - gpio_install_isr_service(0); - gpio_isr_handler_add(TEST_GPIO_EXT_IN_IO, gpio_isr_level_handler2, (void *) TEST_GPIO_EXT_IN_IO); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_EQUAL_INT_MESSAGE(level_intr_times, 1, "go into high-level interrupt more than once with cur interrupt source way"); - gpio_isr_handler_remove(TEST_GPIO_EXT_IN_IO); - gpio_uninstall_isr_service(); - -} - -TEST_CASE("GPIO_low_level_interrupt_test", "[gpio][test_env=UT_T1_GPIO]") -{ - disable_intr_times = 0; - gpio_config_t output_io = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config_t input_io = init_io(TEST_GPIO_EXT_IN_IO); - input_io.intr_type = GPIO_INTR_POSEDGE; - input_io.mode = GPIO_MODE_INPUT; - input_io.pull_up_en = 1; - TEST_ESP_OK(gpio_config(&output_io)); - TEST_ESP_OK(gpio_config(&input_io)); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1)); - - gpio_set_intr_type(TEST_GPIO_EXT_IN_IO, GPIO_INTR_LOW_LEVEL); - gpio_install_isr_service(0); - gpio_isr_handler_add(TEST_GPIO_EXT_IN_IO, gpio_isr_level_handler, (void *) TEST_GPIO_EXT_IN_IO); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); - printf("get level:%d\n", gpio_get_level(TEST_GPIO_EXT_IN_IO)); - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_EQUAL_INT_MESSAGE(disable_intr_times, 1, "go into low-level interrupt more than once with disable way"); - gpio_isr_handler_remove(TEST_GPIO_EXT_IN_IO); - gpio_uninstall_isr_service(); -} - -TEST_CASE("GPIO_multi-level_interrupt_test_to_cut_the_interrupt_source_exit_interrupt", "[gpio][test_env=UT_T1_GPIO]") -{ - level_intr_times = 0; - gpio_config_t output_io = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config_t input_io = init_io(TEST_GPIO_EXT_IN_IO); - input_io.intr_type = GPIO_INTR_POSEDGE; - input_io.mode = GPIO_MODE_INPUT; - input_io.pull_up_en = 1; - TEST_ESP_OK(gpio_config(&output_io)); - TEST_ESP_OK(gpio_config(&input_io)); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0)); - - gpio_set_intr_type(TEST_GPIO_EXT_IN_IO, GPIO_INTR_HIGH_LEVEL); - gpio_install_isr_service(0); - gpio_isr_handler_add(TEST_GPIO_EXT_IN_IO, gpio_isr_level_handler2, (void *) TEST_GPIO_EXT_IN_IO); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_EQUAL_INT_MESSAGE(level_intr_times, 1, "go into high-level interrupt more than once with cur interrupt source way"); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); - vTaskDelay(200 / portTICK_PERIOD_MS); - TEST_ASSERT_EQUAL_INT_MESSAGE(level_intr_times, 2, "go into high-level interrupt more than once with cur interrupt source way"); - gpio_isr_handler_remove(TEST_GPIO_EXT_IN_IO); - gpio_uninstall_isr_service(); -} - -TEST_CASE("GPIO_enable_and_disable_interrupt_test", "[gpio][test_env=UT_T1_GPIO]") -{ - disable_intr_times = 0; - gpio_config_t output_io = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config_t input_io = init_io(TEST_GPIO_EXT_IN_IO); - input_io.intr_type = GPIO_INTR_POSEDGE; - input_io.mode = GPIO_MODE_INPUT; - input_io.pull_up_en = 1; - TEST_ESP_OK(gpio_config(&output_io)); - TEST_ESP_OK(gpio_config(&input_io)); - - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0)); // Because of GPIO_INTR_HIGH_LEVEL interrupt, 0 must be set first - TEST_ESP_OK(gpio_set_intr_type(TEST_GPIO_EXT_IN_IO, GPIO_INTR_HIGH_LEVEL)); - TEST_ESP_OK(gpio_install_isr_service(0)); - TEST_ESP_OK(gpio_isr_handler_add(TEST_GPIO_EXT_IN_IO, gpio_isr_level_handler, (void *) TEST_GPIO_EXT_IN_IO)); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1)); - TEST_ESP_OK(gpio_isr_handler_remove(TEST_GPIO_EXT_IN_IO)); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0)); - TEST_ASSERT_EQUAL_INT_MESSAGE(disable_intr_times, 1, "go into high-level interrupt more than once with disable way"); - - // not install service now - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ESP_OK(gpio_intr_disable(TEST_GPIO_EXT_IN_IO)); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1)); - TEST_ASSERT_EQUAL_INT_MESSAGE(disable_intr_times, 1, "disable interrupt does not work, still go into interrupt!"); - - gpio_uninstall_isr_service(); //uninstall the service - TEST_ASSERT(gpio_isr_handler_add(TEST_GPIO_EXT_IN_IO, gpio_isr_level_handler, (void *) TEST_GPIO_EXT_IN_IO) == ESP_ERR_INVALID_STATE); - TEST_ASSERT(gpio_isr_handler_remove(TEST_GPIO_EXT_IN_IO) == ESP_ERR_INVALID_STATE); -} -#endif //DISABLED_FOR_TARGETS(ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32H2) - -#if !CONFIG_FREERTOS_UNICORE -static void install_isr_service_task(void *arg) -{ - uint32_t gpio_num = (uint32_t) arg; - //rising edge intr - TEST_ESP_OK(gpio_set_intr_type(gpio_num, GPIO_INTR_POSEDGE)); - TEST_ESP_OK(gpio_install_isr_service(0)); - gpio_isr_handler_add(gpio_num, gpio_isr_edge_handler, (void *) gpio_num); - vTaskSuspend(NULL); -} - -TEST_CASE("GPIO_interrupt_on_other_CPUs_test", "[gpio]") -{ - TaskHandle_t gpio_task_handle; - gpio_config_t input_output_io = init_io(TEST_GPIO_EXT_OUT_IO); - input_output_io.mode = GPIO_MODE_INPUT_OUTPUT; - input_output_io.pull_up_en = 1; - TEST_ESP_OK(gpio_config(&input_output_io)); - - for (int cpu_num = 1; cpu_num < portNUM_PROCESSORS; ++cpu_num) { - // We assume unit-test task is running on core 0, so we install gpio interrupt on other cores - edge_intr_times = 0; - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0)); - xTaskCreatePinnedToCore(install_isr_service_task, "install_isr_service_task", 2048, (void *) TEST_GPIO_EXT_OUT_IO, 1, &gpio_task_handle, cpu_num); - - vTaskDelay(200 / portTICK_PERIOD_MS); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1)); - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_EQUAL_INT(edge_intr_times, 1); - gpio_isr_handler_remove(TEST_GPIO_EXT_OUT_IO); - gpio_uninstall_isr_service(); - unity_utils_task_delete(gpio_task_handle); - } -} -#endif //!CONFIG_FREERTOS_UNICORE - -// ESP32 Connect GPIO18 with GPIO19, ESP32-S2 Connect GPIO17 with GPIO21, -// ESP32-S3 Connect GPIO17 with GPIO21, ESP32C3 Connect GPIO2 with GPIO3 -// use multimeter to test the voltage, so it is ignored in CI -TEST_CASE("GPIO_set_gpio_output_level_test", "[gpio][ignore][UT_T1_GPIO]") -{ - gpio_config_t io_conf; - io_conf.intr_type = GPIO_INTR_DISABLE; - io_conf.mode = GPIO_MODE_OUTPUT; - io_conf.pin_bit_mask = ((uint64_t)1 << TEST_GPIO_EXT_OUT_IO); - io_conf.pull_down_en = 0; - io_conf.pull_up_en = 0; - gpio_config(&io_conf); - - io_conf.pin_bit_mask = ((uint64_t)1 << TEST_GPIO_EXT_IN_IO); - io_conf.mode = GPIO_MODE_INPUT; - gpio_config(&io_conf); - - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); - // tested voltage is around 0v - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 0, "get level error! the level should be low!"); - vTaskDelay(1000 / portTICK_PERIOD_MS); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); - // tested voltage is around 3.3v - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 1, "get level error! the level should be high!"); - - //This IO is just used for input, C3 and S3 doesn't have input only pin. -#if SOC_HAS_INPUT_ONLY_PIN - io_conf.pin_bit_mask = ((uint64_t)1 << TEST_GPIO_INPUT_ONLY_PIN); - io_conf.mode = GPIO_MODE_OUTPUT; - gpio_config(&io_conf); - TEST_ASSERT(gpio_config(&io_conf) == ESP_ERR_INVALID_ARG); -#endif // SOC_HAS_INPUT_ONLY_PIN -} - -// TEST_GPIO_INPUT_LEVEL_HIGH_PIN connects to 3.3v pin, TEST_GPIO_INPUT_LEVEL_LOW_PIN connects to the GND pin -// use multimeter to test the voltage, so it is ignored in CI -TEST_CASE("GPIO_get_input_level_test", "[gpio][ignore]") -{ - gpio_num_t num1 = TEST_GPIO_INPUT_LEVEL_HIGH_PIN; - int level1 = gpio_get_level(num1); - printf("TEST_GPIO_INPUT_LEVEL_HIGH_PIN's level is: %d\n", level1); - TEST_ASSERT_EQUAL_INT_MESSAGE(level1, 1, "get level error! the level should be high!"); - - gpio_num_t num2 = TEST_GPIO_INPUT_LEVEL_LOW_PIN; - int level2 = gpio_get_level(num2); - printf("TEST_GPIO_INPUT_LEVEL_LOW_PIN's level is: %d\n", level2); - TEST_ASSERT_EQUAL_INT_MESSAGE(level2, 0, "get level error! the level should be low!"); - printf("the memory get: %d\n", esp_get_free_heap_size()); - //when case finish, get the result from multimeter, the TEST_GPIO_INPUT_LEVEL_HIGH_PIN is 3.3v, the TEST_GPIO_INPUT_LEVEL_LOW_PIN is 0.00v -} - -TEST_CASE("GPIO_io_pull_up/down_function", "[gpio]") -{ - // First, ensure that the output IO will not affect the level - gpio_config_t io_conf = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config(&io_conf); - gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_INPUT); - io_conf = init_io(TEST_GPIO_EXT_IN_IO); - gpio_config(&io_conf); - gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_INPUT); - TEST_ESP_OK(gpio_pullup_en(TEST_GPIO_EXT_IN_IO)); // pull up first - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 1, "gpio_pullup_en error, it can't pull up"); - TEST_ESP_OK(gpio_pulldown_dis(TEST_GPIO_EXT_IN_IO)); //can't be pull down - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 1, "gpio_pulldown_dis error, it can pull down"); - TEST_ESP_OK(gpio_pulldown_en(TEST_GPIO_EXT_IN_IO)); // can be pull down now - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 0, "gpio_pulldown_en error, it can't pull down"); - TEST_ESP_OK(gpio_pullup_dis(TEST_GPIO_EXT_IN_IO)); // can't be pull up - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 0, "gpio_pullup_dis error, it can pull up"); -} - -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32H2) -//No runners -TEST_CASE("GPIO_output_and_input_mode_test", "[gpio][test_env=UT_T1_GPIO]") -{ - //ESP32 connect io18 and io19, ESP32-S2 connect io17 and io21, ESP32-S3 connect io17 and io21, ESP32C3 Connect GPIO2 with GPIO3 - gpio_config_t output_io = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config_t input_io = init_io(TEST_GPIO_EXT_IN_IO); - gpio_config(&output_io); - gpio_config(&input_io); - int level = gpio_get_level(TEST_GPIO_EXT_IN_IO); - - //disable mode - gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_DISABLE); - gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_OUTPUT); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, !level); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), level, "direction GPIO_MODE_DISABLE set error, it can output"); - - //input mode and output mode - gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_OUTPUT); - gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_INPUT); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 1, "direction GPIO_MODE_OUTPUT set error, it can't output"); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 0, "direction GPIO_MODE_OUTPUT set error, it can't output"); - - // open drain mode(output), can just output low level - gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_OUTPUT_OD); - gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_INPUT); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 0, "direction GPIO_MODE_OUTPUT set error, it can't output"); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 0, "direction GPIO_MODE_OUTPUT set error, it can't output"); - - // open drain mode(output and input), can just output low level - // output test - gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_INPUT_OUTPUT_OD); - gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_INPUT); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 0, "direction GPIO_MODE_OUTPUT set error, it can't output"); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), 0, "direction GPIO_MODE_OUTPUT set error, it can't output"); - - // GPIO_MODE_INPUT_OUTPUT mode - // output test - level = gpio_get_level(TEST_GPIO_EXT_IN_IO); - gpio_set_direction(TEST_GPIO_EXT_OUT_IO, GPIO_MODE_INPUT_OUTPUT); - gpio_set_direction(TEST_GPIO_EXT_IN_IO, GPIO_MODE_INPUT); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, !level); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(TEST_GPIO_EXT_IN_IO), !level, "direction set error, it can't output"); -} - -TEST_CASE("GPIO_repeat_call_service_and_isr_has_no_memory_leak_test", "[gpio][test_env=UT_T1_GPIO][timeout=90]") -{ - gpio_config_t output_io = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config_t input_io = init_io(TEST_GPIO_EXT_IN_IO); - input_io.intr_type = GPIO_INTR_POSEDGE; - input_io.mode = GPIO_MODE_INPUT; - input_io.pull_up_en = 1; - TEST_ESP_OK(gpio_config(&output_io)); - TEST_ESP_OK(gpio_config(&input_io)); - TEST_ESP_OK(gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0)); - //rising edge - uint32_t size = esp_get_free_heap_size(); - for (int i = 0; i < 1000; i++) { - TEST_ESP_OK(gpio_set_intr_type(TEST_GPIO_EXT_IN_IO, GPIO_INTR_POSEDGE)); - TEST_ESP_OK(gpio_install_isr_service(0)); - TEST_ESP_OK(gpio_isr_handler_add(TEST_GPIO_EXT_IN_IO, gpio_isr_edge_handler, (void *)TEST_GPIO_EXT_IN_IO)); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); - TEST_ESP_OK(gpio_isr_handler_remove(TEST_GPIO_EXT_IN_IO)); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 0); - gpio_uninstall_isr_service(); - } - TEST_ASSERT_INT32_WITHIN(size, esp_get_free_heap_size(), 100); -} -#endif //DISABLED_FOR_TARGETS(ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32H2) - -#if !WAKE_UP_IGNORE -//this function development is not completed yet, set it ignored -TEST_CASE("GPIO_wake_up_enable_and_disable_test", "[gpio][ignore]") -{ - xTaskCreate(sleep_wake_up, "sleep_wake_up", 4096, NULL, 5, NULL); - xTaskCreate(trigger_wake_up, "trigger_wake_up", 4096, NULL, 5, NULL); - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_TRUE(wake_up_result); - - wake_up_result = false; - TEST_ESP_OK(gpio_wakeup_disable(TEST_GPIO_EXT_IN_IO)); - gpio_set_level(TEST_GPIO_EXT_OUT_IO, 1); - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT_FALSE(wake_up_result); -} -#endif // !WAKE_UP_IGNORE - -// this case need the resistance to pull up the voltage or pull down the voltage -// ignored because the voltage needs to be tested with multimeter -TEST_CASE("GPIO_verify_only_the_gpio_with_input_ability_can_be_set_pull/down", "[gpio][ignore]") -{ - gpio_config_t output_io = init_io(TEST_GPIO_EXT_OUT_IO); - gpio_config_t input_io = init_io(TEST_GPIO_EXT_IN_IO); + gpio_config_t output_io = test_init_io(TEST_GPIO_EXT_OUT_IO); + gpio_config_t input_io = test_init_io(TEST_GPIO_EXT_IN_IO); gpio_config(&output_io); input_io.mode = GPIO_MODE_INPUT; gpio_config(&input_io); @@ -690,6 +730,18 @@ TEST_CASE("GPIO_verify_only_the_gpio_with_input_ability_can_be_set_pull/down", " prompt_to_continue("mode: GPIO_MODE_INPUT"); } +static void drive_capability_set_get(gpio_num_t num, gpio_drive_cap_t capability) +{ + gpio_config_t pad_io = test_init_io(num); + TEST_ESP_OK(gpio_config(&pad_io)); + TEST_ASSERT(gpio_set_drive_capability(num, GPIO_DRIVE_CAP_MAX) == ESP_ERR_INVALID_ARG); + + gpio_drive_cap_t cap; + TEST_ESP_OK(gpio_set_drive_capability(num, capability)); + TEST_ESP_OK(gpio_get_drive_capability(num, &cap)); + TEST_ASSERT_EQUAL_INT(capability, cap); +} + /** * There are 5 situation for the GPIO drive capability: * 1. GPIO drive weak capability test @@ -710,11 +762,11 @@ TEST_CASE("GPIO_verify_only_the_gpio_with_input_ability_can_be_set_pull/down", " * strongest capability: (0.33-64.2)mA * * the data shows: - * weak capabilitygpio_num, gpio_get_level(param->gpio_num)); - param->isr_cnt++; -} - -/** The previous GPIO interrupt service routine polls the interrupt raw status register to find the GPIO that triggered the interrupt. - * But this will incorrectly handle the interrupt disabled GPIOs, because the raw interrupt status register can still be set when - * the trigger signal arrives, even if the interrupt is disabled. - * First on the core 0: - * 1. Configure the GPIO9 and GPIO10(ESP32, ESP32C3)/GPIO21(ESP32-S2) input_output mode. - * 2. Enable GPIO9 dual edge triggered interrupt, enable GPIO10(ESP32, ESP32C3)/GPIO21(ESP32-S2) falling edge triggered interrupt. - * 3. Trigger GPIO9 interrupt, than disable the GPIO18 interrupt, and than trigger GPIO18 again(This time will not respond to the interrupt). - * 4. Trigger GPIO10(ESP32, ESP32C3)/GPIO21(ESP32-S2) interrupt. - * If the bug is not fixed, you will see, in the step 4, the interrupt of GPIO9 will also respond. - */ -TEST_CASE("GPIO_ISR_service_test", "[gpio][ignore]") -{ - gpio_isr_param_t io9_param = { - .gpio_num = TEST_IO_9, - .isr_cnt = 0, - }; - gpio_isr_param_t io10_param = { - .gpio_num = TEST_IO_10, - .isr_cnt = 0, - }; - gpio_config_t io_conf; - io_conf.intr_type = GPIO_INTR_DISABLE; - io_conf.mode = GPIO_MODE_INPUT_OUTPUT; - io_conf.pin_bit_mask = (1ULL << TEST_IO_9) | (1ULL << TEST_IO_10); - io_conf.pull_down_en = 0; - io_conf.pull_up_en = 1; - TEST_ESP_OK(gpio_config(&io_conf)); - TEST_ESP_OK(gpio_set_level(TEST_IO_9, 0)); - TEST_ESP_OK(gpio_set_level(TEST_IO_10, 0)); - TEST_ESP_OK(gpio_install_isr_service(0)); - TEST_ESP_OK(gpio_set_intr_type(TEST_IO_9, GPIO_INTR_ANYEDGE)); - TEST_ESP_OK(gpio_set_intr_type(TEST_IO_10, GPIO_INTR_NEGEDGE)); - TEST_ESP_OK(gpio_isr_handler_add(TEST_IO_9, gpio_isr_handler, (void *)&io9_param)); - TEST_ESP_OK(gpio_isr_handler_add(TEST_IO_10, gpio_isr_handler, (void *)&io10_param)); - printf("Triggering the interrupt of GPIO9\n"); - vTaskDelay(1000 / portTICK_PERIOD_MS); - //Rising edge - TEST_ESP_OK(gpio_set_level(TEST_IO_9, 1)); - printf("Disable the interrupt of GPIO9\n"); - vTaskDelay(100 / portTICK_PERIOD_MS); - //Disable GPIO9 interrupt, GPIO18 will not respond to the next falling edge interrupt. - TEST_ESP_OK(gpio_intr_disable(TEST_IO_9)); - vTaskDelay(100 / portTICK_PERIOD_MS); - //Falling edge - TEST_ESP_OK(gpio_set_level(TEST_IO_9, 0)); - - printf("Triggering the interrupt of GPIO10\n"); - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ESP_OK(gpio_set_level(TEST_IO_10, 1)); - vTaskDelay(100 / portTICK_PERIOD_MS); - //Falling edge - TEST_ESP_OK(gpio_set_level(TEST_IO_10, 0)); - vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ESP_OK(gpio_isr_handler_remove(TEST_IO_9)); - TEST_ESP_OK(gpio_isr_handler_remove(TEST_IO_10)); - gpio_uninstall_isr_service(); - TEST_ASSERT((io9_param.isr_cnt == 1) && (io10_param.isr_cnt == 1)); -} - #if SOC_USB_SERIAL_JTAG_SUPPORTED TEST_CASE("GPIO_input_and_output_of_USB_pins_test", "[gpio]") { - const int test_pins[] = {TEST_GPIO_USB_DP_IO, TEST_GPIO_USB_DM_IO}; + const int test_pins[] = {USB_DM_GPIO_NUM, USB_DM_GPIO_NUM}; gpio_config_t io_conf = { .intr_type = GPIO_INTR_DISABLE, .mode = GPIO_MODE_INPUT_OUTPUT, @@ -878,22 +808,36 @@ TEST_CASE("GPIO_input_and_output_of_USB_pins_test", "[gpio]") gpio_set_level(pin, 0); // tested voltage is around 0v esp_rom_delay_us(10); - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(pin), 0, "get level error! the level should be low!"); - vTaskDelay(1000 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, gpio_get_level(pin), "get level error! the level should be low!"); gpio_set_level(pin, 1); esp_rom_delay_us(10); // tested voltage is around 3.3v - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(pin), 1, "get level error! the level should be high!"); - vTaskDelay(1000 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, gpio_get_level(pin), "get level error! the level should be high!"); gpio_set_level(pin, 0); esp_rom_delay_us(10); // tested voltage is around 0v - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(pin), 0, "get level error! the level should be low!"); - vTaskDelay(1000 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, gpio_get_level(pin), "get level error! the level should be low!"); gpio_set_level(pin, 1); esp_rom_delay_us(10); // tested voltage is around 3.3v - TEST_ASSERT_EQUAL_INT_MESSAGE(gpio_get_level(pin), 1, "get level error! the level should be high!"); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, gpio_get_level(pin), "get level error! the level should be high!"); } } #endif //SOC_USB_SERIAL_JTAG_SUPPORTED + +// Ignored in CI because it needs manually connect TEST_GPIO_INPUT_LEVEL_LOW_PIN to 3.3v to wake up from light sleep +TEST_CASE_CI_IGNORE("GPIO_light_sleep_wake_up_test", "[gpio]") +{ + gpio_config_t io_config = test_init_io(TEST_GPIO_INPUT_LEVEL_LOW_PIN); + io_config.mode = GPIO_MODE_INPUT; + io_config.pull_down_en = 1; + gpio_config(&io_config); + TEST_ESP_OK(gpio_wakeup_enable(TEST_GPIO_INPUT_LEVEL_LOW_PIN, GPIO_INTR_HIGH_LEVEL)); + TEST_ESP_OK(esp_sleep_enable_gpio_wakeup()); + printf("Entering light sleep... Please connect GPIO%d to 3.3v to wake up...\n", TEST_GPIO_INPUT_LEVEL_LOW_PIN); + // Wait for the complete line to be printed before entering sleep + vTaskDelay(1000 / portTICK_PERIOD_MS); + esp_light_sleep_start(); + printf("Waked up from light sleep\n"); + TEST_ASSERT(esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_GPIO); +} diff --git a/components/driver/test_apps/gpio/main/test_gpio.h b/components/driver/test_apps/gpio/main/test_gpio.h new file mode 100644 index 0000000000..6ab38136ea --- /dev/null +++ b/components/driver/test_apps/gpio/main/test_gpio.h @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "sdkconfig.h" +#include "soc/gpio_sig_map.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// GPIO self-test pins (GPIO_MODE_INPUT_OUTPUT) +#define TEST_GPIO_INPUT_OUTPUT_IO1 (4) +#define TEST_GPIO_INPUT_OUTPUT_IO2 (5) + +#if CONFIG_IDF_TARGET_ESP32 +#define TEST_GPIO_EXT_OUT_IO (18) +#define TEST_GPIO_EXT_IN_IO (19) +#define TEST_GPIO_INPUT_ONLY_PIN (34) +#define TEST_GPIO_INPUT_LEVEL_LOW_PIN (4) +#define TEST_GPIO_SIGNAL_IDX (SIG_IN_FUNC224_IDX) +#elif CONFIG_IDF_TARGET_ESP32S2 +#define TEST_GPIO_EXT_OUT_IO (17) +#define TEST_GPIO_EXT_IN_IO (21) +#define TEST_GPIO_INPUT_ONLY_PIN (46) +#define TEST_GPIO_INPUT_LEVEL_LOW_PIN (1) +#define TEST_GPIO_SIGNAL_IDX (SIG_IN_FUNC223_IDX) +#elif CONFIG_IDF_TARGET_ESP32S3 +#define TEST_GPIO_EXT_OUT_IO (17) +#define TEST_GPIO_EXT_IN_IO (21) +#define TEST_GPIO_INPUT_LEVEL_LOW_PIN (1) +#define TEST_GPIO_SIGNAL_IDX (SIG_IN_FUNC208_IDX) +#elif CONFIG_IDF_TARGET_ESP32C3 +#define TEST_GPIO_EXT_OUT_IO (2) +#define TEST_GPIO_EXT_IN_IO (3) +#define TEST_GPIO_INPUT_LEVEL_LOW_PIN (1) +#define TEST_GPIO_SIGNAL_IDX (SIG_IN_FUNC97_IDX) +#elif CONFIG_IDF_TARGET_ESP32C2 +#define TEST_GPIO_EXT_OUT_IO (2) +#define TEST_GPIO_EXT_IN_IO (3) +#define TEST_GPIO_INPUT_LEVEL_LOW_PIN (1) +#define TEST_GPIO_SIGNAL_IDX (SIG_IN_FUNC97_IDX) +#elif CONFIG_IDF_TARGET_ESP32H2 +#define TEST_GPIO_EXT_OUT_IO (6) +#define TEST_GPIO_EXT_IN_IO (7) +#define TEST_GPIO_INPUT_LEVEL_LOW_PIN (1) +#define TEST_GPIO_SIGNAL_IDX (SIG_IN_FUNC97_IDX) +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/driver/test_apps/gpio/sdkconfig.ci.iram_safe b/components/driver/test_apps/gpio/sdkconfig.ci.iram_safe index 4272350d24..abfc89e440 100644 --- a/components/driver/test_apps/gpio/sdkconfig.ci.iram_safe +++ b/components/driver/test_apps/gpio/sdkconfig.ci.iram_safe @@ -1,4 +1,4 @@ CONFIG_COMPILER_DUMP_RTL_FILES=y - +CONFIG_GPIO_CTRL_FUNC_IN_IRAM=y # silent the error check, as the error string are stored in rodata, causing RTL check failure CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y diff --git a/components/esp_rom/include/esp32h2/rom/gpio.h b/components/esp_rom/include/esp32h2/rom/gpio.h index 2969d14fc0..be60742711 100644 --- a/components/esp_rom/include/esp32h2/rom/gpio.h +++ b/components/esp_rom/include/esp32h2/rom/gpio.h @@ -1,16 +1,8 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #ifndef _ROM_GPIO_H_ #define _ROM_GPIO_H_ @@ -20,6 +12,7 @@ #include "esp_attr.h" #include "soc/gpio_reg.h" +#include "sdkconfig.h" #ifdef __cplusplus extern "C" { @@ -39,8 +32,13 @@ extern "C" { #define GPIO_ID_PIN(n) (GPIO_ID_PIN0+(n)) #define GPIO_PIN_ADDR(i) (GPIO_PIN0_REG + i*4) +#if CONFIG_IDF_TARGET_ESP32H2_BETA_VERSION_1 #define GPIO_FUNC_IN_HIGH 0x38 #define GPIO_FUNC_IN_LOW 0x3C +#elif CONFIG_IDF_TARGET_ESP32H2_BETA_VERSION_2 +#define GPIO_FUNC_IN_HIGH 0x1E +#define GPIO_FUNC_IN_LOW 0x1F +#endif #define GPIO_ID_IS_PIN_REGISTER(reg_id) \ ((reg_id >= GPIO_ID_PIN0) && (reg_id <= GPIO_ID_PIN(GPIO_PIN_COUNT-1))) diff --git a/components/hal/gpio_hal.c b/components/hal/gpio_hal.c index 9907104ab3..6d9bd0a772 100644 --- a/components/hal/gpio_hal.c +++ b/components/hal/gpio_hal.c @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ // The HAL layer for GPIO (common part) diff --git a/components/hal/linker.lf b/components/hal/linker.lf index cf8dd38d5e..695b7be44f 100644 --- a/components/hal/linker.lf +++ b/components/hal/linker.lf @@ -24,3 +24,5 @@ entries: systimer_hal (noflash) if GPTIMER_CTRL_FUNC_IN_IRAM = y: timer_hal_iram (noflash) + if GPIO_CTRL_FUNC_IN_IRAM = y: + gpio_hal: gpio_hal_intr_disable (noflash) diff --git a/components/soc/esp32c3/include/soc/io_mux_reg.h b/components/soc/esp32c3/include/soc/io_mux_reg.h index 69d2ae4bb7..6d5ae6da2f 100644 --- a/components/soc/esp32c3/include/soc/io_mux_reg.h +++ b/components/soc/esp32c3/include/soc/io_mux_reg.h @@ -130,6 +130,9 @@ #define SD_DATA2_GPIO_NUM 9 #define SD_DATA3_GPIO_NUM 10 +#define USB_DM_GPIO_NUM 18 +#define USB_DP_GPIO_NUM 19 + #define MAX_RTC_GPIO_NUM 5 #define MAX_PAD_GPIO_NUM 21 #define MAX_GPIO_NUM 25 diff --git a/components/soc/esp32h2/include/rev1/soc/io_mux_reg.h b/components/soc/esp32h2/include/rev1/soc/io_mux_reg.h index 96ec302766..276c526990 100644 --- a/components/soc/esp32h2/include/rev1/soc/io_mux_reg.h +++ b/components/soc/esp32h2/include/rev1/soc/io_mux_reg.h @@ -149,6 +149,9 @@ #define SD_DATA2_GPIO_NUM 9 #define SD_DATA3_GPIO_NUM 10 +#define USB_DM_GPIO_NUM 18 +#define USB_DP_GPIO_NUM 19 + #define MAX_RTC_GPIO_NUM 5 #define MAX_PAD_GPIO_NUM 40 #define MAX_GPIO_NUM 44 diff --git a/components/soc/esp32h2/include/rev2/soc/io_mux_reg.h b/components/soc/esp32h2/include/rev2/soc/io_mux_reg.h index 26d6fba79c..829adedcf3 100644 --- a/components/soc/esp32h2/include/rev2/soc/io_mux_reg.h +++ b/components/soc/esp32h2/include/rev2/soc/io_mux_reg.h @@ -124,6 +124,9 @@ #define SPI_D_GPIO_NUM 18 #define SPI_Q_GPIO_NUM 14 +#define USB_DM_GPIO_NUM 24 +#define USB_DP_GPIO_NUM 25 + #define MAX_RTC_GPIO_NUM 12 // GPIO7~12 are the rtc_io pads #define MAX_PAD_GPIO_NUM 25 #define MAX_GPIO_NUM 29 diff --git a/components/soc/esp32h2/include/soc/gpio_pins.h b/components/soc/esp32h2/include/soc/gpio_pins.h index f5a35b9975..c7b38724d0 100644 --- a/components/soc/esp32h2/include/soc/gpio_pins.h +++ b/components/soc/esp32h2/include/soc/gpio_pins.h @@ -1,26 +1,25 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once +#include "sdkconfig.h" + #ifdef __cplusplus extern "C" { #endif +#if CONFIG_IDF_TARGET_ESP32H2_BETA_VERSION_1 +#define GPIO_MATRIX_CONST_ONE_INPUT (0x38) +#define GPIO_MATRIX_CONST_ZERO_INPUT (0x3C) +#elif CONFIG_IDF_TARGET_ESP32H2_BETA_VERSION_2 #define GPIO_MATRIX_CONST_ONE_INPUT (0x1E) #define GPIO_MATRIX_CONST_ZERO_INPUT (0x1F) +#endif #ifdef __cplusplus } diff --git a/components/soc/esp32s3/include/soc/io_mux_reg.h b/components/soc/esp32s3/include/soc/io_mux_reg.h index 1cde913790..f8456b33b7 100644 --- a/components/soc/esp32s3/include/soc/io_mux_reg.h +++ b/components/soc/esp32s3/include/soc/io_mux_reg.h @@ -154,6 +154,8 @@ #define SD_DATA1_GPIO_NUM 14 #define SD_DATA2_GPIO_NUM 9 #define SD_DATA3_GPIO_NUM 10 +#define USB_DM_GPIO_NUM 19 +#define USB_DP_GPIO_NUM 20 #define MAX_RTC_GPIO_NUM 21 #define MAX_PAD_GPIO_NUM 48 diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 94f0178c65..7864eff995 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -580,7 +580,6 @@ components/esp_rom/include/esp32h2/rom/digital_signature.h components/esp_rom/include/esp32h2/rom/efuse.h components/esp_rom/include/esp32h2/rom/esp_flash.h components/esp_rom/include/esp32h2/rom/ets_sys.h -components/esp_rom/include/esp32h2/rom/gpio.h components/esp_rom/include/esp32h2/rom/hmac.h components/esp_rom/include/esp32h2/rom/libc_stubs.h components/esp_rom/include/esp32h2/rom/lldesc.h @@ -906,7 +905,6 @@ components/hal/esp32s3/include/hal/uhci_ll.h components/hal/esp32s3/include/hal/usb_ll.h components/hal/esp32s3/include/hal/usb_serial_jtag_ll.h components/hal/esp32s3/interrupt_descriptor_table.c -components/hal/gpio_hal.c components/hal/include/hal/aes_hal.h components/hal/include/hal/aes_types.h components/hal/include/hal/brownout_hal.h @@ -1384,7 +1382,6 @@ components/soc/esp32h2/include/soc/efuse_reg.h components/soc/esp32h2/include/soc/efuse_struct.h components/soc/esp32h2/include/soc/extmem_reg.h components/soc/esp32h2/include/soc/fe_reg.h -components/soc/esp32h2/include/soc/gpio_pins.h components/soc/esp32h2/include/soc/gpio_sd_reg.h components/soc/esp32h2/include/soc/gpio_sd_struct.h components/soc/esp32h2/include/soc/hwcrypto_reg.h