gpio: support glitch filter

This commit is contained in:
morris
2022-10-11 18:04:54 +08:00
parent 2b9d3a37ee
commit 62f1cbca2c
36 changed files with 945 additions and 83 deletions

View File

@@ -3,6 +3,7 @@ idf_build_get_property(target IDF_TARGET)
set(srcs
"gpio/gpio.c"
"gpio/rtc_io.c"
"gpio/gpio_glitch_filter_ops.c"
"gptimer/gptimer.c"
"sdspi_crc.c"
"sdspi_host.c"
@@ -57,6 +58,14 @@ if(CONFIG_SOC_DEDICATED_GPIO_SUPPORTED)
list(APPEND srcs "gpio/dedic_gpio.c")
endif()
if(CONFIG_SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER)
list(APPEND srcs "gpio/gpio_pin_glitch_filter.c")
endif()
if(CONFIG_SOC_GPIO_FLEX_GLITCH_FILTER_NUM GREATER 0)
list(APPEND srcs "gpio/gpio_flex_glitch_filter.c")
endif()
if(CONFIG_SOC_SDM_SUPPORTED)
list(APPEND srcs "sdm.c" "deprecated/sigma_delta_legacy.c")
endif()

View File

@@ -0,0 +1,40 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include "driver/gpio_filter.h"
#include "esp_heap_caps.h"
#define FILTER_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#ifdef __cplusplus
extern "C" {
#endif
typedef struct gpio_glitch_filter_t gpio_glitch_filter_t;
typedef enum {
GLITCH_FILTER_FSM_INIT,
GLITCH_FILTER_FSM_ENABLE,
} glitch_filter_fsm_t;
/**
* @brief Glitch Filter base class
*/
struct gpio_glitch_filter_t {
glitch_filter_fsm_t fsm;
gpio_num_t gpio_num;
esp_err_t (*enable)(gpio_glitch_filter_t *filter);
esp_err_t (*disable)(gpio_glitch_filter_t *filter);
esp_err_t (*del)(gpio_glitch_filter_t *filter);
};
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,142 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/cdefs.h>
#include "freertos/FreeRTOS.h"
#include "esp_check.h"
#include "glitch_filter_priv.h"
#include "esp_private/esp_clk.h"
#include "soc/soc_caps.h"
#include "hal/gpio_glitch_filter_ll.h"
static const char *TAG = "gpio-filter";
typedef struct gpio_flex_glitch_filter_t gpio_flex_glitch_filter_t;
typedef struct gpio_flex_glitch_filter_group_t {
gpio_glitch_filter_dev_t *hw;
gpio_flex_glitch_filter_t *filters[SOC_GPIO_FLEX_GLITCH_FILTER_NUM];
portMUX_TYPE spinlock;
} gpio_flex_glitch_filter_group_t;
struct gpio_flex_glitch_filter_t {
gpio_glitch_filter_t base;
gpio_flex_glitch_filter_group_t *group;
uint32_t filter_id;
};
static gpio_flex_glitch_filter_group_t s_gpio_glitch_filter_group = {
.hw = &GLITCH_FILTER,
.spinlock = portMUX_INITIALIZER_UNLOCKED,
};
static esp_err_t gpio_filter_register_to_group(gpio_flex_glitch_filter_t *filter)
{
gpio_flex_glitch_filter_group_t *group = &s_gpio_glitch_filter_group;
int filter_id = -1;
// loop to search free one in the group
portENTER_CRITICAL(&group->spinlock);
for (int j = 0; j < SOC_GPIO_FLEX_GLITCH_FILTER_NUM; j++) {
if (!group->filters[j]) {
filter_id = j;
group->filters[j] = filter;
break;
}
}
portEXIT_CRITICAL(&group->spinlock);
ESP_RETURN_ON_FALSE(filter_id != -1, ESP_ERR_NOT_FOUND, TAG, "no free gpio glitch filter");
filter->filter_id = filter_id;
filter->group = group;
return ESP_OK;
}
static esp_err_t gpio_filter_destroy(gpio_flex_glitch_filter_t *filter)
{
gpio_flex_glitch_filter_group_t *group = &s_gpio_glitch_filter_group;
int filter_id = filter->filter_id;
// unregister the filter from the group
if (filter->group) {
portENTER_CRITICAL(&group->spinlock);
group->filters[filter_id] = NULL;
portEXIT_CRITICAL(&group->spinlock);
}
free(filter);
return ESP_OK;
}
static esp_err_t gpio_flex_glitch_filter_del(gpio_glitch_filter_t *filter)
{
ESP_RETURN_ON_FALSE(filter->fsm == GLITCH_FILTER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "filter not in init state");
gpio_flex_glitch_filter_t *flex_filter = __containerof(filter, gpio_flex_glitch_filter_t, base);
return gpio_filter_destroy(flex_filter);
}
static esp_err_t gpio_flex_glitch_filter_enable(gpio_glitch_filter_t *filter)
{
ESP_RETURN_ON_FALSE(filter->fsm == GLITCH_FILTER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "filter not in init state");
gpio_flex_glitch_filter_t *flex_filter = __containerof(filter, gpio_flex_glitch_filter_t, base);
int filter_id = flex_filter->filter_id;
gpio_ll_glitch_filter_enable(s_gpio_glitch_filter_group.hw, filter_id, true);
filter->fsm = GLITCH_FILTER_FSM_ENABLE;
return ESP_OK;
}
static esp_err_t gpio_flex_glitch_filter_disable(gpio_glitch_filter_t *filter)
{
ESP_RETURN_ON_FALSE(filter->fsm == GLITCH_FILTER_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "filter not in enable state");
gpio_flex_glitch_filter_t *flex_filter = __containerof(filter, gpio_flex_glitch_filter_t, base);
int filter_id = flex_filter->filter_id;
gpio_ll_glitch_filter_enable(s_gpio_glitch_filter_group.hw, filter_id, false);
filter->fsm = GLITCH_FILTER_FSM_INIT;
return ESP_OK;
}
esp_err_t gpio_new_flex_glitch_filter(const gpio_flex_glitch_filter_config_t *config, gpio_glitch_filter_handle_t *ret_filter)
{
esp_err_t ret = ESP_OK;
gpio_flex_glitch_filter_t *filter = NULL;
ESP_GOTO_ON_FALSE(config && ret_filter, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(GPIO_IS_VALID_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, err, TAG, "invalid gpio number");
// Glitch filter's clock source is same to the IOMUX clock
// TODO: IDF-6345 task will make the IOMUX clock source configurable, and we should opt the glitch filter clock source accordingly
uint32_t clk_freq_mhz = esp_clk_xtal_freq() / 1000000;
uint32_t window_thres_ticks = clk_freq_mhz * config->window_thres_ns / 1000;
uint32_t window_width_ticks = clk_freq_mhz * config->window_width_ns / 1000;
ESP_GOTO_ON_FALSE(window_thres_ticks && window_thres_ticks <= window_width_ticks && window_width_ticks <= GPIO_LL_GLITCH_FILTER_MAX_WINDOW,
ESP_ERR_INVALID_ARG, err, TAG, "invalid or out of range window width/threshold");
filter = heap_caps_calloc(1, sizeof(gpio_flex_glitch_filter_t), FILTER_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(filter, ESP_ERR_NO_MEM, err, TAG, "no memory for flex glitch filter");
// register the filter to the group
ESP_GOTO_ON_ERROR(gpio_filter_register_to_group(filter), err, TAG, "register filter to group failed");
int filter_id = filter->filter_id;
// make sure the filter is disabled
gpio_ll_glitch_filter_enable(s_gpio_glitch_filter_group.hw, filter_id, false);
// apply the filter to the GPIO
gpio_ll_glitch_filter_set_gpio(s_gpio_glitch_filter_group.hw, filter_id, config->gpio_num);
// set filter coefficient
gpio_ll_glitch_filter_set_window_coeff(s_gpio_glitch_filter_group.hw, filter_id, window_width_ticks, window_thres_ticks);
filter->base.gpio_num = config->gpio_num;
filter->base.fsm = GLITCH_FILTER_FSM_INIT;
filter->base.del = gpio_flex_glitch_filter_del;
filter->base.enable = gpio_flex_glitch_filter_enable;
filter->base.disable = gpio_flex_glitch_filter_disable;
*ret_filter = &(filter->base);
return ESP_OK;
err:
if (filter) {
gpio_filter_destroy(filter);
}
return ret;
}

View File

@@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_check.h"
#include "glitch_filter_priv.h"
static const char *TAG = "gpio-filter";
/////////// Public abstract functions ///////////
esp_err_t gpio_del_glitch_filter(gpio_glitch_filter_handle_t filter)
{
ESP_RETURN_ON_FALSE(filter, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
return filter->del(filter);
}
esp_err_t gpio_glitch_filter_enable(gpio_glitch_filter_handle_t filter)
{
ESP_RETURN_ON_FALSE(filter, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
return filter->enable(filter);
}
esp_err_t gpio_glitch_filter_disable(gpio_glitch_filter_handle_t filter)
{
ESP_RETURN_ON_FALSE(filter, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
return filter->disable(filter);
}

View File

@@ -0,0 +1,69 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/cdefs.h>
#include "freertos/FreeRTOS.h"
#include "esp_check.h"
#include "glitch_filter_priv.h"
#include "hal/gpio_ll.h"
static const char *TAG = "gpio-filter";
/**
* @brief Type of GPIO pin glitch filter
*/
typedef struct gpio_pin_glitch_filter_t {
gpio_glitch_filter_t base;
} gpio_pin_glitch_filter_t;
static esp_err_t gpio_pin_glitch_filter_del(gpio_glitch_filter_t *filter)
{
ESP_RETURN_ON_FALSE(filter->fsm == GLITCH_FILTER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "filter not in init state");
gpio_pin_glitch_filter_t *pin_filter = __containerof(filter, gpio_pin_glitch_filter_t, base);
free(pin_filter);
return ESP_OK;
}
static esp_err_t gpio_pin_glitch_filter_enable(gpio_glitch_filter_t *filter)
{
ESP_RETURN_ON_FALSE(filter->fsm == GLITCH_FILTER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "filter not in init state");
gpio_ll_pin_filter_enable(NULL, filter->gpio_num);
filter->fsm = GLITCH_FILTER_FSM_ENABLE;
return ESP_OK;
}
static esp_err_t gpio_pin_glitch_filter_disable(gpio_glitch_filter_t *filter)
{
ESP_RETURN_ON_FALSE(filter->fsm == GLITCH_FILTER_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "filter not in enable state");
gpio_ll_pin_filter_disable(NULL, filter->gpio_num);
filter->fsm = GLITCH_FILTER_FSM_INIT;
return ESP_OK;
}
esp_err_t gpio_new_pin_glitch_filter(const gpio_pin_glitch_filter_config_t *config, gpio_glitch_filter_handle_t *ret_filter)
{
esp_err_t ret = ESP_OK;
gpio_pin_glitch_filter_t *filter = NULL;
ESP_GOTO_ON_FALSE(config && ret_filter, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(GPIO_IS_VALID_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, err, TAG, "invalid gpio number");
filter = heap_caps_calloc(1, sizeof(gpio_pin_glitch_filter_t), FILTER_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(filter, ESP_ERR_NO_MEM, err, TAG, "no memory for pin glitch filter");
filter->base.gpio_num = config->gpio_num;
filter->base.fsm = GLITCH_FILTER_FSM_INIT;
filter->base.del = gpio_pin_glitch_filter_del;
filter->base.enable = gpio_pin_glitch_filter_enable;
filter->base.disable = gpio_pin_glitch_filter_disable;
*ret_filter = &(filter->base);
return ESP_OK;
err:
if (filter) {
free(filter);
}
return ret;
}

View File

@@ -0,0 +1,112 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "esp_err.h"
#include "driver/gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Typedef of GPIO glitch filter handle
*/
typedef struct gpio_glitch_filter_t *gpio_glitch_filter_handle_t;
/**
* @brief Configuration of GPIO pin glitch filter
*/
typedef struct {
gpio_num_t gpio_num; /*!< GPIO number */
} gpio_pin_glitch_filter_config_t;
/**
* @brief Create a pin glitch filter
*
* @note Pin glitch filter parameters are fixed, pulses shorter than two sample clocks (IO-MUX's source clock) will be filtered out.
* It's independent with "flex" glitch filter. See also `gpio_new_flex_glitch_filter`.
* @note The created filter handle can later be deleted by `gpio_del_glitch_filter`.
*
* @param[in] config Glitch filter configuration
* @param[out] ret_filter Returned glitch filter handle
* @return
* - ESP_OK: Create a pin glitch filter successfully
* - ESP_ERR_INVALID_ARG: Create a pin glitch filter failed because of invalid arguments (e.g. wrong GPIO number)
* - ESP_ERR_NO_MEM: Create a pin glitch filter failed because of out of memory
* - ESP_FAIL: Create a pin glitch filter failed because of other error
*/
esp_err_t gpio_new_pin_glitch_filter(const gpio_pin_glitch_filter_config_t *config, gpio_glitch_filter_handle_t *ret_filter);
/**
* @brief Configuration of GPIO flex glitch filter
*/
typedef struct {
gpio_num_t gpio_num; /*!< GPIO number */
uint32_t window_width_ns; /*!< Sample window width (in ns) */
uint32_t window_thres_ns; /*!< Sample window threshold (in ns), during the `window_width_ns` sample window, any pulse whose width < window_thres_ns will be discarded. */
} gpio_flex_glitch_filter_config_t;
/**
* @brief Allocate a flex glitch filter
*
* @note "flex" means the filter parameters (window, threshold) are adjustable. It's independent with pin glitch filter.
* See also `gpio_new_pin_glitch_filter`.
* @note The created filter handle can later be deleted by `gpio_del_glitch_filter`.
*
* @param[in] config Glitch filter configuration
* @param[out] ret_filter Returned glitch filter handle
* @return
* - ESP_OK: Allocate a flex glitch filter successfully
* - ESP_ERR_INVALID_ARG: Allocate a flex glitch filter failed because of invalid arguments (e.g. wrong GPIO number, filter parameters out of range)
* - ESP_ERR_NO_MEM: Allocate a flex glitch filter failed because of out of memory
* - ESP_ERR_NOT_FOUND: Allocate a flex glitch filter failed because the underlying hardware resources are used up
* - ESP_FAIL: Allocate a flex glitch filter failed because of other error
*/
esp_err_t gpio_new_flex_glitch_filter(const gpio_flex_glitch_filter_config_t *config, gpio_glitch_filter_handle_t *ret_filter);
/**
* @brief Delete a glitch filter
*
* @param[in] filter Glitch filter handle returned from `gpio_new_flex_glitch_filter` or `gpio_new_pin_glitch_filter`
* @return
* - ESP_OK: Delete glitch filter successfully
* - ESP_ERR_INVALID_ARG: Delete glitch filter failed because of invalid arguments
* - ESP_ERR_INVALID_STATE: Delete glitch filter failed because the glitch filter is still in working
* - ESP_FAIL: Delete glitch filter failed because of other error
*/
esp_err_t gpio_del_glitch_filter(gpio_glitch_filter_handle_t filter);
/**
* @brief Enable a glitch filter
*
* @param[in] filter Glitch filter handle returned from `gpio_new_flex_glitch_filter` or `gpio_new_pin_glitch_filter`
* @return
* - ESP_OK: Enable glitch filter successfully
* - ESP_ERR_INVALID_ARG: Enable glitch filter failed because of invalid arguments
* - ESP_ERR_INVALID_STATE: Enable glitch filter failed because the glitch filter is already enabled
* - ESP_FAIL: Enable glitch filter failed because of other error
*/
esp_err_t gpio_glitch_filter_enable(gpio_glitch_filter_handle_t filter);
/**
* @brief Disable a glitch filter
*
* @param[in] filter Glitch filter handle returned from `gpio_new_flex_glitch_filter` or `gpio_new_pin_glitch_filter`
* @return
* - ESP_OK: Disable glitch filter successfully
* - ESP_ERR_INVALID_ARG: Disable glitch filter failed because of invalid arguments
* - ESP_ERR_INVALID_STATE: Disable glitch filter failed because the glitch filter is not enabled yet
* - ESP_FAIL: Disable glitch filter failed because of other error
*/
esp_err_t gpio_glitch_filter_disable(gpio_glitch_filter_handle_t filter);
#ifdef __cplusplus
}
#endif

View File

@@ -1,6 +1,10 @@
set(srcs "test_app_main.c"
"test_gpio.c")
if(CONFIG_SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER OR (CONFIG_SOC_GPIO_FLEX_GLITCH_FILTER_NUM GREATER 0))
list(APPEND srcs "test_gpio_filter.c")
endif()
if(CONFIG_SOC_DEDICATED_GPIO_SUPPORTED)
list(APPEND srcs "test_dedicated_gpio.c")
endif()

View File

@@ -0,0 +1,151 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "unity.h"
#include "driver/gpio_filter.h"
#include "driver/dedic_gpio.h"
#include "soc/soc_caps.h"
#if SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER
TEST_CASE("GPIO pin glitch filter life cycle", "[gpio_filter]")
{
gpio_glitch_filter_handle_t filter = NULL;
gpio_pin_glitch_filter_config_t config = {};
TEST_ESP_OK(gpio_new_pin_glitch_filter(&config, &filter));
TEST_ESP_OK(gpio_glitch_filter_enable(filter));
// can't delete filter if it's not disabled
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, gpio_del_glitch_filter(filter));
TEST_ESP_OK(gpio_glitch_filter_disable(filter));
TEST_ESP_OK(gpio_del_glitch_filter(filter));
}
#endif // SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER
#if SOC_GPIO_FLEX_GLITCH_FILTER_NUM > 0
TEST_CASE("GPIO flex glitch filter life cycle", "[gpio_filter]")
{
gpio_glitch_filter_handle_t filters[SOC_GPIO_FLEX_GLITCH_FILTER_NUM];
gpio_flex_glitch_filter_config_t config = {};
// install filter with wrong parameters
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, gpio_new_flex_glitch_filter(&config, &filters[0]));
config.window_thres_ns = 75;
config.window_width_ns = 100;
for (int i = 0; i < SOC_GPIO_FLEX_GLITCH_FILTER_NUM; i++) {
TEST_ESP_OK((gpio_new_flex_glitch_filter(&config, &filters[i])));
}
// no more hardware resource
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, gpio_new_flex_glitch_filter(&config, &filters[0]));
TEST_ESP_OK(gpio_glitch_filter_enable(filters[0]));
// can't delete filter if it's not disabled
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, gpio_del_glitch_filter(filters[0]));
TEST_ESP_OK(gpio_glitch_filter_disable(filters[0]));
for (int i = 0; i < SOC_GPIO_FLEX_GLITCH_FILTER_NUM; i++) {
TEST_ESP_OK(gpio_del_glitch_filter(filters[i]));
}
}
/**
* @brief In order to generate the short glitch pulse, we use CPU CSR register to control the GPIO level,
* which is also called the Fast GPIO or Dedicated GPIO.
* @note Because the CPU instruction / CSR register is not compatible in all ESP chips,
* at the moment, this test only works for Espressif's RISC-V core (e.g. ESP32C6)
*/
#if SOC_DEDICATED_GPIO_SUPPORTED
#include "hal/dedic_gpio_cpu_ll.h"
static void test_gpio_intr_callback(void *args)
{
SemaphoreHandle_t sem = (SemaphoreHandle_t)args;
BaseType_t high_task_wakeup = pdFALSE;
esp_rom_printf("event fired\r\n");
xSemaphoreGiveFromISR(sem, &high_task_wakeup);
if (high_task_wakeup) {
esp_rom_printf("high priority task wake up\r\n");
}
}
TEST_CASE("GPIO flex glitch filter enable/disable", "[gpio_filter]")
{
const gpio_num_t test_gpio = 0;
printf("initialize GPIO for input and out\r\n");
gpio_config_t gpio_cfg = {
.mode = GPIO_MODE_INPUT_OUTPUT,
.pin_bit_mask = BIT64(test_gpio),
.intr_type = GPIO_INTR_POSEDGE,
.pull_down_en = GPIO_PULLDOWN_ENABLE,
};
TEST_ESP_OK(gpio_config(&gpio_cfg));
printf("install fast gpio to generate the glitch signal\r\n");
dedic_gpio_bundle_handle_t bundle = NULL;
dedic_gpio_bundle_config_t bundle_cfg = {
.gpio_array = (int[]){test_gpio},
.array_size = 1,
.flags.out_en = true,
};
TEST_ESP_OK(dedic_gpio_new_bundle(&bundle_cfg, &bundle));
// initial output value to zero
asm volatile("csrrci zero, %0, 0x1" :: "i"(CSR_GPIO_OUT_USER));
printf("apply glitch filter to the GPIO\r\n");
gpio_glitch_filter_handle_t filter;
gpio_flex_glitch_filter_config_t filter_cfg = {
.gpio_num = test_gpio,
.window_thres_ns = 1500, // pulse whose width is shorter than 1500 will be filtered out
.window_width_ns = 1500,
};
TEST_ESP_OK((gpio_new_flex_glitch_filter(&filter_cfg, &filter)));
TEST_ESP_OK(gpio_glitch_filter_enable(filter));
printf("install gpio interrupt\r\n");
gpio_install_isr_service(0);
SemaphoreHandle_t sem = xSemaphoreCreateBinary();
TEST_ESP_OK(gpio_isr_handler_add(test_gpio, test_gpio_intr_callback, sem));
printf("generate rising edge glitch signal\r\n");
asm volatile("csrrsi zero, %0, 0x1" :: "i"(CSR_GPIO_OUT_USER));
asm volatile("csrrci zero, %0, 0x1" :: "i"(CSR_GPIO_OUT_USER));
// should timeout, because the glitch is filtered out
TEST_ASSERT_EQUAL(pdFALSE, xSemaphoreTake(sem, pdMS_TO_TICKS(1000)));
printf("disable the glitch filter\r\n");
TEST_ESP_OK(gpio_glitch_filter_disable(filter));
printf("generate rising edge glitch signal again\r\n");
asm volatile("csrrsi zero, %0, 0x1" :: "i"(CSR_GPIO_OUT_USER));
asm volatile("csrrci zero, %0, 0x1" :: "i"(CSR_GPIO_OUT_USER));
// this time we should see the GPIO interrupt fired up
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(sem, pdMS_TO_TICKS(1000)));
TEST_ESP_OK(gpio_isr_handler_remove(test_gpio));
gpio_uninstall_isr_service();
printf("disable gpio glitch filter\r\n");
TEST_ESP_OK(gpio_del_glitch_filter(filter));
TEST_ESP_OK(dedic_gpio_del_bundle(bundle));
vSemaphoreDelete(sem);
}
#endif // SOC_DEDICATED_GPIO_SUPPORTED
#endif // SOC_GPIO_FLEX_GLITCH_FILTER_NUM > 0