mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-05 21:54:33 +02:00
Merge branch 'refactor/gpio_unit_test' into 'master'
gpio: Clean up unit tests and enable ci ut on some previously disabled test cases Closes IDF-4620 See merge request espressif/esp-idf!17417
This commit is contained in:
@@ -176,6 +176,8 @@ before_script:
|
||||
scapy
|
||||
google-api-python-client
|
||||
- cd $IDF_PATH
|
||||
- export EXTRA_CFLAGS=${PEDANTIC_CFLAGS}
|
||||
- export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS}
|
||||
|
||||
default:
|
||||
retry:
|
||||
|
@@ -186,6 +186,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"
|
||||
|
@@ -90,6 +90,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
|
||||
@@ -102,6 +104,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
|
||||
*
|
||||
|
@@ -17,3 +17,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)
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include "test_utils.h"
|
||||
#include "esp_adc_cal.h"
|
||||
#include "driver/adc_common.h"
|
||||
#include "esp_cpu.h"
|
||||
|
||||
__attribute__((unused)) static const char *TAG = "ADC";
|
||||
|
||||
|
@@ -1,897 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/**
|
||||
* About test environment UT_T1_GPIO:
|
||||
* Please connect TEST_GPIO_EXT_OUT_IO and TEST_GPIO_EXT_IN_IO
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.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"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_rom_uart.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "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
|
||||
|
||||
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
|
||||
*
|
||||
*/
|
||||
static gpio_config_t init_io(gpio_num_t num)
|
||||
{
|
||||
TEST_ASSERT(num < TEST_GPIO_OUTPUT_MAX);
|
||||
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,
|
||||
};
|
||||
return io_conf;
|
||||
}
|
||||
|
||||
// edge interrupt event
|
||||
__attribute__((unused)) 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)
|
||||
{
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
// wake up light sleep event
|
||||
static void trigger_wake_up(void *arg)
|
||||
{
|
||||
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);
|
||||
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_set_level(TEST_GPIO_EXT_OUT_IO, 1);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
#endif //!WAKE_UP_IGNORE
|
||||
|
||||
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 (esp_rom_uart_rx_one_char((uint8_t *) sign) == 0) {
|
||||
}
|
||||
/* Read line */
|
||||
esp_rom_uart_rx_string((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
|
||||
//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();
|
||||
test_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 repeate 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 disenable 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(&output_io);
|
||||
input_io.mode = GPIO_MODE_INPUT;
|
||||
gpio_config(&input_io);
|
||||
|
||||
printf("pull up test!\n");
|
||||
// pull up test
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_OUTPUT");
|
||||
|
||||
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));
|
||||
|
||||
// open drain just can output low level
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_OUTPUT_OD");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_INPUT_OUTPUT");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_INPUT");
|
||||
|
||||
// after pull up the level is high now
|
||||
// pull down test
|
||||
printf("pull down test!\n");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_OUTPUT");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_OUTPUT_OD");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_INPUT_OUTPUT_OD");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_INPUT_OUTPUT");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_INPUT");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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-10k
|
||||
* 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:
|
||||
* weak capability<stronger capability<default capability=default capability2<strongest capability
|
||||
*
|
||||
* all of these cases should be ignored that it will not run in CI
|
||||
*/
|
||||
|
||||
// drive capability test
|
||||
TEST_CASE("GPIO drive capability test", "[gpio][ignore]")
|
||||
{
|
||||
printf("weak capability test! please view the current change!\n");
|
||||
drive_capability_set_get(TEST_GPIO_EXT_OUT_IO, GPIO_DRIVE_CAP_0);
|
||||
prompt_to_continue("If this test finishes");
|
||||
|
||||
printf("stronger capability test! please view the current change!\n");
|
||||
drive_capability_set_get(TEST_GPIO_EXT_OUT_IO, GPIO_DRIVE_CAP_1);
|
||||
prompt_to_continue("If this test finishes");
|
||||
|
||||
printf("default capability test! please view the current change!\n");
|
||||
drive_capability_set_get(TEST_GPIO_EXT_OUT_IO, GPIO_DRIVE_CAP_2);
|
||||
prompt_to_continue("If this test finishes");
|
||||
|
||||
printf("default capability2 test! please view the current change!\n");
|
||||
drive_capability_set_get(TEST_GPIO_EXT_OUT_IO, GPIO_DRIVE_CAP_DEFAULT);
|
||||
prompt_to_continue("If this test finishes");
|
||||
|
||||
printf("strongest capability test! please view the current change!\n");
|
||||
drive_capability_set_get(TEST_GPIO_EXT_OUT_IO, GPIO_DRIVE_CAP_3);
|
||||
prompt_to_continue("If this test finishes");
|
||||
}
|
||||
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
void gpio_enable_task(void *param)
|
||||
{
|
||||
int gpio_num = (int)param;
|
||||
TEST_ESP_OK(gpio_intr_enable(gpio_num));
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/** 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.
|
||||
* First on the core 0, Do the following steps:
|
||||
* 1. Configure the GPIO9 input_output mode, and enable the rising edge interrupt mode.
|
||||
* 2. Trigger the GPIO9 interrupt and check if the interrupt responds correctly.
|
||||
* 3. Disable the GPIO9 interrupt
|
||||
* Then on the core 1, Do the following steps:
|
||||
* 1. Enable the GPIO9 interrupt again.
|
||||
* 2. Trigger the GPIO9 interrupt and check if the interrupt responds correctly.
|
||||
*
|
||||
*/
|
||||
TEST_CASE("GPIO Enable/Disable interrupt on multiple cores", "[gpio][ignore]")
|
||||
{
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = GPIO_INTR_NEGEDGE;
|
||||
io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << TEST_IO_9);
|
||||
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_install_isr_service(0));
|
||||
TEST_ESP_OK(gpio_isr_handler_add(TEST_IO_9, gpio_isr_edge_handler, (void *) TEST_IO_9));
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
TEST_ESP_OK(gpio_set_level(TEST_IO_9, 1));
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
TEST_ESP_OK(gpio_set_level(TEST_IO_9, 0));
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
TEST_ESP_OK(gpio_intr_disable(TEST_IO_9));
|
||||
TEST_ASSERT(edge_intr_times == 1);
|
||||
xTaskCreatePinnedToCore(gpio_enable_task, "gpio_enable_task", 1024 * 4, (void *)TEST_IO_9, 8, NULL, (xPortGetCoreID() == 0));
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
TEST_ESP_OK(gpio_set_level(TEST_IO_9, 1));
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
TEST_ESP_OK(gpio_set_level(TEST_IO_9, 0));
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
TEST_ESP_OK(gpio_intr_disable(TEST_IO_9));
|
||||
TEST_ESP_OK(gpio_isr_handler_remove(TEST_IO_9));
|
||||
gpio_uninstall_isr_service();
|
||||
TEST_ASSERT(edge_intr_times == 2);
|
||||
}
|
||||
#endif //!CONFIG_FREERTOS_UNICORE
|
||||
|
||||
typedef struct {
|
||||
int gpio_num;
|
||||
int isr_cnt;
|
||||
} gpio_isr_param_t;
|
||||
|
||||
static void gpio_isr_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 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};
|
||||
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
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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!");
|
||||
}
|
||||
}
|
||||
#endif //SOC_USB_SERIAL_JTAG_SUPPORTED
|
18
components/driver/test_apps/gpio/CMakeLists.txt
Normal file
18
components/driver/test_apps/gpio/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(gpio_test)
|
||||
|
||||
if(CONFIG_COMPILER_DUMP_RTL_FILES)
|
||||
add_custom_target(check_test_app_sections ALL
|
||||
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
|
||||
--rtl-dir ${CMAKE_BINARY_DIR}/esp-idf/driver/
|
||||
--elf-file ${CMAKE_BINARY_DIR}/gpio_test.elf
|
||||
find-refs
|
||||
--from-sections=.iram0.text
|
||||
--to-sections=.flash.text,.flash.rodata
|
||||
--exit-code
|
||||
DEPENDS ${elf}
|
||||
)
|
||||
endif()
|
18
components/driver/test_apps/gpio/main/CMakeLists.txt
Normal file
18
components/driver/test_apps/gpio/main/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_gpio.c")
|
||||
|
||||
set(include_tests "-u test_app_include_gpio")
|
||||
|
||||
if(CONFIG_SOC_DEDICATED_GPIO_SUPPORTED)
|
||||
list(APPEND srcs "test_dedicated_gpio.c")
|
||||
list(APPEND include_tests "-u test_app_include_dedicated_gpio")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_SIGMADELTA_SUPPORTED)
|
||||
list(APPEND srcs "test_sigmadelta.c")
|
||||
list(APPEND include_tests "-u test_app_include_sigmadelta")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs})
|
||||
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE ${include_tests})
|
41
components/driver/test_apps/gpio/main/test_app_main.c
Normal file
41
components/driver/test_apps/gpio/main/test_app_main.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
// Some resources are lazy allocated in gpio/dedicated_gpio/delta_sigma driver, the threshold is left for that case
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-400)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
unity_run_menu();
|
||||
}
|
@@ -1,20 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/cpu_ll.h"
|
||||
#include "driver/gpio.h"
|
||||
#if SOC_DEDICATED_GPIO_SUPPORTED
|
||||
#include "driver/dedic_gpio.h"
|
||||
|
||||
TEST_CASE("Dedicated GPIO bundle install/uninstall", "[dedic_gpio]")
|
||||
void test_app_include_dedicated_gpio(void)
|
||||
{
|
||||
}
|
||||
|
||||
TEST_CASE("Dedicated_GPIO_bundle_install/uninstall", "[dedic_gpio]")
|
||||
{
|
||||
const int test_gpios[SOC_DEDIC_GPIO_OUT_CHANNELS_NUM / 2] = {0};
|
||||
const int test2_gpios[SOC_DEDIC_GPIO_OUT_CHANNELS_NUM / 2 + 1] = {0};
|
||||
@@ -136,12 +141,13 @@ static void test_dedic_gpio_on_specific_core(void *args)
|
||||
TEST_ESP_OK(dedic_gpio_del_bundle(bundleB));
|
||||
|
||||
xSemaphoreGive(ctx->sem);
|
||||
vTaskDelete(NULL);
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Dedicated GPIO run on multiple CPU core", "[dedic_gpio]")
|
||||
TEST_CASE("Dedicated_GPIO_run_on_multiple_CPU_cores", "[dedic_gpio]")
|
||||
{
|
||||
SemaphoreHandle_t sem = xSemaphoreCreateCounting(SOC_CPU_CORES_NUM, 0);
|
||||
TaskHandle_t task_handle[SOC_CPU_CORES_NUM];
|
||||
|
||||
for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
|
||||
int start_gpio = i * TEST_GPIO_GROUP_SIZE;
|
||||
@@ -149,13 +155,18 @@ TEST_CASE("Dedicated GPIO run on multiple CPU core", "[dedic_gpio]")
|
||||
.sem = sem,
|
||||
.gpios = {start_gpio, start_gpio + 1, start_gpio + 2, start_gpio + 3}
|
||||
};
|
||||
xTaskCreatePinnedToCore(test_dedic_gpio_on_specific_core, "dedic_gpio_test_tsk", 4096, &isr_ctx, 1, NULL, i);
|
||||
xTaskCreatePinnedToCore(test_dedic_gpio_on_specific_core, "dedic_gpio_test_tsk", 4096, &isr_ctx, 1,
|
||||
&task_handle[i], i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
|
||||
xSemaphoreTake(sem, pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
vSemaphoreDelete(sem);
|
||||
for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
|
||||
unity_utils_task_delete(task_handle[i]);
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR static void test_dedic_gpio_isr_callback(void *args)
|
||||
@@ -169,7 +180,7 @@ IRAM_ATTR static void test_dedic_gpio_isr_callback(void *args)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Dedicated GPIO interrupt and callback", "[dedic_gpio]")
|
||||
TEST_CASE("Dedicated_GPIO_interrupt_and_callback", "[dedic_gpio]")
|
||||
{
|
||||
SemaphoreHandle_t sem = xSemaphoreCreateBinary();
|
||||
|
||||
@@ -214,5 +225,3 @@ TEST_CASE("Dedicated GPIO interrupt and callback", "[dedic_gpio]")
|
||||
TEST_ESP_OK(dedic_gpio_del_bundle(bundle));
|
||||
vSemaphoreDelete(sem);
|
||||
}
|
||||
|
||||
#endif // #if SOC_DEDICATED_GPIO_SUPPORTED
|
843
components/driver/test_apps/gpio/main/test_gpio.c
Normal file
843
components/driver/test_apps/gpio/main/test_gpio.c
Normal file
@@ -0,0 +1,843 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#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 "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
|
||||
|
||||
/**
|
||||
* Do some initialization operation in this function
|
||||
* @param num it is the destination GPIO wanted to be initialized
|
||||
*/
|
||||
static gpio_config_t test_init_io(gpio_num_t num)
|
||||
{
|
||||
TEST_ASSERT(GPIO_IS_VALID_OUTPUT_GPIO(num));
|
||||
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,
|
||||
};
|
||||
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
|
||||
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]")
|
||||
{
|
||||
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_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");
|
||||
}
|
||||
|
||||
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 (esp_rom_uart_rx_one_char((uint8_t *) sign) == 0) {
|
||||
}
|
||||
/* Read line */
|
||||
esp_rom_uart_rx_string((uint8_t *) sign, sizeof(sign) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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);
|
||||
|
||||
printf("pull up test!\n");
|
||||
// pull up test
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_OUTPUT");
|
||||
|
||||
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));
|
||||
|
||||
// open drain just can output low level
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_OUTPUT_OD");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_INPUT_OUTPUT");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_INPUT");
|
||||
|
||||
// after pull up the level is high now
|
||||
// pull down test
|
||||
printf("pull down test!\n");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_OUTPUT");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_OUTPUT_OD");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_INPUT_OUTPUT_OD");
|
||||
|
||||
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));
|
||||
prompt_to_continue("mode: GPIO_MODE_INPUT_OUTPUT");
|
||||
|
||||
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));
|
||||
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
|
||||
* 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-10k
|
||||
* 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:
|
||||
* weak capability < stronger capability < default capability = default capability2 < strongest capability
|
||||
*
|
||||
* all of these cases should be ignored that it will not run in CI
|
||||
*/
|
||||
TEST_CASE_CI_IGNORE("GPIO_drive_capability_test", "[gpio]")
|
||||
{
|
||||
printf("weak capability test! please view the current change!\n");
|
||||
drive_capability_set_get(TEST_GPIO_EXT_OUT_IO, GPIO_DRIVE_CAP_0);
|
||||
prompt_to_continue("If this test finishes");
|
||||
|
||||
printf("stronger capability test! please view the current change!\n");
|
||||
drive_capability_set_get(TEST_GPIO_EXT_OUT_IO, GPIO_DRIVE_CAP_1);
|
||||
prompt_to_continue("If this test finishes");
|
||||
|
||||
printf("default capability test! please view the current change!\n");
|
||||
drive_capability_set_get(TEST_GPIO_EXT_OUT_IO, GPIO_DRIVE_CAP_2);
|
||||
prompt_to_continue("If this test finishes");
|
||||
|
||||
printf("default capability2 test! please view the current change!\n");
|
||||
drive_capability_set_get(TEST_GPIO_EXT_OUT_IO, GPIO_DRIVE_CAP_DEFAULT);
|
||||
prompt_to_continue("If this test finishes");
|
||||
|
||||
printf("strongest capability test! please view the current change!\n");
|
||||
drive_capability_set_get(TEST_GPIO_EXT_OUT_IO, GPIO_DRIVE_CAP_3);
|
||||
prompt_to_continue("If this test finishes");
|
||||
}
|
||||
|
||||
#if SOC_USB_SERIAL_JTAG_SUPPORTED
|
||||
TEST_CASE("GPIO_input_and_output_of_USB_pins_test", "[gpio]")
|
||||
{
|
||||
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,
|
||||
.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
|
||||
esp_rom_delay_us(10);
|
||||
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(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(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(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);
|
||||
}
|
53
components/driver/test_apps/gpio/main/test_gpio.h
Normal file
53
components/driver/test_apps/gpio/main/test_gpio.h
Normal file
@@ -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
|
@@ -3,16 +3,18 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_SIGMADELTA_SUPPORTED
|
||||
#include "driver/sigmadelta.h"
|
||||
|
||||
void test_app_include_sigmadelta(void)
|
||||
{
|
||||
}
|
||||
|
||||
TEST_CASE("SigmaDelta config test", "[sigma_delta]")
|
||||
TEST_CASE("SigmaDelta_config_test", "[sigma_delta]")
|
||||
{
|
||||
sigmadelta_config_t sigmadelta_cfg = {
|
||||
.sigmadelta_prescale = 80,
|
||||
@@ -30,7 +32,7 @@ TEST_CASE("SigmaDelta config test", "[sigma_delta]")
|
||||
|
||||
// connect GPIO4 with LED positive pin, and the GND pin connect LED negative pin
|
||||
// logic analyzer help also to see the wave form(more standard and accurate)
|
||||
TEST_CASE("SigmaDelta pin, duty, prescale set", "[sigma_delta][ignore]")
|
||||
TEST_CASE("SigmaDelta_pin_duty_prescale_set", "[sigma_delta][ignore]")
|
||||
{
|
||||
sigmadelta_config_t sigmadelta_cfg = {
|
||||
.channel = 0,
|
||||
@@ -66,5 +68,3 @@ TEST_CASE("SigmaDelta pin, duty, prescale set", "[sigma_delta][ignore]")
|
||||
TEST_ESP_OK(sigmadelta_set_pin(sigmadelta_cfg.channel, 5));
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
#endif // SOC_SIGMADELTA_SUPPORTED
|
21
components/driver/test_apps/gpio/pytest_gpio.py
Normal file
21
components/driver/test_apps/gpio/pytest_gpio.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.supported_targets
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'iram_safe',
|
||||
'release',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_gpio(dut: Dut) -> None:
|
||||
dut.expect_exact('Press ENTER to see the list of tests')
|
||||
dut.write('*')
|
||||
dut.expect_unity_test_output()
|
4
components/driver/test_apps/gpio/sdkconfig.ci.iram_safe
Normal file
4
components/driver/test_apps/gpio/sdkconfig.ci.iram_safe
Normal file
@@ -0,0 +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
|
5
components/driver/test_apps/gpio/sdkconfig.ci.release
Normal file
5
components/driver/test_apps/gpio/sdkconfig.ci.release
Normal file
@@ -0,0 +1,5 @@
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
2
components/driver/test_apps/gpio/sdkconfig.defaults
Normal file
2
components/driver/test_apps/gpio/sdkconfig.defaults
Normal file
@@ -0,0 +1,2 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT=n
|
@@ -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)))
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include "nvs_flash.h"
|
||||
#include "test_utils.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "unity_test_utils.h"
|
||||
|
||||
#define GOT_IP_EVENT 0x00000001
|
||||
#define DISCONNECT_EVENT 0x00000002
|
||||
@@ -116,7 +117,7 @@ TEST_CASE("wifi driver can start on APP CPU", "[wifi_init]")
|
||||
xSemaphoreTake(sema, portMAX_DELAY);
|
||||
vSemaphoreDelete(sema);
|
||||
sema = NULL;
|
||||
test_utils_task_delete(th);
|
||||
unity_utils_task_delete(th);
|
||||
}
|
||||
|
||||
static void wifi_start_stop_task(void* arg)
|
||||
@@ -169,7 +170,7 @@ TEST_CASE("Calling esp_wifi_stop() with start", "[wifi_init]")
|
||||
xSemaphoreTake(sema, portMAX_DELAY);
|
||||
vSemaphoreDelete(sema);
|
||||
sema = NULL;
|
||||
test_utils_task_delete(th);
|
||||
unity_utils_task_delete(th);
|
||||
}
|
||||
|
||||
static void wifi_stop_task(void* arg)
|
||||
@@ -218,7 +219,7 @@ TEST_CASE("Calling esp_wifi_stop() without start", "[wifi_init]")
|
||||
xSemaphoreTake(sema, portMAX_DELAY);
|
||||
vSemaphoreDelete(sema);
|
||||
sema = NULL;
|
||||
test_utils_task_delete(th);
|
||||
unity_utils_task_delete(th);
|
||||
}
|
||||
|
||||
static void wifi_deinit_task(void* arg)
|
||||
@@ -271,5 +272,5 @@ TEST_CASE("Calling esp_wifi_deinit() without stop", "[wifi_init]")
|
||||
xSemaphoreTake(sema, portMAX_DELAY);
|
||||
vSemaphoreDelete(sema);
|
||||
sema = NULL;
|
||||
test_utils_task_delete(th);
|
||||
unity_utils_task_delete(th);
|
||||
}
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -24,6 +24,8 @@
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "test_utils.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <esp_spi_flash.h>
|
||||
#include "../cache_utils.h"
|
||||
#include "soc/timer_periph.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include "lwip/sockets.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "tcp_transport_fixtures.h"
|
||||
#include "unity_test_utils.h"
|
||||
|
||||
// This is a private API of the tcp transport, but needed for socket operation tests
|
||||
int esp_transport_get_socket(esp_transport_handle_t t);
|
||||
@@ -228,8 +229,8 @@ static void connect_test_teardown(tcp_connect_test_t t)
|
||||
vTaskSuspend(t->tcp_connect_task);
|
||||
vTaskSuspend(t->listener_task);
|
||||
vEventGroupDelete(t->tcp_connect_done);
|
||||
test_utils_task_delete(t->tcp_connect_task);
|
||||
test_utils_task_delete(t->listener_task);
|
||||
unity_utils_task_delete(t->tcp_connect_task);
|
||||
unity_utils_task_delete(t->listener_task);
|
||||
free(t);
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,7 @@ endif()
|
||||
|
||||
if(CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER)
|
||||
list(APPEND srcs "unity_runner.c")
|
||||
list(APPEND srcs "unity_utils_freertos.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_UNITY_ENABLE_FIXTURE)
|
||||
|
@@ -1,16 +1,8 @@
|
||||
// Copyright 2016-2018 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: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -131,7 +123,6 @@ void unity_testcase_register(test_desc_t* desc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* First argument is a free-form description,
|
||||
* second argument is (by convention) a list of identifiers, each one in square brackets.
|
||||
@@ -157,6 +148,18 @@ void unity_testcase_register(test_desc_t* desc);
|
||||
unity_testcase_register( & UNITY_TEST_UID(test_desc_) ); \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Test case macro to be ignored in CI.
|
||||
Tests will still be built (to check for compile error) but not linked if IDF_CI_BUILD.
|
||||
*/
|
||||
#if IDF_CI_BUILD
|
||||
#define TEST_CASE_CI_IGNORE(name_, desc_) \
|
||||
__attribute__((unused)) static void UNITY_TEST_UID(test_func_) (void)
|
||||
#else
|
||||
#define TEST_CASE_CI_IGNORE(name_, desc_) TEST_CASE(name_, desc_)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Note: initialization of test_desc_t fields above has to be done exactly
|
||||
* in the same order as the fields are declared in the structure.
|
||||
|
26
components/unity/include/unity_test_utils.h
Normal file
26
components/unity/include/unity_test_utils.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Delete task ensuring dynamic memory (for stack, tcb etc.) gets freed up immediately
|
||||
*
|
||||
* @param[in] thandle Handle of task to be deleted (should not be NULL or self handle)
|
||||
*/
|
||||
void unity_utils_task_delete(TaskHandle_t thandle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
69
components/unity/unity_utils_freertos.c
Normal file
69
components/unity/unity_utils_freertos.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "sdkconfig.h"
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
#include "esp_ipc.h"
|
||||
#include "esp_freertos_hooks.h"
|
||||
#endif
|
||||
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
static SemaphoreHandle_t test_sem;
|
||||
|
||||
static bool idle_hook_func(void)
|
||||
{
|
||||
if (test_sem) {
|
||||
xSemaphoreGive(test_sem);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void task_delete_func(void *arg)
|
||||
{
|
||||
vTaskDelete(arg);
|
||||
}
|
||||
#endif // !CONFIG_FREERTOS_UNICORE
|
||||
|
||||
void unity_utils_task_delete(TaskHandle_t thandle)
|
||||
{
|
||||
/* Self deletion can not free up associated task dynamic memory immediately,
|
||||
* hence not recommended for test scenarios */
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(thandle, "unity_utils_task_delete: handle is NULL");
|
||||
TEST_ASSERT_NOT_EQUAL_MESSAGE(thandle, xTaskGetCurrentTaskHandle(), "unity_utils_task_delete: handle is of currently executing task");
|
||||
|
||||
#if CONFIG_FREERTOS_UNICORE
|
||||
vTaskDelete(thandle);
|
||||
#else // CONFIG_FREERTOS_UNICORE
|
||||
const BaseType_t tsk_affinity = xTaskGetAffinity(thandle);
|
||||
const BaseType_t core_id = xPortGetCoreID();
|
||||
|
||||
printf("Task_affinity: 0x%x, current_core: %d\n", tsk_affinity, core_id);
|
||||
|
||||
if (tsk_affinity == tskNO_AFFINITY) {
|
||||
/* For no affinity case, we wait for idle hook to trigger on different core */
|
||||
esp_err_t ret = esp_register_freertos_idle_hook_for_cpu(idle_hook_func, !core_id);
|
||||
TEST_ASSERT_EQUAL_MESSAGE(ret, ESP_OK, "unity_utils_task_delete: failed to register idle hook");
|
||||
vTaskDelete(thandle);
|
||||
test_sem = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(test_sem, "unity_utils_task_delete: failed to create semaphore");
|
||||
xSemaphoreTake(test_sem, portMAX_DELAY);
|
||||
esp_deregister_freertos_idle_hook_for_cpu(idle_hook_func, !core_id);
|
||||
vSemaphoreDelete(test_sem);
|
||||
test_sem = NULL;
|
||||
} else if (tsk_affinity != core_id) {
|
||||
/* Task affinity and current core are differnt, schedule IPC call (to delete task)
|
||||
* on core where task is pinned to */
|
||||
esp_ipc_call_blocking(tsk_affinity, task_delete_func, thandle);
|
||||
} else {
|
||||
/* Task affinity and current core are same, so we can safely proceed for deletion */
|
||||
vTaskDelete(thandle);
|
||||
}
|
||||
#endif // !CONFIG_FREERTOS_UNICORE
|
||||
}
|
@@ -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
|
||||
@@ -905,7 +904,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
|
||||
@@ -1383,7 +1381,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
|
||||
@@ -1683,7 +1680,6 @@ components/ulp/test/esp32/test_ulp_as.c
|
||||
components/unity/include/priv/setjmp.h
|
||||
components/unity/include/unity_config.h
|
||||
components/unity/include/unity_fixture_extras.h
|
||||
components/unity/include/unity_test_runner.h
|
||||
components/unity/unity_runner.c
|
||||
components/usb/test/hcd/test_hcd_ctrl.c
|
||||
components/vfs/include/esp_vfs_common.h
|
||||
|
@@ -11,8 +11,6 @@
|
||||
#include <stdint.h>
|
||||
#include <esp_partition.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "soc/soc_caps.h"
|
||||
/* include performance pass standards header file */
|
||||
@@ -237,14 +235,6 @@ test_utils_exhaust_memory_rec test_utils_exhaust_memory(uint32_t caps, size_t li
|
||||
*/
|
||||
void test_utils_free_exhausted_memory(test_utils_exhaust_memory_rec rec);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete task ensuring dynamic memory (for stack, tcb etc.) gets freed up immediately
|
||||
*
|
||||
* @param[in] thandle Handle of task to be deleted (should not be NULL or self handle)
|
||||
*/
|
||||
void test_utils_task_delete(TaskHandle_t thandle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -13,10 +13,6 @@
|
||||
#include "lwip/sockets.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "memory_checks.h"
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
#include "esp_ipc.h"
|
||||
#include "esp_freertos_hooks.h"
|
||||
#endif
|
||||
|
||||
const esp_partition_t *get_test_data_partition(void)
|
||||
{
|
||||
@@ -147,57 +143,3 @@ void test_utils_free_exhausted_memory(test_utils_exhaust_memory_rec rec)
|
||||
}
|
||||
free(rec);
|
||||
}
|
||||
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
static SemaphoreHandle_t test_sem;
|
||||
|
||||
static bool test_idle_hook_func(void)
|
||||
{
|
||||
if (test_sem) {
|
||||
xSemaphoreGive(test_sem);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void test_task_delete_func(void *arg)
|
||||
{
|
||||
vTaskDelete(arg);
|
||||
}
|
||||
#endif // !CONFIG_FREERTOS_UNICORE
|
||||
|
||||
void test_utils_task_delete(TaskHandle_t thandle)
|
||||
{
|
||||
/* Self deletion can not free up associated task dynamic memory immediately,
|
||||
* hence not recommended for test scenarios */
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(thandle, "test_utils_task_delete: handle is NULL");
|
||||
TEST_ASSERT_NOT_EQUAL_MESSAGE(thandle, xTaskGetCurrentTaskHandle(), "test_utils_task_delete: handle is of currently executing task");
|
||||
|
||||
#if CONFIG_FREERTOS_UNICORE
|
||||
vTaskDelete(thandle);
|
||||
#else // CONFIG_FREERTOS_UNICORE
|
||||
const BaseType_t tsk_affinity = xTaskGetAffinity(thandle);
|
||||
const BaseType_t core_id = xPortGetCoreID();
|
||||
|
||||
printf("Task_affinity: 0x%x, current_core: %d\n", tsk_affinity, core_id);
|
||||
|
||||
if (tsk_affinity == tskNO_AFFINITY) {
|
||||
/* For no affinity case, we wait for idle hook to trigger on different core */
|
||||
esp_err_t ret = esp_register_freertos_idle_hook_for_cpu(test_idle_hook_func, !core_id);
|
||||
TEST_ASSERT_EQUAL_MESSAGE(ret, ESP_OK, "test_utils_task_delete: failed to register idle hook");
|
||||
vTaskDelete(thandle);
|
||||
test_sem = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(test_sem, "test_utils_task_delete: failed to create semaphore");
|
||||
xSemaphoreTake(test_sem, portMAX_DELAY);
|
||||
esp_deregister_freertos_idle_hook_for_cpu(test_idle_hook_func, !core_id);
|
||||
vSemaphoreDelete(test_sem);
|
||||
test_sem = NULL;
|
||||
} else if (tsk_affinity != core_id) {
|
||||
/* Task affinity and current core are differnt, schedule IPC call (to delete task)
|
||||
* on core where task is pinned to */
|
||||
esp_ipc_call_blocking(tsk_affinity, test_task_delete_func, thandle);
|
||||
} else {
|
||||
/* Task affinity and current core are same, so we can safely proceed for deletion */
|
||||
vTaskDelete(thandle);
|
||||
}
|
||||
#endif // !CONFIG_FREERTOS_UNICORE
|
||||
}
|
||||
|
Reference in New Issue
Block a user