diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 07282a70fb..aa1b5dcd2a 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -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() diff --git a/components/driver/gpio/glitch_filter_priv.h b/components/driver/gpio/glitch_filter_priv.h new file mode 100644 index 0000000000..5d05244e44 --- /dev/null +++ b/components/driver/gpio/glitch_filter_priv.h @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#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 diff --git a/components/driver/gpio/gpio_flex_glitch_filter.c b/components/driver/gpio/gpio_flex_glitch_filter.c new file mode 100644 index 0000000000..a7105805df --- /dev/null +++ b/components/driver/gpio/gpio_flex_glitch_filter.c @@ -0,0 +1,142 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#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; +} diff --git a/components/driver/gpio/gpio_glitch_filter_ops.c b/components/driver/gpio/gpio_glitch_filter_ops.c new file mode 100644 index 0000000000..841d095326 --- /dev/null +++ b/components/driver/gpio/gpio_glitch_filter_ops.c @@ -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); +} diff --git a/components/driver/gpio/gpio_pin_glitch_filter.c b/components/driver/gpio/gpio_pin_glitch_filter.c new file mode 100644 index 0000000000..e2068ba74d --- /dev/null +++ b/components/driver/gpio/gpio_pin_glitch_filter.c @@ -0,0 +1,69 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#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; +} diff --git a/components/driver/include/driver/gpio_filter.h b/components/driver/include/driver/gpio_filter.h new file mode 100644 index 0000000000..7ee33432ba --- /dev/null +++ b/components/driver/include/driver/gpio_filter.h @@ -0,0 +1,112 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#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 diff --git a/components/driver/test_apps/gpio/main/CMakeLists.txt b/components/driver/test_apps/gpio/main/CMakeLists.txt index 60cb6effa6..09dabd06a5 100644 --- a/components/driver/test_apps/gpio/main/CMakeLists.txt +++ b/components/driver/test_apps/gpio/main/CMakeLists.txt @@ -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() diff --git a/components/driver/test_apps/gpio/main/test_gpio_filter.c b/components/driver/test_apps/gpio/main/test_gpio_filter.c new file mode 100644 index 0000000000..345ef6600b --- /dev/null +++ b/components/driver/test_apps/gpio/main/test_gpio_filter.c @@ -0,0 +1,151 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#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 diff --git a/components/driver/twai.c b/components/driver/twai.c index ea34737d04..418f4b24fe 100644 --- a/components/driver/twai.c +++ b/components/driver/twai.c @@ -284,6 +284,8 @@ TWAI_ISR_ATTR static void twai_intr_handler_main(void *arg) static void twai_configure_gpio(gpio_num_t tx, gpio_num_t rx, gpio_num_t clkout, gpio_num_t bus_status) { + // assert the GPIO number is not a negative number (shift operation on a negative number is undefined) + assert(tx >= 0 && rx >= 0); int controller_id = p_twai_obj->controller_id; // if TX and RX set to the same GPIO, which means we want to create a loop-back in the GPIO matrix bool io_loop_back = (tx == rx); @@ -408,8 +410,8 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_ TWAI_CHECK(t_config != NULL, ESP_ERR_INVALID_ARG); TWAI_CHECK(f_config != NULL, ESP_ERR_INVALID_ARG); TWAI_CHECK(g_config->rx_queue_len > 0, ESP_ERR_INVALID_ARG); - TWAI_CHECK(g_config->tx_io >= 0 && g_config->tx_io < GPIO_NUM_MAX, ESP_ERR_INVALID_ARG); - TWAI_CHECK(g_config->rx_io >= 0 && g_config->rx_io < GPIO_NUM_MAX, ESP_ERR_INVALID_ARG); + TWAI_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(g_config->tx_io), ESP_ERR_INVALID_ARG); + TWAI_CHECK(GPIO_IS_VALID_GPIO(g_config->rx_io), ESP_ERR_INVALID_ARG); #ifndef CONFIG_TWAI_ISR_IN_IRAM TWAI_CHECK(!(g_config->intr_flags & ESP_INTR_FLAG_IRAM), ESP_ERR_INVALID_ARG); #endif diff --git a/components/hal/esp32c2/include/hal/gpio_ll.h b/components/hal/esp32c2/include/hal/gpio_ll.h index 1d4c93cf90..fe6a2f4e9e 100644 --- a/components/hal/esp32c2/include/hal/gpio_ll.h +++ b/components/hal/esp32c2/include/hal/gpio_ll.h @@ -185,7 +185,29 @@ static inline void gpio_ll_input_disable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) { - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); + PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); +} + +/** + * @brief Enable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_EN(IO_MUX_GPIO0_REG + (gpio_num * 4)); +} + +/** + * @brief Disable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_DIS(IO_MUX_GPIO0_REG + (gpio_num * 4)); } /** diff --git a/components/hal/esp32c3/include/hal/gpio_ll.h b/components/hal/esp32c3/include/hal/gpio_ll.h index e5d1ad1841..d3b5bd7ea9 100644 --- a/components/hal/esp32c3/include/hal/gpio_ll.h +++ b/components/hal/esp32c3/include/hal/gpio_ll.h @@ -193,7 +193,29 @@ static inline void gpio_ll_input_disable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) { - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); + PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); +} + +/** + * @brief Enable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_EN(IO_MUX_GPIO0_REG + (gpio_num * 4)); +} + +/** + * @brief Disable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_DIS(IO_MUX_GPIO0_REG + (gpio_num * 4)); } /** diff --git a/components/hal/esp32c6/include/hal/gpio_glitch_filter_ll.h b/components/hal/esp32c6/include/hal/gpio_glitch_filter_ll.h new file mode 100644 index 0000000000..7823060765 --- /dev/null +++ b/components/hal/esp32c6/include/hal/gpio_glitch_filter_ll.h @@ -0,0 +1,66 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in hal/include/hal/readme.md + ******************************************************************************/ + +#pragma once + +#include +#include "hal/assert.h" +#include "soc/gpio_ext_struct.h" + +#define GPIO_LL_GLITCH_FILTER_MAX_WINDOW 64 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Enable GPIO glitch filter + * + * @param hw Glitch filter register base address + * @param filter_idx Glitch filter index + * @param enable True to enable, false to disable + */ +static inline void gpio_ll_glitch_filter_enable(gpio_glitch_filter_dev_t *hw, uint32_t filter_idx, bool enable) +{ + hw->glitch_filter_chn[filter_idx].filter_chn_en = enable; +} + +/** + * @brief Set the input GPIO for the glitch filter + * + * @param hw Glitch filter register base address + * @param filter_idx Glitch filter index + * @param gpio_num GPIO number + */ +static inline void gpio_ll_glitch_filter_set_gpio(gpio_glitch_filter_dev_t *hw, uint32_t filter_idx, uint32_t gpio_num) +{ + hw->glitch_filter_chn[filter_idx].filter_chn_input_io_num = gpio_num; +} + +/** + * @brief Set the coefficient of the glitch filter window + * + * @param hw Glitch filter register base address + * @param filter_idx Glitch filter index + * @param window_width Window width, in IOMUX clock ticks + * @param window_threshold Window threshold, in IOMUX clock ticks + */ +static inline void gpio_ll_glitch_filter_set_window_coeff(gpio_glitch_filter_dev_t *hw, uint32_t filter_idx, uint32_t window_width, uint32_t window_thres) +{ + HAL_ASSERT(window_thres <= window_width); + hw->glitch_filter_chn[filter_idx].filter_chn_window_width = window_width - 1; + hw->glitch_filter_chn[filter_idx].filter_chn_window_thres = window_thres - 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32c6/include/hal/gpio_ll.h b/components/hal/esp32c6/include/hal/gpio_ll.h index ea085f2315..05b7b9445b 100644 --- a/components/hal/esp32c6/include/hal/gpio_ll.h +++ b/components/hal/esp32c6/include/hal/gpio_ll.h @@ -201,6 +201,28 @@ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); } +/** + * @brief Enable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_EN(IO_MUX_GPIO0_REG + (gpio_num * 4)); +} + +/** + * @brief Disable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_DIS(IO_MUX_GPIO0_REG + (gpio_num * 4)); +} + /** * @brief Disable output mode on GPIO. * diff --git a/components/hal/esp32h4/include/rev1/hal/gpio_ll.h b/components/hal/esp32h4/include/rev1/hal/gpio_ll.h index b19fcd778a..26bbfdc13e 100644 --- a/components/hal/esp32h4/include/rev1/hal/gpio_ll.h +++ b/components/hal/esp32h4/include/rev1/hal/gpio_ll.h @@ -193,6 +193,28 @@ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); } +/** + * @brief Enable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_EN(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Disable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_DIS(GPIO_PIN_MUX_REG[gpio_num]); +} + /** * @brief Disable output mode on GPIO. * diff --git a/components/hal/esp32h4/include/rev2/hal/gpio_ll.h b/components/hal/esp32h4/include/rev2/hal/gpio_ll.h index dde3843f7a..8ff1a3fc1a 100644 --- a/components/hal/esp32h4/include/rev2/hal/gpio_ll.h +++ b/components/hal/esp32h4/include/rev2/hal/gpio_ll.h @@ -193,6 +193,28 @@ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); } +/** + * @brief Enable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_EN(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Disable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_DIS(GPIO_PIN_MUX_REG[gpio_num]); +} + /** * @brief Disable output mode on GPIO. * @@ -558,7 +580,7 @@ static inline void gpio_ll_sleep_output_enable(gpio_dev_t *hw, uint32_t gpio_num static inline void gpio_ll_deepsleep_wakeup_enable(gpio_dev_t *hw, uint32_t gpio_num, gpio_int_type_t intr_type) { HAL_ASSERT((gpio_num >= GPIO_NUM_7 && gpio_num <= GPIO_NUM_12) && - "only gpio7~12 support deep sleep wake-up function"); + "only gpio7~12 support deep sleep wake-up function"); REG_SET_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_PIN_CLK_GATE); REG_SET_BIT(RTC_CNTL_EXT_WAKEUP_CONF_REG, RTC_CNTL_GPIO_WAKEUP_FILTER); @@ -578,7 +600,7 @@ static inline void gpio_ll_deepsleep_wakeup_enable(gpio_dev_t *hw, uint32_t gpio static inline void gpio_ll_deepsleep_wakeup_disable(gpio_dev_t *hw, uint32_t gpio_num) { HAL_ASSERT((gpio_num >= GPIO_NUM_7 && gpio_num <= GPIO_NUM_12) && - "only gpio7~12 support deep sleep wake-up function"); + "only gpio7~12 support deep sleep wake-up function"); CLEAR_PERI_REG_MASK(RTC_CNTL_GPIO_WAKEUP_REG, 1 << (RTC_CNTL_GPIO_PIN0_WAKEUP_ENABLE_S - (gpio_num - 7))); CLEAR_PERI_REG_MASK(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_PIN0_INT_TYPE_S - (gpio_num - 7) * 3); diff --git a/components/hal/esp32s2/include/hal/gpio_ll.h b/components/hal/esp32s2/include/hal/gpio_ll.h index 75b7c4b0b4..d70b8baf50 100644 --- a/components/hal/esp32s2/include/hal/gpio_ll.h +++ b/components/hal/esp32s2/include/hal/gpio_ll.h @@ -187,7 +187,29 @@ static inline void gpio_ll_input_disable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) { - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); + PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); +} + +/** + * @brief Enable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_EN(IO_MUX_GPIO0_REG + (gpio_num * 4)); +} + +/** + * @brief Disable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_DIS(IO_MUX_GPIO0_REG + (gpio_num * 4)); } /** diff --git a/components/hal/esp32s3/include/hal/gpio_ll.h b/components/hal/esp32s3/include/hal/gpio_ll.h index 93836fb663..62b4bd1d8c 100644 --- a/components/hal/esp32s3/include/hal/gpio_ll.h +++ b/components/hal/esp32s3/include/hal/gpio_ll.h @@ -200,7 +200,29 @@ static inline void gpio_ll_input_disable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) { - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); + PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); +} + +/** + * @brief Enable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_EN(IO_MUX_GPIO0_REG + (gpio_num * 4)); +} + +/** + * @brief Disable GPIO pin filter + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + */ +static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num) +{ + PIN_FILTER_DIS(IO_MUX_GPIO0_REG + (gpio_num * 4)); } /** diff --git a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in index 54171ea6ac..8e0bd7f712 100644 --- a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in @@ -207,6 +207,10 @@ config SOC_GPIO_PIN_COUNT int default 21 +config SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER + bool + default y + config SOC_GPIO_SUPPORTS_RTC_INDEPENDENT bool default y diff --git a/components/soc/esp32c2/include/soc/io_mux_reg.h b/components/soc/esp32c2/include/soc/io_mux_reg.h index b610a6e9dd..b54614e477 100644 --- a/components/soc/esp32c2/include/soc/io_mux_reg.h +++ b/components/soc/esp32c2/include/soc/io_mux_reg.h @@ -65,6 +65,11 @@ #define MCU_SEL_M (MCU_SEL_V << MCU_SEL_S) #define MCU_SEL_V 0x7 #define MCU_SEL_S 12 +/* Pin filter (Pulse width shorter than 2 clock cycles will be filtered out) */ +#define FILTER_EN (BIT(15)) +#define FILTER_EN_M (FILTER_EN_V << FILTER_EN_S) +#define FILTER_EN_V 1 +#define FILTER_EN_S 15 #define PIN_SLP_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_IE) #define PIN_SLP_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_IE) @@ -78,14 +83,16 @@ #define PIN_SLP_SEL_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_SEL) -#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); -#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) -#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) -#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); +#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) +#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) +#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_FILTER_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FILTER_EN) +#define PIN_FILTER_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FILTER_EN) #define IO_MUX_GPIO0_REG PERIPHS_IO_MUX_XTAL_32K_P_U #define IO_MUX_GPIO1_REG PERIPHS_IO_MUX_XTAL_32K_N_U diff --git a/components/soc/esp32c2/include/soc/soc_caps.h b/components/soc/esp32c2/include/soc/soc_caps.h index 58da616a01..47a0d42bac 100644 --- a/components/soc/esp32c2/include/soc/soc_caps.h +++ b/components/soc/esp32c2/include/soc/soc_caps.h @@ -102,8 +102,9 @@ /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-C2 has 1 GPIO peripheral -#define SOC_GPIO_PORT (1U) -#define SOC_GPIO_PIN_COUNT (21) +#define SOC_GPIO_PORT 1U +#define SOC_GPIO_PIN_COUNT 21 +#define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1 // Target has no full RTC IO subsystem, so GPIO is 100% "independent" of RTC // On ESP32-C2, Digital IOs have their own registers to control pullup/down capability, independent of RTC registers. diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index af535e9290..d328f4a92c 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -299,6 +299,10 @@ config SOC_GPIO_PIN_COUNT int default 22 +config SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER + bool + default y + config SOC_GPIO_SUPPORTS_RTC_INDEPENDENT bool default y diff --git a/components/soc/esp32c3/include/soc/io_mux_reg.h b/components/soc/esp32c3/include/soc/io_mux_reg.h index 6d5ae6da2f..c814bdd956 100644 --- a/components/soc/esp32c3/include/soc/io_mux_reg.h +++ b/components/soc/esp32c3/include/soc/io_mux_reg.h @@ -64,6 +64,11 @@ #define MCU_SEL_M (MCU_SEL_V << MCU_SEL_S) #define MCU_SEL_V 0x7 #define MCU_SEL_S 12 +/* Pin filter (Pulse width shorter than 2 clock cycles will be filtered out) */ +#define FILTER_EN (BIT(15)) +#define FILTER_EN_M (FILTER_EN_V << FILTER_EN_S) +#define FILTER_EN_V 1 +#define FILTER_EN_S 15 #define PIN_SLP_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_IE) #define PIN_SLP_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_IE) @@ -77,14 +82,16 @@ #define PIN_SLP_SEL_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_SEL) -#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); -#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) -#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) -#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); +#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) +#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) +#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_FILTER_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FILTER_EN) +#define PIN_FILTER_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FILTER_EN) #define IO_MUX_GPIO0_REG PERIPHS_IO_MUX_XTAL_32K_P_U #define IO_MUX_GPIO1_REG PERIPHS_IO_MUX_XTAL_32K_N_U diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index a443795fdb..9c79e1895d 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -140,8 +140,9 @@ /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-C3 has 1 GPIO peripheral -#define SOC_GPIO_PORT (1U) -#define SOC_GPIO_PIN_COUNT (22) +#define SOC_GPIO_PORT 1U +#define SOC_GPIO_PIN_COUNT 22 +#define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1 // Target has no full RTC IO subsystem, so GPIO is 100% "independent" of RTC // On ESP32-C3, Digital IOs have their own registers to control pullup/down capability, independent of RTC registers. diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 3027883033..244bd789a6 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -279,6 +279,14 @@ config SOC_GPIO_PIN_COUNT int default 31 +config SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER + bool + default y + +config SOC_GPIO_FLEX_GLITCH_FILTER_NUM + int + default 8 + config SOC_GPIO_SUPPORT_ETM bool default y diff --git a/components/soc/esp32c6/include/soc/gpio_ext_struct.h b/components/soc/esp32c6/include/soc/gpio_ext_struct.h index 7bcb54adf2..1468d5ef2a 100644 --- a/components/soc/esp32c6/include/soc/gpio_ext_struct.h +++ b/components/soc/esp32c6/include/soc/gpio_ext_struct.h @@ -70,22 +70,22 @@ typedef union { */ typedef union { struct { - /** filter_ch0_en : R/W; bitpos: [0]; default: 0; + /** filter_chn_en : R/W; bitpos: [0]; default: 0; * Glitch Filter channel enable bit. */ - uint32_t filter_ch0_en:1; - /** filter_ch0_input_io_num : R/W; bitpos: [6:1]; default: 0; + uint32_t filter_chn_en:1; + /** filter_chn_input_io_num : R/W; bitpos: [6:1]; default: 0; * Glitch Filter input io number. */ - uint32_t filter_ch0_input_io_num:6; - /** filter_ch0_window_thres : R/W; bitpos: [12:7]; default: 0; + uint32_t filter_chn_input_io_num:6; + /** filter_chn_window_thres : R/W; bitpos: [12:7]; default: 0; * Glitch Filter window threshold. */ - uint32_t filter_ch0_window_thres:6; - /** filter_ch0_window_width : R/W; bitpos: [18:13]; default: 0; + uint32_t filter_chn_window_thres:6; + /** filter_chn_window_width : R/W; bitpos: [18:13]; default: 0; * Glitch Filter window width. */ - uint32_t filter_ch0_window_width:6; + uint32_t filter_chn_window_width:6; uint32_t reserved_19:13; }; uint32_t val; diff --git a/components/soc/esp32c6/include/soc/io_mux_reg.h b/components/soc/esp32c6/include/soc/io_mux_reg.h index cbba6b20f4..0e255ac519 100644 --- a/components/soc/esp32c6/include/soc/io_mux_reg.h +++ b/components/soc/esp32c6/include/soc/io_mux_reg.h @@ -63,6 +63,11 @@ #define MCU_SEL_M (MCU_SEL_V << MCU_SEL_S) #define MCU_SEL_V 0x7 #define MCU_SEL_S 12 +/* Pin filter (Pulse width shorter than 2 clock cycles will be filtered out) */ +#define FILTER_EN (BIT(15)) +#define FILTER_EN_M (FILTER_EN_V << FILTER_EN_S) +#define FILTER_EN_V 1 +#define FILTER_EN_S 15 #define PIN_SLP_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_IE) #define PIN_SLP_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_IE) @@ -83,6 +88,8 @@ #define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) #define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) #define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_FILTER_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FILTER_EN) +#define PIN_FILTER_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FILTER_EN) #define IO_MUX_GPIO0_REG PERIPHS_IO_MUX_XTAL_32K_P_U #define IO_MUX_GPIO1_REG PERIPHS_IO_MUX_XTAL_32K_N_U diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index e0a5075abf..0f9d99c411 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -150,8 +150,10 @@ /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-C6 has 1 GPIO peripheral -#define SOC_GPIO_PORT (1U) -#define SOC_GPIO_PIN_COUNT (31) +#define SOC_GPIO_PORT 1U +#define SOC_GPIO_PIN_COUNT 31 +#define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1 +#define SOC_GPIO_FLEX_GLITCH_FILTER_NUM 8 // GPIO peripheral has the ETM extension #define SOC_GPIO_SUPPORT_ETM 1 diff --git a/components/soc/esp32h4/include/rev1/soc/io_mux_reg.h b/components/soc/esp32h4/include/rev1/soc/io_mux_reg.h index 62bcd9ac29..45aad3cdb8 100644 --- a/components/soc/esp32h4/include/rev1/soc/io_mux_reg.h +++ b/components/soc/esp32h4/include/rev1/soc/io_mux_reg.h @@ -64,6 +64,11 @@ #define MCU_SEL_M (MCU_SEL_V << MCU_SEL_S) #define MCU_SEL_V 0x7 #define MCU_SEL_S 12 +/* Pin filter (Pulse width shorter than 2 clock cycles will be filtered out) */ +#define FILTER_EN (BIT(15)) +#define FILTER_EN_M (FILTER_EN_V << FILTER_EN_S) +#define FILTER_EN_V 1 +#define FILTER_EN_S 15 #define PIN_SLP_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_IE) #define PIN_SLP_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_IE) @@ -77,14 +82,16 @@ #define PIN_SLP_SEL_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_SEL) -#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); -#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) -#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) -#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); +#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) +#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) +#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_FILTER_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FILTER_EN) +#define PIN_FILTER_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FILTER_EN) #define IO_MUX_GPIO0_REG PERIPHS_IO_MUX_XTAL_32K_P_U #define IO_MUX_GPIO1_REG PERIPHS_IO_MUX_XTAL_32K_N_U diff --git a/components/soc/esp32h4/include/rev2/soc/io_mux_reg.h b/components/soc/esp32h4/include/rev2/soc/io_mux_reg.h index 4182513522..9b5ae4f4dc 100644 --- a/components/soc/esp32h4/include/rev2/soc/io_mux_reg.h +++ b/components/soc/esp32h4/include/rev2/soc/io_mux_reg.h @@ -63,6 +63,11 @@ #define MCU_SEL_M (MCU_SEL_V << MCU_SEL_S) #define MCU_SEL_V 0x7 #define MCU_SEL_S 12 +/* Pin filter (Pulse width shorter than 2 clock cycles will be filtered out) */ +#define FILTER_EN (BIT(15)) +#define FILTER_EN_M (FILTER_EN_V << FILTER_EN_S) +#define FILTER_EN_V 1 +#define FILTER_EN_S 15 #define PIN_SLP_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_IE) #define PIN_SLP_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_IE) @@ -75,14 +80,16 @@ #define PIN_SLP_SEL_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_SEL) #define PIN_SLP_SEL_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_SEL) -#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); -#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) -#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) -#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); +#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) +#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) +#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_FILTER_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FILTER_EN) +#define PIN_FILTER_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FILTER_EN) #define IO_MUX_GPIO0_REG PERIPHS_IO_MUX_GPIO0_U #define IO_MUX_GPIO1_REG PERIPHS_IO_MUX_GPIO1_U diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index b30588649f..3edca105ed 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -271,6 +271,10 @@ config SOC_GPIO_PORT int default 1 +config SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER + bool + default y + config SOC_GPIO_PIN_COUNT int default 41 diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index c990716955..d7772eeed4 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -137,7 +137,9 @@ /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-H4 has 1 GPIO peripheral -#define SOC_GPIO_PORT (1U) +#define SOC_GPIO_PORT 1U +#define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1 + #if CONFIG_IDF_TARGET_ESP32H4_BETA_VERSION_1 #define SOC_GPIO_PIN_COUNT (41) #elif CONFIG_IDF_TARGET_ESP32H4_BETA_VERSION_2 diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index bc7f711550..35e159f3b3 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -283,6 +283,10 @@ config SOC_GPIO_PIN_COUNT int default 47 +config SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER + bool + default y + config SOC_GPIO_SUPPORT_RTC_INDEPENDENT bool default y diff --git a/components/soc/esp32s2/include/soc/io_mux_reg.h b/components/soc/esp32s2/include/soc/io_mux_reg.h index 0ba1eb17ff..18a3da1c64 100644 --- a/components/soc/esp32s2/include/soc/io_mux_reg.h +++ b/components/soc/esp32s2/include/soc/io_mux_reg.h @@ -64,26 +64,33 @@ #define MCU_SEL_M (MCU_SEL_V << MCU_SEL_S) #define MCU_SEL_V 0x7 #define MCU_SEL_S 12 +/* Pin filter (Pulse width shorter than 2 clock cycles will be filtered out) */ +#define FILTER_EN (BIT(15)) +#define FILTER_EN_M (FILTER_EN_V << FILTER_EN_S) +#define FILTER_EN_V 1 +#define FILTER_EN_S 15 -#define PIN_SLP_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_IE) -#define PIN_SLP_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_IE) -#define PIN_SLP_OUTPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_OE) -#define PIN_SLP_OUTPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_OE) -#define PIN_SLP_PULLUP_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_PU) -#define PIN_SLP_PULLUP_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_PU) -#define PIN_SLP_PULLDOWN_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_PD) -#define PIN_SLP_PULLDOWN_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_PD) -#define PIN_SLP_SEL_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_SEL) -#define PIN_SLP_SEL_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_SEL) +#define PIN_SLP_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_IE) +#define PIN_SLP_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_IE) +#define PIN_SLP_OUTPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_OE) +#define PIN_SLP_OUTPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_OE) +#define PIN_SLP_PULLUP_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_PU) +#define PIN_SLP_PULLUP_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_PU) +#define PIN_SLP_PULLDOWN_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_PD) +#define PIN_SLP_PULLDOWN_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_PD) +#define PIN_SLP_SEL_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_SEL) +#define PIN_SLP_SEL_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_SEL) -#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); -#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) -#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) -#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); +#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) +#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) +#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_FILTER_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FILTER_EN) +#define PIN_FILTER_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FILTER_EN) #define IO_MUX_GPIO0_REG PERIPHS_IO_MUX_GPIO0_U #define IO_MUX_GPIO1_REG PERIPHS_IO_MUX_GPIO1_U diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 6470f78a96..9c1c3ee293 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -134,8 +134,9 @@ /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-S2 has 1 GPIO peripheral -#define SOC_GPIO_PORT (1U) -#define SOC_GPIO_PIN_COUNT (47) +#define SOC_GPIO_PORT 1U +#define SOC_GPIO_PIN_COUNT 47 +#define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1 // On ESP32-S2 those PADs which have RTC functions must set pullup/down/capability via RTC register. // On ESP32-S2, Digital IOs have their own registers to control pullup/down/capability, independent with RTC registers. diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index 0338fa1b8a..b2bdf24ccf 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -347,6 +347,10 @@ config SOC_GPIO_PIN_COUNT int default 49 +config SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER + bool + default y + config SOC_GPIO_SUPPORT_RTC_INDEPENDENT bool default y diff --git a/components/soc/esp32s3/include/soc/io_mux_reg.h b/components/soc/esp32s3/include/soc/io_mux_reg.h index e595824e09..b2dfe9eb64 100644 --- a/components/soc/esp32s3/include/soc/io_mux_reg.h +++ b/components/soc/esp32s3/include/soc/io_mux_reg.h @@ -63,6 +63,11 @@ #define MCU_SEL_M (MCU_SEL_V << MCU_SEL_S) #define MCU_SEL_V 0x7 #define MCU_SEL_S 12 +/* Pin filter (Pulse width shorter than 2 clock cycles will be filtered out) */ +#define FILTER_EN (BIT(15)) +#define FILTER_EN_M (FILTER_EN_V << FILTER_EN_S) +#define FILTER_EN_V 1 +#define FILTER_EN_S 15 #define PIN_SLP_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_IE) #define PIN_SLP_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_IE) @@ -75,14 +80,16 @@ #define PIN_SLP_SEL_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_SEL) #define PIN_SLP_SEL_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_SEL) -#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) -#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); -#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) -#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) -#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) +#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); +#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) +#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) +#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) +#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) +#define PIN_FILTER_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FILTER_EN) +#define PIN_FILTER_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FILTER_EN) #define IO_MUX_GPIO0_REG PERIPHS_IO_MUX_GPIO0_U #define IO_MUX_GPIO1_REG PERIPHS_IO_MUX_GPIO1_U diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index b6588bc0ec..de2b9abf02 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -142,8 +142,9 @@ /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-S3 has 1 GPIO peripheral -#define SOC_GPIO_PORT (1U) -#define SOC_GPIO_PIN_COUNT (49) +#define SOC_GPIO_PORT 1U +#define SOC_GPIO_PIN_COUNT 49 +#define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1 // On ESP32-S3, Digital IOs have their own registers to control pullup/down/capability, independent with RTC registers. #define SOC_GPIO_SUPPORT_RTC_INDEPENDENT (1) diff --git a/docs/docs_not_updated/esp32c6.txt b/docs/docs_not_updated/esp32c6.txt index 8b701c1341..da960a70d2 100644 --- a/docs/docs_not_updated/esp32c6.txt +++ b/docs/docs_not_updated/esp32c6.txt @@ -105,7 +105,6 @@ api-reference/peripherals/secure_element api-reference/peripherals/ledc api-reference/peripherals/sdio_slave api-reference/peripherals/clk_tree -api-reference/peripherals/sdm api-reference/peripherals/touch_pad api-reference/peripherals/adc_calibration api-reference/peripherals/ds diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 53ed969f4e..d7a47864e0 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -68,6 +68,7 @@ INPUT = \ $(PROJECT_PATH)/components/driver/include/driver/dedic_gpio.h \ $(PROJECT_PATH)/components/driver/include/driver/gpio.h \ $(PROJECT_PATH)/components/driver/include/driver/gpio_etm.h \ + $(PROJECT_PATH)/components/driver/include/driver/gpio_filter.h \ $(PROJECT_PATH)/components/driver/include/driver/gptimer.h \ $(PROJECT_PATH)/components/driver/include/driver/gptimer_etm.h \ $(PROJECT_PATH)/components/driver/include/driver/gptimer_types.h \ diff --git a/docs/en/api-reference/peripherals/gpio.rst b/docs/en/api-reference/peripherals/gpio.rst index ad89869aa2..744268ac4b 100644 --- a/docs/en/api-reference/peripherals/gpio.rst +++ b/docs/en/api-reference/peripherals/gpio.rst @@ -21,6 +21,36 @@ GPIO Summary :SOC_ULP_SUPPORTED: - The :doc:`Ultra Low Power co-processor <../../api-reference/system/ulp>` is running - Analog functions such as ADC/DAC/etc are in use. + +.. only:: SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER or SOC_GPIO_FLEX_GLITCH_FILTER_NUM + + GPIO Glitch Filter + ------------------ + + The {IDF_TARGET_NAME} chip features hardware filters to remove unwanted glitch pulses from the input GPIO, which can help reduce false triggering of the interrupt and prevent a noise being routed to the peripheral side. + + .. only:: SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER + + Each GPIO can be configured with a glitch filter, which can be used to filter out pulses shorter than **two** sample clock cycles. The duration of the filter is not configurable. The sample clock is the clock source of the IO-MUX. In the driver, we call this kind of filter as "pin glitch filter". You can create the filter handle by calling :cpp:func:`gpio_new_pin_glitch_filter`. All the configurations for a pin glitch filter are listed in the :cpp:type:`gpio_pin_glitch_filter_config_t` structure. + + - :cpp:member:`gpio_pin_glitch_filter_config_t::gpio_num` sets the GPIO number to enable the glitch filter. + + .. only:: SOC_GPIO_FLEX_GLITCH_FILTER_NUM + + {IDF_TARGET_FLEX_GLITCH_FILTER_NUM:default="8"} + + {IDF_TARGET_NAME} provides {IDF_TARGET_FLEX_GLITCH_FILTER_NUM} flexible glitch filters, whose duration is configurable. We refer to this kind of filter as "flex flitch filter". Each of them can be applied to any input GPIO. However, applying multiple filters to the same GPIO doesn't make difference from one. You can create the filter handle by calling :cpp:func:`gpio_new_flex_glitch_filter`. All the configurations for a flexible glitch filter are listed in the :cpp:type:`gpio_flex_glitch_filter_config_t` structure. + + - :cpp:member:`gpio_flex_glitch_filter_config_t::gpio_num` sets the GPIO that will be applied the flex glitch filter. + - :cpp:member:`gpio_flex_glitch_filter_config_t::window_width_ns` and :cpp:member:`gpio_flex_glitch_filter_config_t::window_thres_ns` are the key parameters of the glitch filter. During :cpp:member:`gpio_flex_glitch_filter_config_t::window_width_ns`, any pulse whose width is shorter than :cpp:member:`gpio_flex_glitch_filter_config_t::window_thres_ns` will be discarded. Please note that, you can't set :cpp:member:`gpio_flex_glitch_filter_config_t::window_thres_ns` bigger than :cpp:member:`gpio_flex_glitch_filter_config_t::window_width_ns`. + + .. only:: SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER and SOC_GPIO_FLEX_GLITCH_FILTER_NUM + + Please note, the "pin glitch filter" and "flex glitch filter" are independent. You can enable both of them for the same GPIO. + + The glitch filter is disabled by default, and can be enabled by calling :cpp:func:`gpio_glitch_filter_enable`. To recycle the filter, you can call :cpp:func:`gpio_del_glitch_filter`. Please note, before deleting the filter, you should disable it first by calling :cpp:func:`gpio_glitch_filter_disable`. + + Application Example ------------------- @@ -40,3 +70,11 @@ API Reference - Normal GPIO .. include-build-file:: inc/rtc_io.inc .. include-build-file:: inc/rtc_io_types.inc + + +.. only:: SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER or SOC_GPIO_FLEX_GLITCH_FILTER_NUM + + API Reference - GPIO Glitch Filter + ---------------------------------- + + .. include-build-file:: inc/gpio_filter.inc diff --git a/docs/zh_CN/api-reference/peripherals/gpio.rst b/docs/zh_CN/api-reference/peripherals/gpio.rst index fb25fdc99c..0545b8eeda 100644 --- a/docs/zh_CN/api-reference/peripherals/gpio.rst +++ b/docs/zh_CN/api-reference/peripherals/gpio.rst @@ -21,6 +21,35 @@ GPIO 汇总 :SOC_ULP_SUPPORTED: - :doc:`超低功耗协处理器 (ULP) <../../api-reference/system/ulp>` 运行时 - 使用 ADC/DAC 等模拟功能时 +.. only:: SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER or SOC_GPIO_FLEX_GLITCH_FILTER_NUM + + GPIO 毛刺过滤器 + --------------- + + {IDF_TARGET_NAME} 内置硬件的过滤器可以帮助过滤掉 GPIO 输入端口上的毛刺信号, 这可以一定程度上避免错误地触发中断或者是错把噪声当成有效的外设信号。 + + .. only:: SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER + + 每个 GPIO 都可以使用独立的毛刺过滤器,该过滤器可以将那些脉冲宽度窄于 **2** 个采样时钟的信号剔除掉, 并且这个宽度是无法配置的。GPIO 对输入信号的采样时钟通常是 IO-MUX 的时钟源。在驱动中, 我们将此类过滤器称为 “pin glitch filter“。 你可以调用 :cpp:func:`gpio_new_pin_glitch_filter` 函数来创建一个过滤器句柄。过滤器的相关配置保存在 :cpp:type:`gpio_pin_glitch_filter_config_t` 结构体中。 + + - :cpp:member:`gpio_pin_glitch_filter_config_t::gpio_num` 设置哪个 GPIO 需要开启毛刺过滤器。 + + .. only:: SOC_GPIO_FLEX_GLITCH_FILTER_NUM + + {IDF_TARGET_FLEX_GLITCH_FILTER_NUM:default="8"} + + {IDF_TARGET_NAME} 提供了 {IDF_TARGET_FLEX_GLITCH_FILTER_NUM} 个灵活的毛刺过滤器, 被过滤信号的脉冲宽度可以由软件进行配置。我们称此类过滤器为 "flex flitch filter"。每个过滤器可以分配给任意一个 GPIO, 但是将多个过滤器应用在同一个 GPIO 上并不能带来更好的效果。你可以调用 :cpp:func:`gpio_new_flex_glitch_filter` 函数来创建一个过滤器句柄。过滤器的相关配置保存在 :cpp:type:`gpio_flex_glitch_filter_config_t` 结构体中。 + + - :cpp:member:`gpio_flex_glitch_filter_config_t::gpio_num` 设置哪个 GPIO 需要使用毛刺过滤器。 + - :cpp:member:`gpio_flex_glitch_filter_config_t::window_width_ns` 和 :cpp:member:`gpio_flex_glitch_filter_config_t::window_thres_ns` 是毛刺过滤器的关键参数。在:cpp:member:`gpio_flex_glitch_filter_config_t::window_width_ns` 时间内,任何脉冲信号,如果它的宽度小于 :cpp:member:`gpio_flex_glitch_filter_config_t::window_thres_ns`, 那么该脉冲信号就会被滤除掉。:cpp:member:`gpio_flex_glitch_filter_config_t::window_thres_ns` 的值不能大于 :cpp:member:`gpio_flex_glitch_filter_config_t::window_width_ns`。 + + .. only:: SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER and SOC_GPIO_FLEX_GLITCH_FILTER_NUM + + 请注意, "pin glitch filter" 和 "flex glitch filter" 是各自独立的,你可以给同一个 GPIO 同时启用他们两种滤波器。 + + 毛刺滤波器默认情况下是处于关闭状态的, 你需要调用 :cpp:func:`gpio_glitch_filter_enable` 去使能它。如果要回收这个过滤器,你可以调用 :cpp:func:`gpio_del_glitch_filter` 函数。注意, 在你回收过滤器句柄之前, 请确保它是处于关闭状态的,如果不是,你需要调用 :cpp:func:`gpio_glitch_filter_disable`。 + + 应用示例 ------------------- @@ -40,3 +69,10 @@ API 参考 - 普通 GPIO .. include-build-file:: inc/rtc_io.inc .. include-build-file:: inc/rtc_io_types.inc + +.. only:: SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER or SOC_GPIO_FLEX_GLITCH_FILTER_NUM + + API 参考 - GPIO 毛刺过滤器 + -------------------------- + + .. include-build-file:: inc/gpio_filter.inc