gpio: h2 support input hysteresis filter

pull/10828/head
wanlei 2023-02-20 18:48:47 +08:00
rodzic c88efb7fa8
commit c9bcec9212
14 zmienionych plików z 259 dodań i 12 usunięć

Wyświetl plik

@ -239,6 +239,26 @@ int gpio_get_level(gpio_num_t gpio_num)
return gpio_hal_get_level(gpio_context.gpio_hal, gpio_num);
}
#if SOC_GPIO_SUPPORT_PIN_HYS_FILTER
static esp_err_t gpio_hysteresis_enable(gpio_num_t gpio_num)
{
gpio_hal_hysteresis_soft_enable(gpio_context.gpio_hal, gpio_num, true);
return ESP_OK;
}
static esp_err_t gpio_hysteresis_disable(gpio_num_t gpio_num)
{
gpio_hal_hysteresis_soft_enable(gpio_context.gpio_hal, gpio_num, false);
return ESP_OK;
}
static esp_err_t gpio_hysteresis_by_efuse(gpio_num_t gpio_num)
{
gpio_hal_hysteresis_from_efuse(gpio_context.gpio_hal, gpio_num);
return ESP_OK;
}
#endif //SOC_GPIO_SUPPORT_PIN_HYS_FILTER
esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
@ -386,6 +406,15 @@ esp_err_t gpio_config(const gpio_config_t *pGPIOConfig)
gpio_intr_disable(io_num);
}
#if SOC_GPIO_SUPPORT_PIN_HYS_FILTER
if (pGPIOConfig->hys_ctrl_mode == GPIO_HYS_SOFT_ENABLE) {
gpio_hysteresis_enable(io_num);
} else if (pGPIOConfig->hys_ctrl_mode == GPIO_HYS_SOFT_DISABLE) {
gpio_hysteresis_disable(io_num);
} else {
gpio_hysteresis_by_efuse(io_num);
}
#endif //SOC_GPIO_SUPPORT_PIN_HYS_FILTER
/* By default, all the pins have to be configured as GPIO pins. */
gpio_hal_iomux_func_sel(io_reg, PIN_FUNC_GPIO);
}

Wyświetl plik

@ -48,6 +48,9 @@ typedef struct {
gpio_pullup_t pull_up_en; /*!< GPIO pull-up */
gpio_pulldown_t pull_down_en; /*!< GPIO pull-down */
gpio_int_type_t intr_type; /*!< GPIO interrupt type */
#if SOC_GPIO_SUPPORT_PIN_HYS_FILTER
gpio_hys_ctrl_mode_t hys_ctrl_mode; /*!< GPIO hysteresis: hysteresis filter on slope input */
#endif
} gpio_config_t;
/**

Wyświetl plik

@ -12,6 +12,10 @@ if(CONFIG_SOC_SDM_SUPPORTED)
list(APPEND srcs "test_sdm.c")
endif()
if(CONFIG_SOC_GPIO_SUPPORT_PIN_HYS_FILTER)
list(APPEND srcs "test_hysteresis.c")
endif()
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}

Wyświetl plik

@ -1,26 +1,19 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "unity_test_utils.h"
#include "esp_heap_caps.h"
// Some resources are lazy allocated in the driver, the threshold is left for that case
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
#define TEST_MEMORY_LEAK_THRESHOLD (300)
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);
@ -31,8 +24,9 @@ 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");
printf("\n");
unity_utils_check_leak(before_free_8bit, after_free_8bit, "8BIT", TEST_MEMORY_LEAK_THRESHOLD);
unity_utils_check_leak(before_free_32bit, after_free_32bit, "32BIT", TEST_MEMORY_LEAK_THRESHOLD);
}
void app_main(void)

Wyświetl plik

@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "unity.h"
#include "driver/gpio.h"
/**
* NOTE: To run this special feature test case, a slope analog signal is needed.
* A simple RC circuit used here to formate pin switches to continuos slop signal.
*
* +---------+
* | |
* | (intr)26|----------------+ C:1000uF
* | | | ++ +
* | (wave)27|______+-----+___+___|| |_____
* | | +-----+ || | |
* | ESP32 | R:10k ++ + |
* | | |
* | GND|------------------------------+
* +---------+
*
* or you can connect your slop signals from signal generator to ESP32 pin
* which enabled the hysteresis feature directly to have a test.
**/
static void test_gpio_hysteresis_intr_handler(void *args)
{
esp_rom_printf("%d\n", ++*((uint32_t *)args));
}
// This case is now tested only manually
TEST_CASE("GPIO Input hysteresis filter", "[gpio_filter][timeout=50][ignore]")
{
const gpio_num_t TEST_HYS_IO = 26;
const gpio_num_t TEST_WAVE_IO = 27;
uint32_t intr_cnt=0;
gpio_config_t gpio_cfg = {
.pin_bit_mask = 1 << TEST_WAVE_IO,
.mode = GPIO_MODE_OUTPUT,
.pull_down_en = GPIO_PULLDOWN_ENABLE,
};
TEST_ESP_OK(gpio_config(&gpio_cfg));
gpio_cfg.pin_bit_mask = 1 << TEST_HYS_IO;
gpio_cfg.mode = GPIO_MODE_INPUT;
gpio_cfg.intr_type = GPIO_INTR_ANYEDGE;
gpio_cfg.hys_ctrl_mode = GPIO_HYS_SOFT_ENABLE;
TEST_ESP_OK(gpio_config(&gpio_cfg));
gpio_install_isr_service(0);
gpio_isr_handler_add(TEST_HYS_IO, test_gpio_hysteresis_intr_handler, &intr_cnt);
// generate 5 rising and falling slopes to test gpio interrupt
for (uint8_t i=0; i<5; i++) {
printf("----falling %dth\n", i);
gpio_set_level(TEST_WAVE_IO, 0);
vTaskDelay(1500);
printf("----rising %dth\n", i);
gpio_set_level(TEST_WAVE_IO, 1);
vTaskDelay(1500);
}
gpio_isr_handler_remove(TEST_HYS_IO);
gpio_uninstall_isr_service();
// should shot ISR exactly 10 times
TEST_ASSERT_UINT32_WITHIN(1, 10, intr_cnt);
}

Wyświetl plik

@ -226,6 +226,50 @@ 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 Select gpio hysteresis control by efuse.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pin_input_hysteresis_ctrl_sel_efuse(gpio_dev_t *hw, uint32_t gpio_num)
{
PIN_HYS_EN_SEL_EFUSE(IO_MUX_GPIO0_REG + (gpio_num * 4));
}
/**
* @brief Select gpio hysteresis control by software.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pin_input_hysteresis_ctrl_sel_soft(gpio_dev_t *hw, uint32_t gpio_num)
{
PIN_HYS_EN_SEL_SOFT(IO_MUX_GPIO0_REG + (gpio_num * 4));
}
/**
* @brief Enable gpio hysteresis if controlled by software.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pin_input_hysteresis_enable(gpio_dev_t *hw, uint32_t gpio_num)
{
PIN_HYS_SOFT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
}
/**
* @brief Disable gpio hysteresis if controlled by software.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pin_input_hysteresis_disable(gpio_dev_t *hw, uint32_t gpio_num)
{
PIN_HYS_SOFT_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
}
/**
* @brief Disable output mode on GPIO.
*

Wyświetl plik

@ -29,3 +29,16 @@ void gpio_hal_intr_disable(gpio_hal_context_t *hal, uint32_t gpio_num)
gpio_ll_clear_intr_status_high(hal->dev, BIT(gpio_num - 32));
}
}
#if SOC_GPIO_SUPPORT_PIN_HYS_FILTER
void gpio_hal_hysteresis_soft_enable(gpio_hal_context_t *hal, uint32_t gpio_num, bool enable)
{
if (enable) {
gpio_ll_pin_input_hysteresis_ctrl_sel_soft(hal->dev, gpio_num);
gpio_ll_pin_input_hysteresis_enable(hal->dev, gpio_num);
} else {
gpio_ll_pin_input_hysteresis_ctrl_sel_soft(hal->dev, gpio_num);
gpio_ll_pin_input_hysteresis_disable(hal->dev, gpio_num);
}
}
#endif //SOC_GPIO_SUPPORT_PIN_HYS_FILTER

Wyświetl plik

@ -485,6 +485,25 @@ void gpio_hal_sleep_pupd_config_unapply(gpio_hal_context_t *hal, uint32_t gpio_n
*/
#define gpio_hal_iomux_func_sel(pin_name, func) gpio_ll_iomux_func_sel(pin_name, func)
#if SOC_GPIO_SUPPORT_PIN_HYS_FILTER
/**
* @brief Control gpio hysteresis enable/disable by software.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
* @param enable enable or disable the hysteresis
*/
void gpio_hal_hysteresis_soft_enable(gpio_hal_context_t *hal, uint32_t gpio_num, bool enable);
/**
* @brief Set gpio hysteresis enable/disable by efuse.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_hysteresis_from_efuse(hal, gpio_num) gpio_ll_pin_input_hysteresis_ctrl_sel_efuse((hal)->dev, gpio_num)
#endif // SOC_GPIO_SUPPORT_PIN_HYS_FILTER
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -473,6 +473,15 @@ typedef enum {
GPIO_DRIVE_CAP_MAX,
} gpio_drive_cap_t;
/**
* @brief Available option for configuring hysteresis feature of GPIOs
*/
typedef enum {
GPIO_HYS_CTRL_EFUSE = 0, /*!< Pad input hysteresis ctrl by efuse */
GPIO_HYS_SOFT_ENABLE = 1, /*!< Pad input hysteresis enable by software */
GPIO_HYS_SOFT_DISABLE = 2, /*!< Pad input hysteresis disable by software */
} gpio_hys_ctrl_mode_t;
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -303,6 +303,10 @@ config SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER
bool
default y
config SOC_GPIO_SUPPORT_PIN_HYS_FILTER
bool
default y
config SOC_GPIO_FLEX_GLITCH_FILTER_NUM
int
default 8

Wyświetl plik

@ -69,6 +69,24 @@
#define FILTER_EN_V 1
#define FILTER_EN_S 15
/* HYS_EN : R/W; bitpos: [16]; default: 0;
* Software enables hysteresis function for the pad.
* 1: Hysteresis enabled. 0: Hysteresis disabled.
*/
#define HYS_EN (BIT(16))
#define HYS_EN_M (HYS_EN_V << HYS_EN_S)
#define HYS_EN_V 0x00000001
#define HYS_EN_S 16
/* HYS_SEL : R/W; bitpos: [17]; default: 0;
* Select enabling signals of the pad from software and efuse hardware.
* 1: Select enabling siganl from software.
* 0: Select enabling signal from efuse hardware.
*/
#define HYS_SEL (BIT(17))
#define HYS_SEL_M (HYS_SEL_V << HYS_SEL_S)
#define HYS_SEL_V 0x00000001
#define HYS_SEL_S 17
#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)
@ -90,6 +108,10 @@
#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 PIN_HYS_EN_SEL_EFUSE(PIN_NAME) REG_CLR_BIT(PIN_NAME, HYS_SEL)
#define PIN_HYS_EN_SEL_SOFT(PIN_NAME) REG_SET_BIT(PIN_NAME, HYS_SEL)
#define PIN_HYS_SOFT_ENABLE(PIN_NAME) REG_SET_BIT(PIN_NAME, HYS_EN)
#define PIN_HYS_SOFT_DISABLE(PIN_NAME) REG_CLR_BIT(PIN_NAME, HYS_EN)
#define IO_MUX_GPIO0_REG PERIPHS_IO_MUX_GPIO0_U
#define IO_MUX_GPIO1_REG PERIPHS_IO_MUX_GPIO1_U

Wyświetl plik

@ -156,6 +156,7 @@
#define SOC_GPIO_PORT 1U
#define SOC_GPIO_PIN_COUNT 28
#define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1
#define SOC_GPIO_SUPPORT_PIN_HYS_FILTER 1
#define SOC_GPIO_FLEX_GLITCH_FILTER_NUM 8
// GPIO peripheral has the ETM extension

Wyświetl plik

@ -21,6 +21,7 @@ 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
@ -50,6 +51,20 @@ GPIO Summary
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`.
.. only:: SOC_GPIO_SUPPORT_PIN_HYS_FILTER
GPIO Hysteresis Filter
----------------------
{IDF_TARGET_NAME} support the hardware hysteresis of the input pin, which can reduce the GPIO interrupt shoot by accident due to unstable sampling when the input voltage is near the critical of logic 0 and 1, especially when the input logic level conversion is slow or the voltage setup time is too long.
Each pin can enable hysteresis function independently. By default, it controlled by eFuse and been closed, but it can also be enabled or disabled by software manually. You can select the hysteresis control mode by configuring :cpp:member:`gpio_config_t::hys_ctrl_mode`.
.. note::
When the hysteresis function is controlled by eFuse, this feature can still be controlled independently for each pin, you need to `burn the eFuse <https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html>`_ to enable the hysteresis function on specific GPIO additionally.
Application Example
-------------------

Wyświetl plik

@ -21,6 +21,7 @@ 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 毛刺过滤器
@ -50,6 +51,20 @@ GPIO 汇总
毛刺过滤器默认关闭,可调用 :cpp:func:`gpio_glitch_filter_enable` 使能过滤器。如需回收这个过滤器,可以调用 :cpp:func:`gpio_del_glitch_filter` 函数。在回收句柄前,请确保过滤器处于关闭状态,否则需调用 :cpp:func:`gpio_glitch_filter_disable`
.. only:: SOC_GPIO_SUPPORT_PIN_HYS_FILTER
GPIO 迟滞过滤器
---------------
{IDF_TARGET_NAME} 支持输入引脚的硬件迟滞,这可以减少由于输入电压在逻辑 0、1 临界值附近时采样不稳定造成的 GPIO 中断误触,尤其是当输入逻辑电平转换较慢,电平建立时间较长时。
每个引脚可以独立启用迟滞功能。默认情况下,它由 eFuse 控制,且处于关闭状态,但也可以由软件控制启用或禁用。您可以通过配置 :cpp:member:`gpio_config_t::hys_ctrl_mode` 来选择迟滞控制模式。
.. note::
当迟滞功能由 eFuse 控制时,仍然可以独立的控制每个引脚的该功能,您需要 `烧断 eFuse <https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html>`_ ,以在特定 GPIO上 启用迟滞功能。
应用示例
-------------------