2021-05-23 19:06:17 -04:00
/*
2022-01-17 21:32:56 -05:00
* SPDX - FileCopyrightText : 2021 - 2022 Espressif Systems ( Shanghai ) CO LTD
2021-05-23 19:06:17 -04:00
*
* SPDX - License - Identifier : Apache - 2.0
*/
2022-03-14 07:27:21 -04:00
2017-12-16 21:19:51 -05:00
/**
2022-03-09 01:37:41 -05:00
* 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
2017-12-16 21:19:51 -05:00
*/
2022-03-09 01:37:41 -05:00
2017-12-16 21:19:51 -05:00
# include <stdio.h>
# include <string.h>
2022-03-09 01:37:41 -05:00
# include "test_gpio.h"
2017-12-16 21:19:51 -05:00
# include "esp_system.h"
# include "esp_sleep.h"
# include "unity.h"
2022-03-09 01:37:41 -05:00
# include "unity_test_utils.h"
2017-12-16 21:19:51 -05:00
# include "driver/gpio.h"
2022-03-09 01:37:41 -05:00
# include "hal/gpio_ll.h"
# include "soc/gpio_periph.h"
2017-12-16 21:19:51 -05:00
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
# include "freertos/queue.h"
2022-03-09 01:37:41 -05:00
# include "freertos/semphr.h"
2019-08-06 05:59:26 -04:00
# include "sdkconfig.h"
2020-07-13 09:33:23 -04:00
# include "esp_rom_uart.h"
2020-07-21 01:07:34 -04:00
# include "esp_rom_sys.h"
2022-03-09 01:37:41 -05:00
# include "esp_spi_flash.h"
# include "esp_attr.h"
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
// Enable internal routing for the output and input gpio pins
# define TEST_GPIO_INTERNAL_ROUTING 1
2020-02-25 04:41:50 -05:00
2021-06-09 05:18:39 -04:00
// 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)
2017-12-16 21:19:51 -05:00
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
2020-02-25 04:41:50 -05:00
2017-12-16 21:19:51 -05:00
/**
2022-03-09 01:37:41 -05:00
* Do some initialization operation in this function
* @ param num it is the destination GPIO wanted to be initialized
2017-12-16 21:19:51 -05:00
*/
2022-03-09 01:37:41 -05:00
static gpio_config_t test_init_io ( gpio_num_t num )
2017-12-16 21:19:51 -05:00
{
2022-03-09 01:37:41 -05:00
TEST_ASSERT ( GPIO_IS_VALID_OUTPUT_GPIO ( num ) ) ;
2021-10-26 23:56:56 -04:00
gpio_config_t io_conf = {
. intr_type = GPIO_INTR_DISABLE ,
. mode = GPIO_MODE_OUTPUT ,
. pin_bit_mask = ( 1ULL < < num ) ,
. pull_down_en = 0 ,
. pull_up_en = 0 ,
} ;
2017-12-16 21:19:51 -05:00
return io_conf ;
}
2022-03-09 01:37:41 -05:00
/**
* 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 )
2017-12-16 21:19:51 -05:00
{
2022-03-09 01:37:41 -05:00
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 ) ) ;
2017-12-16 21:19:51 -05:00
}
// test the basic configuration function with right parameters and error parameters
2022-03-14 07:27:21 -04:00
TEST_CASE ( " GPIO_config_parameters_test " , " [gpio] " )
2017-12-16 21:19:51 -05:00
{
2020-10-14 01:06:54 -04:00
gpio_config_t io_config = { 0 } ;
2020-06-19 00:00:58 -04:00
io_config . intr_type = GPIO_INTR_DISABLE ;
2017-12-16 21:19:51 -05:00
// test 0
io_config . pin_bit_mask = 0 ;
TEST_ASSERT ( gpio_config ( & io_config ) = = ESP_ERR_INVALID_ARG ) ;
2022-03-09 01:37:41 -05:00
// test a non-exist pin
2021-06-09 05:18:39 -04:00
io_config . pin_bit_mask = ( ( uint64_t ) 1 < < GPIO_NUM_MAX ) ;
2017-12-16 21:19:51 -05:00
TEST_ASSERT ( gpio_config ( & io_config ) = = ESP_ERR_INVALID_ARG ) ;
2022-03-09 01:37:41 -05:00
// test an available pin
io_config . pin_bit_mask = ( ( uint64_t ) 1 < < TEST_GPIO_EXT_OUT_IO ) ;
2017-12-16 21:19:51 -05:00
TEST_ESP_OK ( gpio_config ( & io_config ) ) ;
2021-06-09 05:18:39 -04:00
//This IO is just used for input, C3 and S3 doesn't have input only pin.
# if SOC_HAS_INPUT_ONLY_PIN
2020-02-25 04:41:50 -05:00
io_config . pin_bit_mask = ( ( uint64_t ) 1 < < TEST_GPIO_INPUT_ONLY_PIN ) ;
2017-12-16 21:19:51 -05:00
io_config . mode = GPIO_MODE_INPUT ;
TEST_ESP_OK ( gpio_config ( & io_config ) ) ;
io_config . mode = GPIO_MODE_OUTPUT ;
2020-02-25 04:41:50 -05:00
// The pin is input only, once set as output should log something
2019-11-26 07:00:24 -05:00
TEST_ASSERT ( gpio_config ( & io_config ) = = ESP_ERR_INVALID_ARG ) ;
2021-06-09 05:18:39 -04:00
# endif // SOC_HAS_INPUT_ONLY_PIN
2017-12-16 21:19:51 -05:00
}
2022-03-09 01:37:41 -05:00
// edge interrupt event
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 + + ;
}
// 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 + + ;
esp_rom_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 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, level_intr_times = %d \n " , gpio_num , gpio_get_level ( gpio_num ) , level_intr_times ) ;
if ( gpio_get_level ( gpio_num ) ) {
gpio_set_level ( gpio_num , 0 ) ;
} else {
gpio_set_level ( gpio_num , 1 ) ;
}
}
TEST_CASE ( " GPIO_rising_edge_interrupt_test " , " [gpio] " )
2017-12-16 21:19:51 -05:00
{
edge_intr_times = 0 ; // set it as 0 prepare to test
2022-03-09 01:37:41 -05:00
test_gpio_config_mode_input_output ( TEST_GPIO_INPUT_OUTPUT_IO1 ) ;
TEST_ESP_OK ( gpio_set_level ( TEST_GPIO_INPUT_OUTPUT_IO1 , 0 ) ) ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
// Rising edge intr
TEST_ESP_OK ( gpio_set_intr_type ( TEST_GPIO_INPUT_OUTPUT_IO1 , GPIO_INTR_POSEDGE ) ) ;
2017-12-16 21:19:51 -05:00
TEST_ESP_OK ( gpio_install_isr_service ( 0 ) ) ;
2022-03-09 01:37:41 -05:00
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 ) ) ;
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT ( 1 , edge_intr_times ) ;
gpio_isr_handler_remove ( TEST_GPIO_INPUT_OUTPUT_IO1 ) ;
2017-12-16 21:19:51 -05:00
gpio_uninstall_isr_service ( ) ;
}
2022-03-09 01:37:41 -05:00
TEST_CASE ( " GPIO_falling_edge_interrupt_test " , " [gpio] " )
2017-12-16 21:19:51 -05:00
{
edge_intr_times = 0 ;
2022-03-09 01:37:41 -05:00
test_gpio_config_mode_input_output ( TEST_GPIO_INPUT_OUTPUT_IO1 ) ;
TEST_ESP_OK ( gpio_set_level ( TEST_GPIO_INPUT_OUTPUT_IO1 , 1 ) ) ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
gpio_set_intr_type ( TEST_GPIO_INPUT_OUTPUT_IO1 , GPIO_INTR_NEGEDGE ) ;
2017-12-16 21:19:51 -05:00
gpio_install_isr_service ( 0 ) ;
2022-03-09 01:37:41 -05:00
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 ) ;
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT ( 1 , edge_intr_times ) ;
gpio_isr_handler_remove ( TEST_GPIO_INPUT_OUTPUT_IO1 ) ;
2017-12-16 21:19:51 -05:00
gpio_uninstall_isr_service ( ) ;
}
2022-03-09 01:37:41 -05:00
TEST_CASE ( " GPIO_both_rising_and_falling_edge_interrupt_test " , " [gpio] " )
2017-12-16 21:19:51 -05:00
{
edge_intr_times = 0 ;
2022-03-09 01:37:41 -05:00
test_gpio_config_mode_input_output ( TEST_GPIO_INPUT_OUTPUT_IO1 ) ;
TEST_ESP_OK ( gpio_set_level ( TEST_GPIO_INPUT_OUTPUT_IO1 , 0 ) ) ;
2017-12-16 21:19:51 -05:00
int level = 0 ;
2022-03-09 01:37:41 -05:00
gpio_set_intr_type ( TEST_GPIO_INPUT_OUTPUT_IO1 , GPIO_INTR_ANYEDGE ) ;
2017-12-16 21:19:51 -05:00
gpio_install_isr_service ( 0 ) ;
2022-03-09 01:37:41 -05:00
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
2021-06-09 05:18:39 -04:00
while ( 1 ) {
2017-12-16 21:19:51 -05:00
level = level + 1 ;
2022-03-09 01:37:41 -05:00
gpio_set_level ( TEST_GPIO_INPUT_OUTPUT_IO1 , level * 0.2 ) ;
2021-06-09 05:18:39 -04:00
if ( level > 10 ) {
2017-12-16 21:19:51 -05:00
break ;
}
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2017-12-16 21:19:51 -05:00
}
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
// For falling edge in GPIO_INTR_ANYEDGE
2021-06-09 05:18:39 -04:00
while ( 1 ) {
2017-12-16 21:19:51 -05:00
level = level - 1 ;
2022-03-09 01:37:41 -05:00
gpio_set_level ( TEST_GPIO_INPUT_OUTPUT_IO1 , level / 5 ) ;
2021-06-09 05:18:39 -04:00
if ( level < 0 ) {
2017-12-16 21:19:51 -05:00
break ;
}
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2017-12-16 21:19:51 -05:00
}
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT ( 2 , edge_intr_times ) ;
gpio_isr_handler_remove ( TEST_GPIO_INPUT_OUTPUT_IO1 ) ;
2017-12-16 21:19:51 -05:00
gpio_uninstall_isr_service ( ) ;
}
2022-03-09 01:37:41 -05:00
TEST_CASE ( " GPIO_input_high_level_trigger_cut_the_interrupt_source_exit_interrupt_test " , " [gpio] " )
2017-12-16 21:19:51 -05:00
{
2021-06-09 05:18:39 -04:00
level_intr_times = 0 ;
2022-03-09 01:37:41 -05:00
test_gpio_config_mode_input_output ( TEST_GPIO_INPUT_OUTPUT_IO1 ) ;
TEST_ESP_OK ( gpio_set_level ( TEST_GPIO_INPUT_OUTPUT_IO1 , 0 ) ) ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
gpio_set_intr_type ( TEST_GPIO_INPUT_OUTPUT_IO1 , GPIO_INTR_HIGH_LEVEL ) ;
2017-12-16 21:19:51 -05:00
gpio_install_isr_service ( 0 ) ;
2022-03-09 01:37:41 -05:00
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 ) ;
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
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 ) ;
2017-12-16 21:19:51 -05:00
gpio_uninstall_isr_service ( ) ;
}
2022-03-09 01:37:41 -05:00
TEST_CASE ( " GPIO_low_level_interrupt_test " , " [gpio] " )
2017-12-16 21:19:51 -05:00
{
2021-06-09 05:18:39 -04:00
disable_intr_times = 0 ;
2022-03-09 01:37:41 -05:00
test_gpio_config_mode_input_output ( TEST_GPIO_INPUT_OUTPUT_IO1 ) ;
TEST_ESP_OK ( gpio_set_level ( TEST_GPIO_INPUT_OUTPUT_IO1 , 1 ) ) ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
gpio_set_intr_type ( TEST_GPIO_INPUT_OUTPUT_IO1 , GPIO_INTR_LOW_LEVEL ) ;
2017-12-16 21:19:51 -05:00
gpio_install_isr_service ( 0 ) ;
2022-03-09 01:37:41 -05:00
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 ) ) ;
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
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 ) ;
2017-12-16 21:19:51 -05:00
gpio_uninstall_isr_service ( ) ;
}
2022-03-09 01:37:41 -05:00
TEST_CASE ( " GPIO_multi-level_trigger_cut_the_interrupt_source_exit_interrupt_test " , " [gpio] " )
2018-09-05 23:47:17 -04:00
{
2021-06-09 05:18:39 -04:00
level_intr_times = 0 ;
2022-03-09 01:37:41 -05:00
test_gpio_config_mode_input_output ( TEST_GPIO_INPUT_OUTPUT_IO1 ) ;
TEST_ESP_OK ( gpio_set_level ( TEST_GPIO_INPUT_OUTPUT_IO1 , 0 ) ) ;
2018-09-05 23:47:17 -04:00
2022-03-09 01:37:41 -05:00
gpio_set_intr_type ( TEST_GPIO_INPUT_OUTPUT_IO1 , GPIO_INTR_HIGH_LEVEL ) ;
2018-09-05 23:47:17 -04:00
gpio_install_isr_service ( 0 ) ;
2022-03-09 01:37:41 -05:00
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 ) ;
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
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 ) ;
2022-02-08 04:39:38 -05:00
vTaskDelay ( 200 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
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 ) ;
2018-09-05 23:47:17 -04:00
gpio_uninstall_isr_service ( ) ;
}
2022-03-09 01:37:41 -05:00
TEST_CASE ( " GPIO_enable_and_disable_interrupt_test " , " [gpio] " )
2017-12-16 21:19:51 -05:00
{
2019-11-26 07:00:24 -05:00
disable_intr_times = 0 ;
2022-03-09 01:37:41 -05:00
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 + + ;
}
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
/** 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 ) ) ;
2017-12-16 21:19:51 -05:00
TEST_ESP_OK ( gpio_install_isr_service ( 0 ) ) ;
2022-03-09 01:37:41 -05:00
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 ) ) ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
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 ) ) ;
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
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 ) ) ;
2017-12-16 21:19:51 -05:00
}
2021-11-14 23:11:40 -05:00
# if !CONFIG_FREERTOS_UNICORE
2022-03-09 01:37:41 -05:00
# include "esp_ipc.h"
2021-11-14 23:11:40 -05:00
static void install_isr_service_task ( void * arg )
{
uint32_t gpio_num = ( uint32_t ) arg ;
2022-03-09 01:37:41 -05:00
// Rising edge intr
2021-11-14 23:11:40 -05:00
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 ) ;
}
2022-03-14 07:27:21 -04:00
TEST_CASE ( " GPIO_interrupt_on_other_CPUs_test " , " [gpio] " )
2021-11-14 23:11:40 -05:00
{
TaskHandle_t gpio_task_handle ;
2022-03-09 01:37:41 -05:00
test_gpio_config_mode_input_output ( TEST_GPIO_INPUT_OUTPUT_IO1 ) ;
2021-11-14 23:11:40 -05:00
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 ;
2022-03-09 01:37:41 -05:00
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 ) ;
2021-11-14 23:11:40 -05:00
2022-02-08 04:39:38 -05:00
vTaskDelay ( 200 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
TEST_ESP_OK ( gpio_set_level ( TEST_GPIO_INPUT_OUTPUT_IO1 , 1 ) ) ;
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT ( 1 , edge_intr_times ) ;
gpio_isr_handler_remove ( TEST_GPIO_INPUT_OUTPUT_IO1 ) ;
2021-11-14 23:11:40 -05:00
gpio_uninstall_isr_service ( ) ;
2022-03-14 07:00:59 -04:00
unity_utils_task_delete ( gpio_task_handle ) ;
2021-11-14 23:11:40 -05:00
}
}
2022-03-09 01:37:41 -05:00
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 ) ;
}
2021-11-14 23:11:40 -05:00
# endif //!CONFIG_FREERTOS_UNICORE
2022-03-09 01:37:41 -05:00
# if CONFIG_GPIO_CTRL_FUNC_IN_IRAM
static volatile DRAM_ATTR bool isr_triggered = false ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
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
2017-12-16 21:19:51 -05:00
2020-02-25 04:41:50 -05:00
gpio_set_level ( TEST_GPIO_EXT_OUT_IO , 0 ) ;
2022-03-09 01:37:41 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2017-12-16 21:19:51 -05:00
// tested voltage is around 0v
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 0 , gpio_get_level ( TEST_GPIO_EXT_IN_IO ) , " get level error! the level should be low! " ) ;
2020-02-25 04:41:50 -05:00
gpio_set_level ( TEST_GPIO_EXT_OUT_IO , 1 ) ;
2022-03-09 01:37:41 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2017-12-16 21:19:51 -05:00
// tested voltage is around 3.3v
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 1 , gpio_get_level ( TEST_GPIO_EXT_IN_IO ) , " get level error! the level should be high! " ) ;
2017-12-16 21:19:51 -05:00
}
2022-03-09 01:37:41 -05:00
// 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] " )
2017-12-16 21:19:51 -05:00
{
2022-03-09 01:37:41 -05:00
# 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! " ) ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
// 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! " ) ;
2017-12-16 21:19:51 -05:00
}
2022-03-14 07:27:21 -04:00
TEST_CASE ( " GPIO_io_pull_up/down_function " , " [gpio] " )
2017-12-16 21:19:51 -05:00
{
2019-11-26 07:00:24 -05:00
// First, ensure that the output IO will not affect the level
2022-03-09 01:37:41 -05:00
gpio_config_t io_conf = test_init_io ( TEST_GPIO_EXT_OUT_IO ) ;
2019-11-26 07:00:24 -05:00
gpio_config ( & io_conf ) ;
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_INPUT ) ;
2022-03-09 01:37:41 -05:00
io_conf = test_init_io ( TEST_GPIO_EXT_IN_IO ) ;
2017-12-16 21:19:51 -05:00
gpio_config ( & io_conf ) ;
2020-02-25 04:41:50 -05:00
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
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 1 , gpio_get_level ( TEST_GPIO_EXT_IN_IO ) , " gpio_pullup_en error, it can't pull up " ) ;
2020-02-25 04:41:50 -05:00
TEST_ESP_OK ( gpio_pulldown_dis ( TEST_GPIO_EXT_IN_IO ) ) ; //can't be pull down
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 1 , gpio_get_level ( TEST_GPIO_EXT_IN_IO ) , " gpio_pulldown_dis error, it can pull down " ) ;
2020-02-25 04:41:50 -05:00
TEST_ESP_OK ( gpio_pulldown_en ( TEST_GPIO_EXT_IN_IO ) ) ; // can be pull down now
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 0 , gpio_get_level ( TEST_GPIO_EXT_IN_IO ) , " gpio_pulldown_en error, it can't pull down " ) ;
2020-02-25 04:41:50 -05:00
TEST_ESP_OK ( gpio_pullup_dis ( TEST_GPIO_EXT_IN_IO ) ) ; // can't be pull up
2022-02-08 04:39:38 -05:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 0 , gpio_get_level ( TEST_GPIO_EXT_IN_IO ) , " gpio_pullup_dis error, it can pull up " ) ;
2017-12-16 21:19:51 -05:00
}
2022-03-09 01:37:41 -05:00
// This test case tests whether gpio_set_level() outputs correctly with all gpio modes (gpio_mode_t)
TEST_CASE ( " GPIO_mode_test " , " [gpio] " )
2017-12-16 21:19:51 -05:00
{
2022-03-09 01:37:41 -05:00
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 ) ;
2017-12-16 21:19:51 -05:00
gpio_config ( & output_io ) ;
gpio_config ( & input_io ) ;
2020-02-25 04:41:50 -05:00
int level = gpio_get_level ( TEST_GPIO_EXT_IN_IO ) ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
// Disable mode
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_DISABLE ) ;
gpio_set_direction ( TEST_GPIO_EXT_IN_IO , GPIO_MODE_OUTPUT ) ;
2022-03-09 01:37:41 -05:00
# 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
2020-02-25 04:41:50 -05:00
gpio_set_level ( TEST_GPIO_EXT_OUT_IO , ! level ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( level , gpio_get_level ( TEST_GPIO_EXT_IN_IO ) , " direction GPIO_MODE_DISABLE set error, it can output " ) ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
// Output mode
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_OUTPUT ) ;
gpio_set_direction ( TEST_GPIO_EXT_IN_IO , GPIO_MODE_INPUT ) ;
2022-03-09 01:37:41 -05:00
# 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
2020-02-25 04:41:50 -05:00
gpio_set_level ( TEST_GPIO_EXT_OUT_IO , 1 ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 1 , gpio_get_level ( TEST_GPIO_EXT_IN_IO ) , " direction GPIO_MODE_OUTPUT set error, it can't output " ) ;
2020-02-25 04:41:50 -05:00
gpio_set_level ( TEST_GPIO_EXT_OUT_IO , 0 ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 0 , gpio_get_level ( TEST_GPIO_EXT_IN_IO ) , " direction GPIO_MODE_OUTPUT set error, it can't output " ) ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
// Open drain mode(output), can just output low level
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_OUTPUT_OD ) ;
gpio_set_direction ( TEST_GPIO_EXT_IN_IO , GPIO_MODE_INPUT ) ;
2022-03-09 01:37:41 -05:00
# 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
2020-02-25 04:41:50 -05:00
gpio_set_level ( TEST_GPIO_EXT_OUT_IO , 1 ) ;
2022-03-09 01:37:41 -05:00
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
2020-02-25 04:41:50 -05:00
gpio_set_level ( TEST_GPIO_EXT_OUT_IO , 0 ) ;
2022-03-09 01:37:41 -05:00
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 " ) ;
2017-12-16 21:19:51 -05:00
2022-03-09 01:37:41 -05:00
// Open drain mode(output and input), can just output low level
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_INPUT_OUTPUT_OD ) ;
gpio_set_direction ( TEST_GPIO_EXT_IN_IO , GPIO_MODE_INPUT ) ;
2022-03-09 01:37:41 -05:00
# 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
2020-02-25 04:41:50 -05:00
gpio_set_level ( TEST_GPIO_EXT_OUT_IO , 1 ) ;
2022-03-09 01:37:41 -05:00
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
2020-02-25 04:41:50 -05:00
gpio_set_level ( TEST_GPIO_EXT_OUT_IO , 0 ) ;
2022-03-09 01:37:41 -05:00
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 " ) ;
2017-12-16 21:19:51 -05:00
// GPIO_MODE_INPUT_OUTPUT mode
2020-02-25 04:41:50 -05:00
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 ) ;
2022-03-09 01:37:41 -05:00
# 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
2020-02-25 04:41:50 -05:00
gpio_set_level ( TEST_GPIO_EXT_OUT_IO , ! level ) ;
2022-03-09 01:37:41 -05:00
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 " ) ;
2017-12-16 21:19:51 -05:00
}
2022-03-09 01:37:41 -05:00
static void prompt_to_continue ( const char * str )
2017-12-16 21:19:51 -05:00
{
2022-03-09 01:37:41 -05:00
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 ( esp_rom_uart_rx_one_char ( ( uint8_t * ) sign ) = = 0 ) {
}
/* Read line */
esp_rom_uart_rx_string ( ( uint8_t * ) sign , sizeof ( sign ) - 1 ) ;
2017-12-16 21:19:51 -05:00
}
}
2022-03-09 01:37:41 -05:00
// 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] " )
2017-12-16 21:19:51 -05:00
{
2022-03-09 01:37:41 -05:00
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 ) ;
2017-12-16 21:19:51 -05:00
gpio_config ( & output_io ) ;
input_io . mode = GPIO_MODE_INPUT ;
gpio_config ( & input_io ) ;
printf ( " pull up test! \n " ) ;
// pull up test
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_OUTPUT ) ;
TEST_ESP_OK ( gpio_set_pull_mode ( TEST_GPIO_EXT_OUT_IO , GPIO_PULLUP_ONLY ) ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " mode: GPIO_MODE_OUTPUT " ) ;
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_OUTPUT_OD ) ;
TEST_ESP_OK ( gpio_set_pull_mode ( TEST_GPIO_EXT_OUT_IO , GPIO_PULLUP_ONLY ) ) ;
2017-12-16 21:19:51 -05:00
// open drain just can output low level
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_INPUT_OUTPUT_OD ) ;
TEST_ESP_OK ( gpio_set_pull_mode ( TEST_GPIO_EXT_OUT_IO , GPIO_PULLUP_ONLY ) ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " mode: GPIO_MODE_OUTPUT_OD " ) ;
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_INPUT_OUTPUT ) ;
TEST_ESP_OK ( gpio_set_pull_mode ( TEST_GPIO_EXT_OUT_IO , GPIO_PULLUP_ONLY ) ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " mode: GPIO_MODE_INPUT_OUTPUT " ) ;
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_INPUT ) ;
TEST_ESP_OK ( gpio_set_pull_mode ( TEST_GPIO_EXT_OUT_IO , GPIO_PULLUP_ONLY ) ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " mode: GPIO_MODE_INPUT " ) ;
// after pull up the level is high now
// pull down test
printf ( " pull down test! \n " ) ;
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_OUTPUT ) ;
TEST_ESP_OK ( gpio_set_pull_mode ( TEST_GPIO_EXT_OUT_IO , GPIO_PULLDOWN_ONLY ) ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " mode: GPIO_MODE_OUTPUT " ) ;
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_OUTPUT_OD ) ;
TEST_ESP_OK ( gpio_set_pull_mode ( TEST_GPIO_EXT_OUT_IO , GPIO_PULLDOWN_ONLY ) ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " mode: GPIO_MODE_OUTPUT_OD " ) ;
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_INPUT_OUTPUT_OD ) ;
TEST_ESP_OK ( gpio_set_pull_mode ( TEST_GPIO_EXT_OUT_IO , GPIO_PULLDOWN_ONLY ) ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " mode: GPIO_MODE_INPUT_OUTPUT_OD " ) ;
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_INPUT_OUTPUT ) ;
TEST_ESP_OK ( gpio_set_pull_mode ( TEST_GPIO_EXT_OUT_IO , GPIO_PULLDOWN_ONLY ) ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " mode: GPIO_MODE_INPUT_OUTPUT " ) ;
2020-02-25 04:41:50 -05:00
gpio_set_direction ( TEST_GPIO_EXT_OUT_IO , GPIO_MODE_INPUT ) ;
TEST_ESP_OK ( gpio_set_pull_mode ( TEST_GPIO_EXT_OUT_IO , GPIO_PULLDOWN_ONLY ) ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " mode: GPIO_MODE_INPUT " ) ;
}
2022-03-09 01:37:41 -05:00
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 ) ;
}
2017-12-16 21:19:51 -05:00
/**
* There are 5 situation for the GPIO drive capability :
* 1. GPIO drive weak capability test
* 2. GPIO drive stronger capability test
* 3. GPIO drive default capability test
* 4. GPIO drive default capability test2
* 5. GPIO drive strongest capability test
*
* How to test :
* when testing , use the sliding resistor and a multimeter
* adjust the resistor from low to high , 0 - 10 k
* watch the current change
* the current test result :
* weak capability : ( 0.32 - 10.1 ) mA
* stronger capability : ( 0.32 - 20.0 ) mA
* default capability : ( 0.33 - 39.8 ) mA
* default capability2 : ( 0.33 - 39.9 ) mA
* strongest capability : ( 0.33 - 64.2 ) mA
*
* the data shows :
2022-03-09 01:37:41 -05:00
* weak capability < stronger capability < default capability = default capability2 < strongest capability
2017-12-16 21:19:51 -05:00
*
* all of these cases should be ignored that it will not run in CI
*/
2022-03-09 01:37:41 -05:00
TEST_CASE_CI_IGNORE ( " GPIO_drive_capability_test " , " [gpio] " )
2017-12-16 21:19:51 -05:00
{
printf ( " weak capability test! please view the current change! \n " ) ;
2020-02-25 04:41:50 -05:00
drive_capability_set_get ( TEST_GPIO_EXT_OUT_IO , GPIO_DRIVE_CAP_0 ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " If this test finishes " ) ;
printf ( " stronger capability test! please view the current change! \n " ) ;
2020-02-25 04:41:50 -05:00
drive_capability_set_get ( TEST_GPIO_EXT_OUT_IO , GPIO_DRIVE_CAP_1 ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " If this test finishes " ) ;
printf ( " default capability test! please view the current change! \n " ) ;
2020-02-25 04:41:50 -05:00
drive_capability_set_get ( TEST_GPIO_EXT_OUT_IO , GPIO_DRIVE_CAP_2 ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " If this test finishes " ) ;
printf ( " default capability2 test! please view the current change! \n " ) ;
2020-02-25 04:41:50 -05:00
drive_capability_set_get ( TEST_GPIO_EXT_OUT_IO , GPIO_DRIVE_CAP_DEFAULT ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " If this test finishes " ) ;
printf ( " strongest capability test! please view the current change! \n " ) ;
2020-02-25 04:41:50 -05:00
drive_capability_set_get ( TEST_GPIO_EXT_OUT_IO , GPIO_DRIVE_CAP_3 ) ;
2017-12-16 21:19:51 -05:00
prompt_to_continue ( " If this test finishes " ) ;
}
2019-07-17 23:34:49 -04:00
2021-12-30 07:31:38 -05:00
# if SOC_USB_SERIAL_JTAG_SUPPORTED
2022-03-14 07:27:21 -04:00
TEST_CASE ( " GPIO_input_and_output_of_USB_pins_test " , " [gpio] " )
2021-06-09 05:18:39 -04:00
{
2022-03-09 01:37:41 -05:00
const int test_pins [ ] = { USB_DM_GPIO_NUM , USB_DM_GPIO_NUM } ;
2021-06-09 05:18:39 -04:00
gpio_config_t io_conf = {
. intr_type = GPIO_INTR_DISABLE ,
. mode = GPIO_MODE_INPUT_OUTPUT ,
. pin_bit_mask = ( BIT64 ( test_pins [ 0 ] ) | BIT64 ( test_pins [ 1 ] ) ) ,
. pull_down_en = 0 ,
. pull_up_en = 0 ,
} ;
gpio_config ( & io_conf ) ;
for ( int i = 0 ; i < sizeof ( test_pins ) / sizeof ( int ) ; i + + ) {
int pin = test_pins [ i ] ;
// test pin
gpio_set_level ( pin , 0 ) ;
// tested voltage is around 0v
2021-07-12 07:07:13 -04:00
esp_rom_delay_us ( 10 ) ;
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 0 , gpio_get_level ( pin ) , " get level error! the level should be low! " ) ;
2021-06-09 05:18:39 -04:00
gpio_set_level ( pin , 1 ) ;
2021-07-12 07:07:13 -04:00
esp_rom_delay_us ( 10 ) ;
2021-06-09 05:18:39 -04:00
// tested voltage is around 3.3v
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 1 , gpio_get_level ( pin ) , " get level error! the level should be high! " ) ;
2021-06-09 05:18:39 -04:00
gpio_set_level ( pin , 0 ) ;
2021-07-12 07:07:13 -04:00
esp_rom_delay_us ( 10 ) ;
2021-06-09 05:18:39 -04:00
// tested voltage is around 0v
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 0 , gpio_get_level ( pin ) , " get level error! the level should be low! " ) ;
2021-06-09 05:18:39 -04:00
gpio_set_level ( pin , 1 ) ;
2021-07-12 07:07:13 -04:00
esp_rom_delay_us ( 10 ) ;
2021-06-09 05:18:39 -04:00
// tested voltage is around 3.3v
2022-03-09 01:37:41 -05:00
TEST_ASSERT_EQUAL_INT_MESSAGE ( 1 , gpio_get_level ( pin ) , " get level error! the level should be high! " ) ;
2021-06-09 05:18:39 -04:00
}
}
2021-12-30 07:31:38 -05:00
# endif //SOC_USB_SERIAL_JTAG_SUPPORTED
2022-03-09 01:37:41 -05:00
// 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 ) ;
}