diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 756c36eaa..82d3eaa45 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -988,6 +988,31 @@ UT_005_02: - UT_T1_SPIMODE - psram +UT_006_01: + <<: *unit_test_template + tags: + - ESP32_IDF + - UT_T1_GPIO + +UT_006_02: + <<: *unit_test_template + tags: + - ESP32_IDF + - UT_T1_GPIO + +UT_006_03: + <<: *unit_test_template + tags: + - ESP32_IDF + - UT_T1_GPIO + +UT_006_04: + <<: *unit_test_template + tags: + - ESP32_IDF + - UT_T1_GPIO + - psram + IT_001_01: <<: *test_template tags: diff --git a/components/driver/test/test_gpio.c b/components/driver/test/test_gpio.c new file mode 100644 index 000000000..442b5b130 --- /dev/null +++ b/components/driver/test/test_gpio.c @@ -0,0 +1,587 @@ +/** + * About test environment UT_T1_GPIO: + * Please connect GPIO18 and GPIO19 + */ +#include +#include +#include "rom/uart.h" +#include "esp_system.h" +#include "esp_sleep.h" +#include "unity.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +#define GPIO_OUTPUT_IO 18 // default output GPIO +#define GPIO_INPUT_IO 19 // default input GPIO +#define GPIO_OUTPUT_MAX GPIO_NUM_34 +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 +static bool wake_up_result = false; // use this to judge the wake up event happen or not + +/** + * 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) +{ + TEST_ASSERT(num < GPIO_OUTPUT_MAX); + gpio_config_t io_conf; + io_conf.intr_type = GPIO_PIN_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = (1ULL << num); + io_conf.pull_down_en = 0; + io_conf.pull_up_en = 0; + return io_conf; +} + +// edge interrupt event +static void gpio_isr_edge_handler(void* arg) +{ + uint32_t gpio_num = (uint32_t) arg; + ets_printf("GPIO[%d] intr, val: %d\n", gpio_num, gpio_get_level(gpio_num)); + edge_intr_times++; +} + +// level interrupt event with "gpio_intr_disable" +static void gpio_isr_level_handler(void* arg) +{ + uint32_t gpio_num = (uint32_t) arg; + disable_intr_times++; + ets_printf("GPIO[%d] intr, val: %d, disable_intr_times = %d\n", gpio_num, gpio_get_level(gpio_num), disable_intr_times); + gpio_intr_disable(gpio_num); +} + +// level interrupt event +static void gpio_isr_level_handler2(void* arg) +{ + uint32_t gpio_num = (uint32_t) arg; + level_intr_times++; + ets_printf("GPIO[%d] intr, val: %d\n", gpio_num, gpio_get_level(gpio_num)); + if(gpio_get_level(gpio_num)) { + gpio_set_level(GPIO_OUTPUT_IO, 0); + }else{ + gpio_set_level(GPIO_OUTPUT_IO, 1); + } + ets_printf("GPIO[%d] intr, val: %d, level_intr_times = %d\n", GPIO_OUTPUT_IO, gpio_get_level(GPIO_OUTPUT_IO), level_intr_times); + ets_printf("GPIO[%d] intr, val: %d, level_intr_times = %d\n", gpio_num, gpio_get_level(gpio_num), level_intr_times); +} + +// get result of waking up or not +static void sleep_wake_up(void *arg) +{ + gpio_config_t io_config = init_io(GPIO_INPUT_IO); + io_config.mode = GPIO_MODE_INPUT; + gpio_config(&io_config); + TEST_ESP_OK(gpio_wakeup_enable(GPIO_INPUT_IO, GPIO_INTR_HIGH_LEVEL)); + esp_light_sleep_start(); + wake_up_result = true; +} + +// wake up light sleep event +static void trigger_wake_up(void *arg) +{ + gpio_config_t io_config = init_io(GPIO_OUTPUT_IO); + gpio_config(&io_config); + gpio_set_level(GPIO_OUTPUT_IO, 0); + gpio_install_isr_service(0); + gpio_isr_handler_add(GPIO_OUTPUT_IO, gpio_isr_level_handler, (void*) GPIO_INPUT_IO); + gpio_set_level(GPIO_OUTPUT_IO, 1); + vTaskDelay(100 / portTICK_RATE_MS); +} + + +static void prompt_to_continue(const char* str) +{ + printf("%s , please press \"Enter\" to go on!\n", str); + char sign[5] = {0}; + while(strlen(sign) == 0) { + /* Flush anything already in the RX buffer */ + while(uart_rx_one_char((uint8_t *) sign) == OK) { + } + /* Read line */ + UartRxString((uint8_t*) sign, sizeof(sign) - 1); + } +} + +static void drive_capability_set_get(gpio_num_t num, gpio_drive_cap_t capability) +{ + 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 + //test 41 bit + gpio_config_t io_config; + 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); + + //test 40 bit + io_config.pin_bit_mask = ((uint64_t)1< 10) { + break; + } + vTaskDelay(100 / portTICK_RATE_MS); + } + vTaskDelay(100 / portTICK_RATE_MS); + // for falling rdge in GPIO_INTR_ANYEDGE + while(1) { + level = level - 1; + gpio_set_level(GPIO_OUTPUT_IO, level/5); + if(level < 0) { + break; + } + vTaskDelay(100 / portTICK_RATE_MS); + } + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ASSERT_EQUAL_INT(edge_intr_times, 2); + vTaskDelay(100 / portTICK_RATE_MS); + gpio_isr_handler_remove(GPIO_INPUT_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(GPIO_OUTPUT_IO); + gpio_config_t input_io = init_io(GPIO_INPUT_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(GPIO_OUTPUT_IO, 0)); + + gpio_set_intr_type(GPIO_INPUT_IO, GPIO_INTR_HIGH_LEVEL); + gpio_install_isr_service(0); + gpio_isr_handler_add(GPIO_INPUT_IO, gpio_isr_level_handler2, (void*) GPIO_INPUT_IO); + gpio_set_level(GPIO_OUTPUT_IO, 1); + vTaskDelay(100 / portTICK_RATE_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(GPIO_INPUT_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(GPIO_OUTPUT_IO); + gpio_config_t input_io = init_io(GPIO_INPUT_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(GPIO_OUTPUT_IO, 1)); + + gpio_set_intr_type(GPIO_INPUT_IO, GPIO_INTR_LOW_LEVEL); + gpio_install_isr_service(0); + gpio_isr_handler_add(GPIO_INPUT_IO, gpio_isr_level_handler, (void*) GPIO_INPUT_IO); + gpio_set_level(GPIO_OUTPUT_IO, 0); + printf("get level:%d\n",gpio_get_level(GPIO_INPUT_IO)); + vTaskDelay(100 / portTICK_RATE_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(GPIO_INPUT_IO); + gpio_uninstall_isr_service(); +} + +TEST_CASE("GPIO enable and disable interrupt test", "[gpio][test_env=UT_T1_GPIO]") +{ + gpio_config_t output_io = init_io(GPIO_OUTPUT_IO); + gpio_config_t input_io = init_io(GPIO_INPUT_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_intr_type(GPIO_INPUT_IO, GPIO_INTR_HIGH_LEVEL)); + TEST_ESP_OK(gpio_install_isr_service(0)); + TEST_ESP_OK(gpio_isr_handler_add(GPIO_INPUT_IO, gpio_isr_level_handler, (void*) GPIO_INPUT_IO)); + TEST_ESP_OK(gpio_set_level(GPIO_OUTPUT_IO, 1)); + TEST_ESP_OK(gpio_isr_handler_remove(GPIO_INPUT_IO)); + TEST_ESP_OK(gpio_set_level(GPIO_OUTPUT_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_RATE_MS); + TEST_ESP_OK(gpio_intr_disable(GPIO_INPUT_IO)); + TEST_ESP_OK(gpio_set_level(GPIO_OUTPUT_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(GPIO_INPUT_IO, gpio_isr_level_handler, (void*) GPIO_INPUT_IO) == ESP_ERR_INVALID_STATE); + TEST_ASSERT(gpio_isr_handler_remove(GPIO_INPUT_IO) == ESP_ERR_INVALID_STATE); +} + +// Connect GPIO18 with GPIO19 +// use multimeter to test the voltage, so it is ignored in CI +TEST_CASE("GPIO set gpio output level test", "[gpio][ignore]") +{ + gpio_config_t io_conf; + io_conf.intr_type = GPIO_PIN_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = (1<