From eb7ccbd174b53b7ba1079f40ab10b19b6e7d1e98 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 13 Feb 2023 16:52:10 +0800 Subject: [PATCH 1/5] hal: added analog comparator's LL driver --- components/hal/CMakeLists.txt | 4 + components/hal/analog_cmpr_hal.c | 13 ++ .../hal/esp32h2/include/hal/analog_cmpr_ll.h | 172 ++++++++++++++++++ components/hal/include/hal/analog_cmpr_hal.h | 37 ++++ .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32h2/include/soc/gpio_ext_struct.h | 5 + components/soc/esp32h2/include/soc/soc_caps.h | 1 + .../soc/esp32h2/ld/esp32h2.peripherals.ld | 1 + 8 files changed, 237 insertions(+) create mode 100644 components/hal/analog_cmpr_hal.c create mode 100644 components/hal/esp32h2/include/hal/analog_cmpr_ll.h create mode 100644 components/hal/include/hal/analog_cmpr_hal.h diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index a944c360b3..6fdfa36008 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -97,6 +97,10 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "sdm_hal.c") endif() + if(CONFIG_SOC_ANALOG_CMPR_SUPPORTED) + list(APPEND srcs "analog_cmpr_hal.c") + endif() + if(CONFIG_ETH_USE_ESP32_EMAC) list(APPEND srcs "emac_hal.c") endif() diff --git a/components/hal/analog_cmpr_hal.c b/components/hal/analog_cmpr_hal.c new file mode 100644 index 0000000000..a9c4cc8e79 --- /dev/null +++ b/components/hal/analog_cmpr_hal.c @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "hal/analog_cmpr_ll.h" +#include "hal/analog_cmpr_hal.h" + +void analog_cmpr_hal_init(analog_cmpr_hal_context_t *hal) +{ + hal->dev = ANALOG_CMPR_LL_GET_HW(); +} diff --git a/components/hal/esp32h2/include/hal/analog_cmpr_ll.h b/components/hal/esp32h2/include/hal/analog_cmpr_ll.h new file mode 100644 index 0000000000..e60a03961c --- /dev/null +++ b/components/hal/esp32h2/include/hal/analog_cmpr_ll.h @@ -0,0 +1,172 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "soc/gpio_ext_struct.h" + +#define ANALOG_CMPR_LL_GET_HW() (&ANALOG_CMPR) +#define ANALOG_CMPR_LL_EVENT_CROSS (1 << 0) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Enable analog comparator + * + * @param hw Analog comparator register base address + * @param en True to enable, False to disable + */ +static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en) +{ + hw->pad_comp_config.xpd_comp = en; +} + +/** + * @brief Set the voltage of the internal reference + * + * @param hw Analog comparator register base address + * @param voltage The voltage of the internal reference, range [0.0V, 0.7VDD], step 0.1VDD + */ +static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw, float voltage) +{ + hw->pad_comp_config.mode_comp = 0; + uint32_t volt_reg_val = (uint32_t)((voltage + 0.05F) / 0.1F); + HAL_ASSERT(volt_reg_val <= 7); + hw->pad_comp_config.dref_comp = volt_reg_val; +} + +/** + * @brief Get the voltage of the internal reference + * + * @param hw Analog comparator register base address + * @return The voltage of the internal reference + */ +static inline float analog_cmpr_ll_get_internal_ref_voltage(analog_cmpr_dev_t *hw) +{ + return hw->pad_comp_config.dref_comp * 0.1F; +} + +/** + * @brief The reference voltage comes from GPIO pad (GPIO10) + * + * @note Also see `analog_cmpr_ll_set_internal_ref_voltage` to use the internal reference voltage + * + * @param hw Analog comparator register base address + */ +static inline void analog_cmpr_ll_ref_voltage_from_external(analog_cmpr_dev_t *hw) +{ + hw->pad_comp_config.mode_comp = 1; +} + +/** + * @brief Disable the cross detection + * + * @param hw Analog comparator register base address + */ +static inline void analog_cmpr_ll_disable_cross_detection(analog_cmpr_dev_t *hw) +{ + hw->pad_comp_config.zero_det_mode = 0; +} + +/** + * @brief Enable to detect the positive cross (input analog goes from low to high and across the reference voltage) + * + * @param hw Analog comparator register base address + * @param enable True to enable, False to disable + */ +static inline void analog_cmpr_ll_enable_pos_cross_detection(analog_cmpr_dev_t *hw, bool enable) +{ + if (enable) { + hw->pad_comp_config.zero_det_mode |= (1 << 0); + } else { + hw->pad_comp_config.zero_det_mode &= ~(1 << 0); + } +} + +/** + * @brief Enable to detect the negative cross (input analog goes from high to low and across the reference voltage) + * + * @param hw Analog comparator register base address + * @param enable True to enable, False to disable + */ +static inline void analog_cmpr_ll_enable_neg_cross_detection(analog_cmpr_dev_t *hw, bool enable) +{ + if (enable) { + hw->pad_comp_config.zero_det_mode |= (1 << 1); + } else { + hw->pad_comp_config.zero_det_mode &= ~(1 << 1); + } +} + +/** + * @brief Set the debounce cycle for the cross detection + * + * @note When the comparator detects a cross, it will wait for the debounce cycle to make sure the cross is stable. + * + * @param hw Analog comparator register base address + * @param cycle The debounce cycle + */ +static inline void analog_cmpr_ll_set_debounce_cycle(analog_cmpr_dev_t *hw, uint32_t cycle) +{ + hw->pad_comp_filter.zero_det_filter_cnt = cycle; +} + +/** + * @brief Enable comparator interrupt + * + * @param hw Analog comparator register base address + * @param mask Interrupt mask + * @param enable True to enable, False to disable + */ +static inline void analog_cmpr_ll_enable_intr(analog_cmpr_dev_t *hw, uint32_t mask, bool enable) +{ + if (enable) { + hw->int_ena.val |= mask; + } else { + hw->int_ena.val &= ~mask; + } +} + +/** + * @brief Get comparator interrupt status + * + * @param hw Analog comparator register base address + */ +static inline void analog_cmpr_ll_get_intr_status(analog_cmpr_dev_t *hw) +{ + hw->int_st.val; +} + +/** + * @brief Clear comparator interrupt status + * + * @param hw Analog comparator register base address + * @param mask Interrupt status word + */ +static inline void analog_cmpr_ll_clear_intr(analog_cmpr_dev_t *hw, uint32_t mask) +{ + hw->int_clr.val = mask; +} + +/** + * @brief Get the interrupt status register address + * + * @param hw Analog comparator register base address + * @return The interrupt status register address + */ +static inline volatile void *analog_cmpr_ll_get_intr_status_reg(analog_cmpr_dev_t *hw) +{ + return &hw->int_st; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/analog_cmpr_hal.h b/components/hal/include/hal/analog_cmpr_hal.h new file mode 100644 index 0000000000..01d81ff1c0 --- /dev/null +++ b/components/hal/include/hal/analog_cmpr_hal.h @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: 2023 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 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct analog_cmpr_dev_t *analog_cmpr_handle_t; // Analog comparator SOC layer handle + +/** + * HAL context type of analog comparator driver + */ +typedef struct { + analog_cmpr_handle_t dev; +} analog_cmpr_hal_context_t; + +/** + * @brief Initialize Analog comparator hal driver + * + * @param hal Context of the HAL layer + */ +void analog_cmpr_hal_init(analog_cmpr_hal_context_t *hal); + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index d342077dd8..25095ba7d5 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -83,6 +83,10 @@ config SOC_SDM_SUPPORTED bool default y +config SOC_ANALOG_CMPR_SUPPORTED + bool + default y + config SOC_ETM_SUPPORTED bool default y diff --git a/components/soc/esp32h2/include/soc/gpio_ext_struct.h b/components/soc/esp32h2/include/soc/gpio_ext_struct.h index 10786e703c..815d6d9e5e 100644 --- a/components/soc/esp32h2/include/soc/gpio_ext_struct.h +++ b/components/soc/esp32h2/include/soc/gpio_ext_struct.h @@ -305,10 +305,15 @@ typedef struct { volatile gpio_ext_version_reg_t version; } gpio_ext_dev_t; +// analog comparator is a stand alone peripheral, but it is connected to GPIO +// so we rename it to analog_cmpr_dev_t from user's perspective +typedef gpio_ext_dev_t analog_cmpr_dev_t; + extern gpio_sd_dev_t SDM; extern gpio_glitch_filter_dev_t GLITCH_FILTER; extern gpio_etm_dev_t GPIO_ETM; extern gpio_ext_dev_t GPIO_EXT; +extern analog_cmpr_dev_t ANALOG_CMPR; #ifndef __cplusplus _Static_assert(sizeof(gpio_ext_dev_t) == 0x100, "Invalid size of gpio_ext_dev_t structure"); diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index abb72b6a14..2614da02ae 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -45,6 +45,7 @@ #define SOC_RTC_MEM_SUPPORTED 1 #define SOC_I2S_SUPPORTED 1 #define SOC_SDM_SUPPORTED 1 +#define SOC_ANALOG_CMPR_SUPPORTED 1 #define SOC_ETM_SUPPORTED 1 #define SOC_RMT_SUPPORTED 1 #define SOC_PARLIO_SUPPORTED 1 diff --git a/components/soc/esp32h2/ld/esp32h2.peripherals.ld b/components/soc/esp32h2/ld/esp32h2.peripherals.ld index c6927ba776..4d24b46d2c 100644 --- a/components/soc/esp32h2/ld/esp32h2.peripherals.ld +++ b/components/soc/esp32h2/ld/esp32h2.peripherals.ld @@ -44,6 +44,7 @@ PROVIDE ( HMAC = 0x6008D000 ); PROVIDE ( IO_MUX = 0x60090000 ); PROVIDE ( GPIO = 0x60091000 ); PROVIDE ( GPIO_EXT = 0x60091f00 ); +PROVIDE ( ANALOG_CMPR = 0x60091f00 ); PROVIDE ( SDM = 0x60091f00 ); PROVIDE ( GLITCH_FILTER = 0x60091f30 ); PROVIDE ( GPIO_ETM = 0x60091f60 ); From 11cdbf2da0b031b0746f8f7f1f5e1cf09a2d5aae Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 14 Feb 2023 18:44:13 +0800 Subject: [PATCH 2/5] driver: added analog comparator driver --- .../analog_cmpr/include/driver/analog_cmpr.h | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 components/driver/analog_cmpr/include/driver/analog_cmpr.h diff --git a/components/driver/analog_cmpr/include/driver/analog_cmpr.h b/components/driver/analog_cmpr/include/driver/analog_cmpr.h new file mode 100644 index 0000000000..d5a2fc456c --- /dev/null +++ b/components/driver/analog_cmpr/include/driver/analog_cmpr.h @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "esp_err.h" + +typedef struct analog_cmpr_t *analog_cmpr_handle_t; +typedef struct analog_cmpr_ref_voltage_t *analog_cmpr_ref_voltage_handle_t; + +typedef struct { + analog_cmpr_ref_voltage_handle_t ref_volt; + struct { + uint32_t detect_pos: 1; + uint32_t detect_neg: 1; + } flags; +} analog_cmpr_config_t; + +esp_err_t analog_cmpr_new_unit(const analog_cmpr_config_t *config, analog_cmpr_handle_t *ret_cmpr); + +typedef struct { + float ref_voltage; +} analog_cmpr_internal_ref_voltage_config_t; + +typedef struct { + int ref_volt_gpio_num; +} analog_cmpr_gpio_ref_voltage_config_t; + +esp_err_t analog_cmpr_new_gpio_ref_voltage(const analog_cmpr_gpio_ref_voltage_config_t *config, analog_cmpr_ref_voltage_handle_t *ret_ref_volt); + +esp_err_t analog_cmpr_new_internal_ref_voltage(const analog_cmpr_internal_ref_voltage_config_t *config, analog_cmpr_ref_voltage_handle_t *ret_ref_volt); + +typedef struct { + +} analog_cmpr_cross_event_data_t; + +typedef bool (*analog_cmpr_cross_cb_t) (analog_cmpr_handle_t cmpr, const analog_cmpr_cross_event_data_t *edata, void *user_ctx); + +typedef struct { + analog_cmpr_cross_cb_t on_cross; +} analog_cmpr_event_callbacks_t; + +esp_err_t analog_cmpr_register_event_callbacks(analog_cmpr_handle_t cmpr, const analog_cmpr_event_callbacks_t *cbs, void *user_data); + +typedef struct { + +} analog_cmpr_debounce_filter_config_t; + +esp_err_t analog_cmpr_set_debounce_filter(analog_cmpr_handle_t cmpr, const analog_cmpr_debounce_filter_config_t *config); + +esp_err_t analog_cmpr_enable(analog_cmpr_handle_t cmpr); +esp_err_t analog_cmpr_disable(analog_cmpr_handle_t cmpr); From c634144ac8d8fa796d0809d63a8c8cb819e64d6c Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Wed, 1 Mar 2023 19:50:45 +0800 Subject: [PATCH 3/5] ana_cmpr: designed driver layer --- components/driver/CMakeLists.txt | 6 + components/driver/Kconfig | 25 ++ .../analog_cmpr/include/driver/analog_cmpr.h | 54 ---- .../driver/analog_comparator/ana_cmpr.c | 299 ++++++++++++++++++ .../include/driver/ana_cmpr.h | 169 ++++++++++ .../include/driver/ana_cmpr_types.h | 109 +++++++ components/driver/linker.lf | 3 + components/hal/CMakeLists.txt | 4 - components/hal/analog_cmpr_hal.c | 13 - .../hal/{analog_cmpr_ll.h => ana_cmpr_ll.h} | 68 ++-- components/hal/include/hal/analog_cmpr_hal.h | 37 --- components/soc/CMakeLists.txt | 4 + components/soc/esp32h2/ana_cmpr_periph.c | 14 + .../esp32h2/include/soc/Kconfig.soc_caps.in | 8 + .../esp32h2/include/soc/ana_cmpr_channel.h | 10 + .../soc/esp32h2/include/soc/clk_tree_defs.h | 16 + .../soc/esp32h2/include/soc/gpio_ext_struct.h | 4 +- components/soc/esp32h2/include/soc/soc_caps.h | 4 + components/soc/include/soc/ana_cmpr_periph.h | 26 ++ .../main/dac_cosine_example_main.c | 2 +- 20 files changed, 718 insertions(+), 157 deletions(-) delete mode 100644 components/driver/analog_cmpr/include/driver/analog_cmpr.h create mode 100644 components/driver/analog_comparator/ana_cmpr.c create mode 100644 components/driver/analog_comparator/include/driver/ana_cmpr.h create mode 100644 components/driver/analog_comparator/include/driver/ana_cmpr_types.h delete mode 100644 components/hal/analog_cmpr_hal.c rename components/hal/esp32h2/include/hal/{analog_cmpr_ll.h => ana_cmpr_ll.h} (60%) delete mode 100644 components/hal/include/hal/analog_cmpr_hal.h create mode 100644 components/soc/esp32h2/ana_cmpr_periph.c create mode 100644 components/soc/esp32h2/include/soc/ana_cmpr_channel.h create mode 100644 components/soc/include/soc/ana_cmpr_periph.h diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 3b3a7f28ba..564814091f 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -10,6 +10,7 @@ set(srcs # Always included headers set(includes "include" "deprecated" + "analog_comparator/include" "dac/include" "gpio/include" "gptimer/include" @@ -39,6 +40,11 @@ if(CONFIG_SOC_ADC_DMA_SUPPORTED) list(APPEND srcs "deprecated/adc_dma_legacy.c") endif() +# Analog comparator related source files +if(CONFIG_SOC_ANA_CMPR_SUPPORTED) + list(APPEND srcs "analog_comparator/ana_cmpr.c") +endif() + # DAC related source files if(CONFIG_SOC_DAC_SUPPORTED) list(APPEND srcs "dac/dac_oneshot.c" diff --git a/components/driver/Kconfig b/components/driver/Kconfig index e458b50922..4195b5979d 100644 --- a/components/driver/Kconfig +++ b/components/driver/Kconfig @@ -274,6 +274,31 @@ menu "Driver Configurations" Note that, this option only controls the SDM driver log, won't affect other drivers. endmenu # Sigma Delta Modulator Configuration + menu "Analog Comparator Configuration" + depends on SOC_ANA_CMPR_SUPPORTED + config ANA_CMPR_ISR_IRAM_SAFE + bool "Analog comparator ISR IRAM-Safe" + default n + help + Ensure the Analog Comparator interrupt is IRAM-Safe by allowing the interrupt handler to be + executable when the cache is disabled (e.g. SPI Flash write). + + config ANA_CMPR_CTRL_FUNC_IN_IRAM + bool "Place Analog Comparator control functions into IRAM" + default n + help + Place Analog Comparator control functions (like set_intl_reference) into IRAM, + so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context. + Enabling this option can improve driver performance as well. + + config ANA_CMPR_ENABLE_DEBUG_LOG + bool "Enable debug log" + default n + help + Wether to enable the debug log message for Analog Comparator driver. + Note that, this option only controls the Analog Comparator driver log, won't affect other drivers. + endmenu # Analog Comparator Configuration + menu "GPTimer Configuration" config GPTIMER_CTRL_FUNC_IN_IRAM bool "Place GPTimer control functions into IRAM" diff --git a/components/driver/analog_cmpr/include/driver/analog_cmpr.h b/components/driver/analog_cmpr/include/driver/analog_cmpr.h deleted file mode 100644 index d5a2fc456c..0000000000 --- a/components/driver/analog_cmpr/include/driver/analog_cmpr.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include "esp_err.h" - -typedef struct analog_cmpr_t *analog_cmpr_handle_t; -typedef struct analog_cmpr_ref_voltage_t *analog_cmpr_ref_voltage_handle_t; - -typedef struct { - analog_cmpr_ref_voltage_handle_t ref_volt; - struct { - uint32_t detect_pos: 1; - uint32_t detect_neg: 1; - } flags; -} analog_cmpr_config_t; - -esp_err_t analog_cmpr_new_unit(const analog_cmpr_config_t *config, analog_cmpr_handle_t *ret_cmpr); - -typedef struct { - float ref_voltage; -} analog_cmpr_internal_ref_voltage_config_t; - -typedef struct { - int ref_volt_gpio_num; -} analog_cmpr_gpio_ref_voltage_config_t; - -esp_err_t analog_cmpr_new_gpio_ref_voltage(const analog_cmpr_gpio_ref_voltage_config_t *config, analog_cmpr_ref_voltage_handle_t *ret_ref_volt); - -esp_err_t analog_cmpr_new_internal_ref_voltage(const analog_cmpr_internal_ref_voltage_config_t *config, analog_cmpr_ref_voltage_handle_t *ret_ref_volt); - -typedef struct { - -} analog_cmpr_cross_event_data_t; - -typedef bool (*analog_cmpr_cross_cb_t) (analog_cmpr_handle_t cmpr, const analog_cmpr_cross_event_data_t *edata, void *user_ctx); - -typedef struct { - analog_cmpr_cross_cb_t on_cross; -} analog_cmpr_event_callbacks_t; - -esp_err_t analog_cmpr_register_event_callbacks(analog_cmpr_handle_t cmpr, const analog_cmpr_event_callbacks_t *cbs, void *user_data); - -typedef struct { - -} analog_cmpr_debounce_filter_config_t; - -esp_err_t analog_cmpr_set_debounce_filter(analog_cmpr_handle_t cmpr, const analog_cmpr_debounce_filter_config_t *config); - -esp_err_t analog_cmpr_enable(analog_cmpr_handle_t cmpr); -esp_err_t analog_cmpr_disable(analog_cmpr_handle_t cmpr); diff --git a/components/driver/analog_comparator/ana_cmpr.c b/components/driver/analog_comparator/ana_cmpr.c new file mode 100644 index 0000000000..c042455668 --- /dev/null +++ b/components/driver/analog_comparator/ana_cmpr.c @@ -0,0 +1,299 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "sdkconfig.h" +#if CONFIG_SDM_ENABLE_DEBUG_LOG +// The local log level must be defined before including esp_log.h +// Set the maximum log level for this source file +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#endif +#include "freertos/FreeRTOS.h" +#include "clk_tree.h" +#include "esp_types.h" +#include "esp_attr.h" +#include "esp_check.h" +#include "esp_pm.h" +#include "esp_heap_caps.h" +#include "esp_intr_alloc.h" +#include "soc/periph_defs.h" +#include "soc/ana_cmpr_periph.h" +#include "hal/ana_cmpr_ll.h" +#include "driver/ana_cmpr.h" +#include "esp_private/io_mux.h" +#include "esp_private/esp_clk.h" + +struct ana_cmpr_t { + ana_cmpr_unit_t unit; /*!< Analog comparator unit id */ + analog_cmpr_dev_t *dev; /*!< Analog comparator unit device address */ + bool is_enabled; /*!< Whether the Analog comparator unit is enabled */ + ana_cmpr_event_callbacks_t cbs; /*!< The callback group that set by user */ + intr_handle_t intr_handle; /*!< Interrupt handle */ + void *user_data; /*!< User data that passed to the callbacks */ + uint32_t src_clk_freq_hz; /*!< Source clock frequency of the Analog Comparator unit */ + esp_pm_lock_handle_t pm_lock; /*!< The Power Management lock that used to avoid unexpected power down of the clock domain */ +}; + +/* Helper macros */ +#define ANA_CMPR_NULL_POINTER_CHECK(p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, TAG, "input parameter '"#p"' is NULL") +#define ANA_CMPR_NULL_POINTER_CHECK_ISR(p) ESP_RETURN_ON_FALSE_ISR((p), ESP_ERR_INVALID_ARG, TAG, "input parameter '"#p"' is NULL") +#define ANA_CMPR_UNIT_CHECK(unit) ESP_RETURN_ON_FALSE((unit) >= ANA_CMPR_UNIT_0 && (unit) < SOC_ANA_CMPR_NUM, \ + ESP_ERR_INVALID_ARG, TAG, "invalid uint number"); + +/* Memory allocation caps which decide the section that memory supposed to allocate */ +#if CONFIG_ANA_CMPR_ISR_IRAM_SAFE +#define ANA_CMPR_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#else +#define ANA_CMPR_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#endif + +/* Driver tag */ +static const char *TAG = "ana_cmpr"; + +/* Global static object of the Analog Comparator unit */ +static ana_cmpr_handle_t s_ana_cmpr[SOC_ANA_CMPR_NUM] = { + [0 ... (SOC_ANA_CMPR_NUM - 1)] = NULL, +}; + +/* Global spin lock */ +static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED; + +static void IRAM_ATTR s_ana_cmpr_default_intr_handler(void *usr_data) +{ + ana_cmpr_handle_t cmpr_handle = (ana_cmpr_handle_t)usr_data; + bool need_yield = false; + ana_cmpr_cross_event_data_t evt_data; + /* Get and clear the interrupt status */ + uint32_t status = analog_cmpr_ll_get_intr_status(cmpr_handle->dev); + analog_cmpr_ll_clear_intr(cmpr_handle->dev, status); + + /* Call the user callback function if it is specified and the corresponding event triggers*/ + if (cmpr_handle->cbs.on_cross && (status & ANALOG_CMPR_LL_EVENT_CROSS)) { + need_yield = cmpr_handle->cbs.on_cross(cmpr_handle, &evt_data, cmpr_handle->user_data); + } + if (need_yield) { + portYIELD_FROM_ISR(); + } +} + +esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t *ret_cmpr) +{ +#if CONFIG_SDM_ENABLE_DEBUG_LOG + esp_log_level_set(TAG, ESP_LOG_DEBUG); +#endif + ANA_CMPR_NULL_POINTER_CHECK(config); + ANA_CMPR_NULL_POINTER_CHECK(ret_cmpr); + ana_cmpr_unit_t unit = config->unit; + ANA_CMPR_UNIT_CHECK(unit); + ESP_RETURN_ON_FALSE(!s_ana_cmpr[unit], ESP_ERR_INVALID_STATE, TAG, + "unit has been allocated already"); + esp_err_t ret = ESP_OK; + + /* Allocate analog comparator unit */ + s_ana_cmpr[unit] = (ana_cmpr_handle_t)heap_caps_calloc(1, sizeof(struct ana_cmpr_t), ANA_CMPR_MEM_ALLOC_CAPS); + ESP_RETURN_ON_FALSE(s_ana_cmpr[unit], ESP_ERR_NO_MEM, TAG, "no memory for analog comparator struct"); + + /* Assign analog comparator unit */ + s_ana_cmpr[unit]->dev = ANALOG_CMPR_LL_GET_HW(); + s_ana_cmpr[unit]->is_enabled = false; + s_ana_cmpr[unit]->pm_lock = NULL; + +#if CONFIG_PM_ENABLE + /* Create PM lock */ + char lock_name[10] = "ana_cmpr\0"; + lock_name[8] = '0' + unit; + ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, lock_name, &s_ana_cmpr[unit]->pm_lock); + ESP_GOTO_ON_ERROR(ret, err, TAG, "create NO_LIGHT_SLEEP, lock failed"); +#endif + + /* Analog clock comes from IO MUX, but IO MUX clock might be shared with other submodules as well */ + ESP_GOTO_ON_ERROR(clk_tree_src_get_freq_hz((soc_module_clk_t)config->clk_src, + CLK_TREE_SRC_FREQ_PRECISION_CACHED, + &s_ana_cmpr[unit]->src_clk_freq_hz), + err, TAG, "get source clock frequency failed"); + ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)(config->clk_src)), err, TAG, "set IO MUX clock source failed"); + + /* Configure the register */ + portENTER_CRITICAL(&s_spinlock); + analog_cmpr_ll_ref_source(s_ana_cmpr[unit]->dev, config->ref_src); + analog_cmpr_ll_set_cross_intr_type(s_ana_cmpr[unit]->dev, config->intr_type); + portEXIT_CRITICAL(&s_spinlock); + + /* Allocate the interrupt, currently the interrupt source of Analog Comparator is shared with GPIO interrupt source */ + esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, + s_ana_cmpr_default_intr_handler, s_ana_cmpr[unit], &s_ana_cmpr[unit]->intr_handle); + + if (config->ref_src == ANA_CMPR_REF_SRC_INTERNAL) { + ESP_LOGD(TAG, "unit %d allocated, source signal: GPIO %d, reference signal: internal", + (int)unit, ana_cmpr_io_map[unit].src_gpio); + } else { + ESP_LOGD(TAG, "unit %d allocated, source signal: GPIO %d, reference signal: GPIO %d", + (int)unit, ana_cmpr_io_map[unit].src_gpio, ana_cmpr_io_map[unit].ext_ref_gpio); + } + + *ret_cmpr = s_ana_cmpr[unit]; + return ESP_OK; + +err: + /* Free the resources if allocation failed */ + free(s_ana_cmpr[unit]); + s_ana_cmpr[unit] = NULL; + return ret; +} + +esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr) +{ + ANA_CMPR_NULL_POINTER_CHECK(cmpr); + /* Search the global object array to check if the input handle is valid */ + ana_cmpr_unit_t unit = -1; + for (int i = 0; i < SOC_ANA_CMPR_NUM; i++) { + if (s_ana_cmpr[i] == cmpr) { + unit = i; + break; + } + } + ESP_RETURN_ON_FALSE(unit >= ANA_CMPR_UNIT_0, ESP_ERR_INVALID_ARG, TAG, "wrong analog comparator handle"); + ESP_RETURN_ON_FALSE(!cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG, "this analog comparator unit not disabled yet"); + + /* Disable the Analog Comparator interrupt */ + portENTER_CRITICAL(&s_spinlock); + analog_cmpr_ll_enable_intr(cmpr->dev, ANALOG_CMPR_LL_EVENT_CROSS, false); + portEXIT_CRITICAL(&s_spinlock); + + /* Delete the pm lock if the unit has */ + if (cmpr->pm_lock) { + ESP_RETURN_ON_ERROR(esp_pm_lock_delete(cmpr->pm_lock), TAG, "delete pm lock failed"); + } + + /* Free interrupt and other resources */ + esp_intr_free(cmpr->intr_handle); + free(s_ana_cmpr[unit]); + s_ana_cmpr[unit] = NULL; + + ESP_LOGD(TAG, "unit %d deleted", (int)unit); + + return ESP_OK; +} + +esp_err_t ana_cmpr_set_intl_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_intl_ref_config_t *ref_cfg) +{ + ANA_CMPR_NULL_POINTER_CHECK_ISR(cmpr); + ANA_CMPR_NULL_POINTER_CHECK_ISR(ref_cfg); + + /* Set internal reference voltage */ + portENTER_CRITICAL_ISR(&s_spinlock); + analog_cmpr_ll_set_internal_ref_voltage(cmpr->dev, ref_cfg->ref_volt); + portEXIT_CRITICAL_ISR(&s_spinlock); + + ESP_EARLY_LOGD(TAG, "unit %d internal voltage level %"PRIu32, (int)cmpr->unit, ref_cfg->ref_volt); + + return ESP_OK; +} + +esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_config_t *dbc_cfg) +{ + ANA_CMPR_NULL_POINTER_CHECK_ISR(cmpr); + ANA_CMPR_NULL_POINTER_CHECK_ISR(dbc_cfg); + + /* Transfer the time to clock cycles */ + uint32_t wait_cycle = (uint32_t)(dbc_cfg->wait_us * cmpr->src_clk_freq_hz) / 1000000; + /* Set the waiting clock cycles */ + portENTER_CRITICAL_ISR(&s_spinlock); + analog_cmpr_ll_set_debounce_cycle(cmpr->dev, wait_cycle); + portEXIT_CRITICAL_ISR(&s_spinlock); + + ESP_EARLY_LOGD(TAG, "unit %d debounce wait cycle %"PRIu32, (int)cmpr->unit, wait_cycle); + + return ESP_OK; +} + +esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cmpr_event_callbacks_t *cbs, void *user_data) +{ + ANA_CMPR_NULL_POINTER_CHECK(cmpr); + ANA_CMPR_NULL_POINTER_CHECK(cbs); + ESP_RETURN_ON_FALSE(!cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG, + "please disable the analog comparator before registering the callbacks"); + + /* Save the callback group */ + memcpy(&(cmpr->cbs), cbs, sizeof(ana_cmpr_event_callbacks_t)); + cmpr->user_data = user_data; + + /* Enable the Analog Comparator interrupt */ + portENTER_CRITICAL(&s_spinlock); + analog_cmpr_ll_enable_intr(cmpr->dev, ANALOG_CMPR_LL_EVENT_CROSS, !!(cbs->on_cross)); + portEXIT_CRITICAL(&s_spinlock); + + ESP_LOGD(TAG, "unit %d event callback registered", (int)cmpr->unit); + + return ESP_OK; +} + +esp_err_t ana_cmpr_enable(ana_cmpr_handle_t cmpr) +{ + ANA_CMPR_NULL_POINTER_CHECK(cmpr); + ESP_RETURN_ON_FALSE(!cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG, + "the analog comparator has enabled already"); + /* Update the driver status */ + cmpr->is_enabled = true; + + /* Acquire the pm lock if the unit has, to avoid the system start light sleep while Analog comparator still working */ + if (cmpr->pm_lock) { + ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(cmpr->pm_lock), TAG, "acquire pm_lock failed"); + } + + /* Enable the Analog Comparator */ + portENTER_CRITICAL(&s_spinlock); + analog_cmpr_ll_enable(cmpr->dev, true); + portEXIT_CRITICAL(&s_spinlock); + + ESP_LOGD(TAG, "unit %d enabled", (int)cmpr->unit); + + return ESP_OK; +} + +esp_err_t ana_cmpr_disable(ana_cmpr_handle_t cmpr) +{ + ANA_CMPR_NULL_POINTER_CHECK(cmpr); + ESP_RETURN_ON_FALSE(cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG, + "the analog comparator not enabled yet"); + /* Disable the Analog Comparator */ + portENTER_CRITICAL(&s_spinlock); + analog_cmpr_ll_enable(cmpr->dev, false); + portEXIT_CRITICAL(&s_spinlock); + + /* Release the pm lock, allow light sleep then */ + if (cmpr->pm_lock) { + ESP_RETURN_ON_ERROR(esp_pm_lock_release(cmpr->pm_lock), TAG, "release pm_lock failed"); + } + + /* Update the driver status */ + cmpr->is_enabled = false; + + ESP_LOGD(TAG, "unit %d disabled", (int)cmpr->unit); + return ESP_OK; +} + +esp_err_t ana_cmpr_get_gpio(ana_cmpr_unit_t unit, ana_cmpr_channel_type_t chan_type, int *gpio_num) +{ + ANA_CMPR_NULL_POINTER_CHECK(gpio_num); + ANA_CMPR_UNIT_CHECK(unit); + + /* Get the gpio number according to the channel type */ + switch (chan_type) { + case ANA_CMPR_SOURCE_CHAN: + *gpio_num = ana_cmpr_io_map[unit].src_gpio; + break; + case ANA_CMPR_EXT_REF_CHAN: + *gpio_num = ana_cmpr_io_map[unit].ext_ref_gpio; + break; + default: + ESP_LOGE(TAG, "invalid channel type"); + return ESP_ERR_INVALID_ARG; + } + + return ESP_OK; +} diff --git a/components/driver/analog_comparator/include/driver/ana_cmpr.h b/components/driver/analog_comparator/include/driver/ana_cmpr.h new file mode 100644 index 0000000000..5e1780e5c3 --- /dev/null +++ b/components/driver/analog_comparator/include/driver/ana_cmpr.h @@ -0,0 +1,169 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "esp_err.h" +#include "driver/ana_cmpr_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Analog comparator unit configuration + * + */ +typedef struct { + ana_cmpr_unit_t unit; /*!< Analog comparator unit */ + ana_cmpr_clk_src_t clk_src; /*!< The clock source of the analog comparator, + * which decide the resolution of the comparator + */ + ana_cmpr_ref_source_t ref_src; /*!< Reference signal source of the comparator, + * select using ANA_CMPR_REF_SRC_INTERNAL or ANA_CMPR_REF_SRC_EXTERNAL. + * For internal reference, the reference voltage should be set to `internal_ref_volt`, + * for external reference, the reference signal should be connect to `ANA_CMPRx_EXT_REF_GPIO` + */ + ana_cmpr_intr_type_t intr_type; /*!< The crossing types that can trigger interrupt */ +} ana_cmpr_config_t; + +/** + * @brief Analog comparator internal reference configuration + * + */ +typedef struct { + ana_cmpr_ref_voltage_t ref_volt; /*!< The internal reference voltage. It can specify several dozen percent from the VDD power supply, + * currently supports 0%~70% VDD with step 10% + */ +} ana_cmpr_intl_ref_config_t; + +/** + * @brief Analog comparator debounce filter configuration + * + */ +typedef struct { + float wait_us; /*!< The wait time of re-enabling the interrupt after the last triggering, + * it is used to avoid the spurious triggering while the source signal crossing the reference signal. + * The value should regarding how fast the source signal changes, e.g., a rapid signal requires + * a small wait time, otherwise the next crosses may be missed. + * (Unit: micro second, resolution = 1 / SRC_CLK_FREQ) + */ +} ana_cmpr_debounce_config_t; + +/** + * @brief Group of Analog Comparator callbacks + * @note The callbacks are all running under ISR environment + * @note When CONFIG_ANA_CMPR_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. + * The variables used in the function should be in the SRAM as well. + */ +typedef struct { + ana_cmpr_cross_cb_t on_cross; /*!< The callback function on cross interrupt */ +} ana_cmpr_event_callbacks_t; + +/** + * @brief Allocating a new analog comparator unit handle + * + * @param[in] config The config of the analog comparator unit + * @param[out] ret_cmpr The returned analog comparator unit handle + * @return + * - ESP_OK Allocate analog comparator unit handle success + * - ESP_ERR_NO_MEM No memory for the analog comparator structure + * - ESP_ERR_INVALID_ARG NULL pointer of the parameters or wrong unit number + * - ESP_ERR_INVALID_STATE The unit has been allocated or the clock source has been occupied + */ +esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t *ret_cmpr); + +/** + * @brief Delete the analog comparator unit handle + * + * @param[in] cmpr The handle of analog comparator unit + * @return + * - ESP_OK Delete analog comparator unit handle success + * - ESP_ERR_INVALID_ARG NULL pointer of the parameters or wrong unit number + * - ESP_ERR_INVALID_STATE The analog comparator is not disabled yet + */ +esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr); + +/** + * @brief Set internal reference configuration + * @note This function only need to be called when `ana_cmpr_config_t::ref_src` + * is ANA_CMPR_REF_SRC_INTERNAL. + * @note This function is allowed to run within ISR context including intr callbacks + * @note This function will be placed into IRAM if `CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` is on, + * so that it's allowed to be executed when Cache is disabled + * + * @param[in] cmpr The handle of analog comparator unit + * @param[in] ref_cfg Internal reference configuration + * @return + * - ESP_OK Set denounce configuration success + * - ESP_ERR_INVALID_ARG NULL pointer of the parameters + */ +esp_err_t ana_cmpr_set_intl_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_intl_ref_config_t *ref_cfg); + +/** + * @brief Set debounce configuration to the analog comparator + * @note This function is allowed to run within ISR context including intr callbacks + * @note This function will be placed into IRAM if `CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` is on, + * so that it's allowed to be executed when Cache is disabled + * + * @param[in] cmpr The handle of analog comparator unit + * @param[in] dbc_cfg Debounce configuration + * @return + * - ESP_OK Set denounce configuration success + * - ESP_ERR_INVALID_ARG NULL pointer of the parameters + */ +esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_config_t *dbc_cfg); + +/** + * @brief Register analog comparator interrupt event callbacks + * @note This function can only be called before enabling the unit + * + * @param[in] cmpr The handle of analog comparator unit + * @param[in] cbs Group of callback functions + * @param[in] user_data The user data that will be passed to callback functions directly + * @return + * - ESP_OK Register callbacks success + * - ESP_ERR_INVALID_ARG NULL pointer of the parameters + * - ESP_ERR_INVALID_STATE The analog comparator has been enabled + */ +esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cmpr_event_callbacks_t *cbs, void *user_data); + +/** + * @brief Enable the analog comparator unit + * + * @param[in] cmpr The handle of analog comparator unit + * @return + * - ESP_OK Enable analog comparator unit success + * - ESP_ERR_INVALID_ARG NULL pointer of the parameters + * - ESP_ERR_INVALID_STATE The analog comparator has been enabled + */ +esp_err_t ana_cmpr_enable(ana_cmpr_handle_t cmpr); + +/** + * @brief Disable the analog comparator unit + * + * @param[in] cmpr The handle of analog comparator unit + * @return + * - ESP_OK Disable analog comparator unit success + * - ESP_ERR_INVALID_ARG NULL pointer of the parameters + * - ESP_ERR_INVALID_STATE The analog comparator has disabled already + */ +esp_err_t ana_cmpr_disable(ana_cmpr_handle_t cmpr); + +/** + * @brief Get the specific GPIO number of the analog comparator unit + * + * @param[in] unit The handle of analog comparator unit + * @param[in] chan_type The channel type of analog comparator, like source channel or reference channel + * @param[out] gpio_num The output GPIO number of this channel + * @return + * - ESP_OK Get GPIO success + * - ESP_ERR_INVALID_ARG NULL pointer of the parameters or wrong unit number or wrong channel type + */ +esp_err_t ana_cmpr_get_gpio(ana_cmpr_unit_t unit, ana_cmpr_channel_type_t chan_type, int *gpio_num); + +#ifdef __cplusplus +} +#endif diff --git a/components/driver/analog_comparator/include/driver/ana_cmpr_types.h b/components/driver/analog_comparator/include/driver/ana_cmpr_types.h new file mode 100644 index 0000000000..d2ea26fc74 --- /dev/null +++ b/components/driver/analog_comparator/include/driver/ana_cmpr_types.h @@ -0,0 +1,109 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "soc/clk_tree_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Analog comparator unit + * + */ +typedef enum { + ANA_CMPR_UNIT_0, /*!< Analog Comparator unit */ +} ana_cmpr_unit_t; + +/** + * @brief Analog comparator reference source + * + */ +typedef enum { + ANA_CMPR_REF_SRC_INTERNAL, /*!< Analog Comparator internal reference source, related to VDD */ + ANA_CMPR_REF_SRC_EXTERNAL, /*!< Analog Comparator external reference source, from `ANA_CMPR0_EXT_REF_GPIO` */ +} ana_cmpr_ref_source_t; + +/** + * @brief Analog comparator channel type + * + */ +typedef enum { + ANA_CMPR_SOURCE_CHAN, /*!< Analog Comparator source channel, which is used to input the signal that to be compared */ + ANA_CMPR_EXT_REF_CHAN, /*!< Analog Comparator external reference channel, which is used as the reference signal */ +} ana_cmpr_channel_type_t; + +/** + * @brief Analog comparator interrupt type + * + */ +typedef enum { + ANA_CMPR_INTR_DISABLE, /*!< Disable the cross event interrupt */ + ANA_CMPR_INTR_POS_CROSS, /*!< Enable the positive cross event interrupt */ + ANA_CMPR_INTR_NEG_CROSS, /*!< Enable the negative cross event interrupt */ + ANA_CMPR_INTR_ANY_CROSS, /*!< Enable the both positive & negative cross event interrupt */ +} ana_cmpr_intr_type_t; + +/** + * @brief Analog comparator internal reference voltage + * + */ +typedef enum { + ANA_CMPR_REF_VOLT_0_PCT_VDD, /*!< Internal reference voltage equals to 0% VDD */ + ANA_CMPR_REF_VOLT_10_PCT_VDD, /*!< Internal reference voltage equals to 10% VDD */ + ANA_CMPR_REF_VOLT_20_PCT_VDD, /*!< Internal reference voltage equals to 20% VDD */ + ANA_CMPR_REF_VOLT_30_PCT_VDD, /*!< Internal reference voltage equals to 30% VDD */ + ANA_CMPR_REF_VOLT_40_PCT_VDD, /*!< Internal reference voltage equals to 40% VDD */ + ANA_CMPR_REF_VOLT_50_PCT_VDD, /*!< Internal reference voltage equals to 50% VDD */ + ANA_CMPR_REF_VOLT_60_PCT_VDD, /*!< Internal reference voltage equals to 60% VDD */ + ANA_CMPR_REF_VOLT_70_PCT_VDD, /*!< Internal reference voltage equals to 70% VDD */ +} ana_cmpr_ref_voltage_t; + +/** + * @brief Analog comparator unit handle + * + */ +typedef struct ana_cmpr_t *ana_cmpr_handle_t; + +#if SOC_ANA_CMPR_SUPPORTED +/** + * @brief Analog comparator clock source + * + */ +typedef soc_periph_ana_cmpr_clk_src_t ana_cmpr_clk_src_t; +#else +/** + * @brief Analog comparator clock source + * + */ +typedef int ana_cmpr_clk_src_t; +#endif + +/** + * @brief Analog comparator cross event data + * + */ +typedef struct { + // Currently no data +} ana_cmpr_cross_event_data_t; + +/** + * @brief Prototype of Analog comparator event callback + * @param[in] cmpr Analog Comparator handle, created from `ana_cmpr_new_unit()` + * @param[in] edata Point to Analog Comparator event data. The lifecycle of this pointer memory is inside this function, + * user should copy it into static memory if used outside this function. (Currently not use) + * @param[in] user_ctx User registered context, passed from `ana_cmpr_register_event_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ +typedef bool (*ana_cmpr_cross_cb_t) (ana_cmpr_handle_t cmpr, const ana_cmpr_cross_event_data_t *edata, void *user_ctx); + +#ifdef __cplusplus +} +#endif diff --git a/components/driver/linker.lf b/components/driver/linker.lf index 54670adf28..544ceff855 100644 --- a/components/driver/linker.lf +++ b/components/driver/linker.lf @@ -18,6 +18,9 @@ entries: gpio: gpio_intr_disable (noflash) if SDM_CTRL_FUNC_IN_IRAM = y: sdm: sdm_channel_set_pulse_density (noflash) + if ANA_CMPR_CTRL_FUNC_IN_IRAM = y: + ana_cmpr: ana_cmpr_set_intl_reference (noflash) + ana_cmpr: ana_cmpr_set_debounce (noflash) if DAC_CTRL_FUNC_IN_IRAM = y: dac_oneshot: dac_oneshot_output_voltage (noflash) dac_continuous: dac_continuous_write_asynchronously (noflash) diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 6fdfa36008..a944c360b3 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -97,10 +97,6 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "sdm_hal.c") endif() - if(CONFIG_SOC_ANALOG_CMPR_SUPPORTED) - list(APPEND srcs "analog_cmpr_hal.c") - endif() - if(CONFIG_ETH_USE_ESP32_EMAC) list(APPEND srcs "emac_hal.c") endif() diff --git a/components/hal/analog_cmpr_hal.c b/components/hal/analog_cmpr_hal.c deleted file mode 100644 index a9c4cc8e79..0000000000 --- a/components/hal/analog_cmpr_hal.c +++ /dev/null @@ -1,13 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "hal/analog_cmpr_ll.h" -#include "hal/analog_cmpr_hal.h" - -void analog_cmpr_hal_init(analog_cmpr_hal_context_t *hal) -{ - hal->dev = ANALOG_CMPR_LL_GET_HW(); -} diff --git a/components/hal/esp32h2/include/hal/analog_cmpr_ll.h b/components/hal/esp32h2/include/hal/ana_cmpr_ll.h similarity index 60% rename from components/hal/esp32h2/include/hal/analog_cmpr_ll.h rename to components/hal/esp32h2/include/hal/ana_cmpr_ll.h index e60a03961c..31e0026cd2 100644 --- a/components/hal/esp32h2/include/hal/analog_cmpr_ll.h +++ b/components/hal/esp32h2/include/hal/ana_cmpr_ll.h @@ -11,8 +11,11 @@ #include "hal/assert.h" #include "soc/gpio_ext_struct.h" -#define ANALOG_CMPR_LL_GET_HW() (&ANALOG_CMPR) -#define ANALOG_CMPR_LL_EVENT_CROSS (1 << 0) +#define ANALOG_CMPR_LL_GET_HW() (&ANALOG_CMPR) +#define ANALOG_CMPR_LL_EVENT_CROSS (1 << 0) + +#define ANALOG_CMPR_LL_POS_CROSS_MASK (1 << 1) +#define ANALOG_CMPR_LL_NEG_CROSS_MASK (1 << 2) #ifdef __cplusplus extern "C" { @@ -33,14 +36,11 @@ static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en) * @brief Set the voltage of the internal reference * * @param hw Analog comparator register base address - * @param voltage The voltage of the internal reference, range [0.0V, 0.7VDD], step 0.1VDD + * @param volt_level The voltage level of the internal reference, range [0.0V, 0.7VDD], step 0.1VDD */ -static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw, float voltage) +static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw, uint32_t volt_level) { - hw->pad_comp_config.mode_comp = 0; - uint32_t volt_reg_val = (uint32_t)((voltage + 0.05F) / 0.1F); - HAL_ASSERT(volt_reg_val <= 7); - hw->pad_comp_config.dref_comp = volt_reg_val; + hw->pad_comp_config.dref_comp = volt_level; } /** @@ -55,55 +55,31 @@ static inline float analog_cmpr_ll_get_internal_ref_voltage(analog_cmpr_dev_t *h } /** - * @brief The reference voltage comes from GPIO pad (GPIO10) + * @brief The reference voltage comes from internal or external * * @note Also see `analog_cmpr_ll_set_internal_ref_voltage` to use the internal reference voltage * * @param hw Analog comparator register base address + * @param ref_src reference source, 0 for internal, 1 for external GPIO pad (GPIO10) */ -static inline void analog_cmpr_ll_ref_voltage_from_external(analog_cmpr_dev_t *hw) +static inline void analog_cmpr_ll_ref_source(analog_cmpr_dev_t *hw, uint32_t ref_src) { - hw->pad_comp_config.mode_comp = 1; + hw->pad_comp_config.mode_comp = ref_src; } /** - * @brief Disable the cross detection + * @brief Set cross interrupt trigger type * * @param hw Analog comparator register base address + * @param type The type of cross interrupt + * - 0: disable interrupt + * - 1: enable positive cross interrupt (input analog goes from low to high and across the reference voltage) + * - 2: enable negative cross interrupt (input analog goes from high to low and across the reference voltage) + * - 3: enable any positive or negative cross interrupt */ -static inline void analog_cmpr_ll_disable_cross_detection(analog_cmpr_dev_t *hw) +static inline void analog_cmpr_ll_set_cross_intr_type(analog_cmpr_dev_t *hw, uint8_t type) { - hw->pad_comp_config.zero_det_mode = 0; -} - -/** - * @brief Enable to detect the positive cross (input analog goes from low to high and across the reference voltage) - * - * @param hw Analog comparator register base address - * @param enable True to enable, False to disable - */ -static inline void analog_cmpr_ll_enable_pos_cross_detection(analog_cmpr_dev_t *hw, bool enable) -{ - if (enable) { - hw->pad_comp_config.zero_det_mode |= (1 << 0); - } else { - hw->pad_comp_config.zero_det_mode &= ~(1 << 0); - } -} - -/** - * @brief Enable to detect the negative cross (input analog goes from high to low and across the reference voltage) - * - * @param hw Analog comparator register base address - * @param enable True to enable, False to disable - */ -static inline void analog_cmpr_ll_enable_neg_cross_detection(analog_cmpr_dev_t *hw, bool enable) -{ - if (enable) { - hw->pad_comp_config.zero_det_mode |= (1 << 1); - } else { - hw->pad_comp_config.zero_det_mode &= ~(1 << 1); - } + hw->pad_comp_config.zero_det_mode = type; } /** @@ -140,9 +116,9 @@ static inline void analog_cmpr_ll_enable_intr(analog_cmpr_dev_t *hw, uint32_t ma * * @param hw Analog comparator register base address */ -static inline void analog_cmpr_ll_get_intr_status(analog_cmpr_dev_t *hw) +static inline uint32_t analog_cmpr_ll_get_intr_status(analog_cmpr_dev_t *hw) { - hw->int_st.val; + return hw->int_st.val; } /** diff --git a/components/hal/include/hal/analog_cmpr_hal.h b/components/hal/include/hal/analog_cmpr_hal.h deleted file mode 100644 index 01d81ff1c0..0000000000 --- a/components/hal/include/hal/analog_cmpr_hal.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 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 - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct analog_cmpr_dev_t *analog_cmpr_handle_t; // Analog comparator SOC layer handle - -/** - * HAL context type of analog comparator driver - */ -typedef struct { - analog_cmpr_handle_t dev; -} analog_cmpr_hal_context_t; - -/** - * @brief Initialize Analog comparator hal driver - * - * @param hal Context of the HAL layer - */ -void analog_cmpr_hal_init(analog_cmpr_hal_context_t *hal); - -#ifdef __cplusplus -} -#endif diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 35572de538..9255e70f77 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -30,6 +30,10 @@ if(CONFIG_SOC_ADC_SUPPORTED) list(APPEND srcs "${target}/adc_periph.c") endif() +if(CONFIG_SOC_ANA_CMPR_SUPPORTED) + list(APPEND srcs "${target}/ana_cmpr_periph.c") +endif() + if(CONFIG_SOC_DEDICATED_GPIO_SUPPORTED) list(APPEND srcs "${target}/dedic_gpio_periph.c") endif() diff --git a/components/soc/esp32h2/ana_cmpr_periph.c b/components/soc/esp32h2/ana_cmpr_periph.c new file mode 100644 index 0000000000..4d3a67586c --- /dev/null +++ b/components/soc/esp32h2/ana_cmpr_periph.c @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/ana_cmpr_periph.h" + +const ana_cmpr_conn_t ana_cmpr_io_map[SOC_ANA_CMPR_NUM] = { + [0] = { + .src_gpio = ANA_CMPR0_SRC_GPIO, + .ext_ref_gpio = ANA_CMPR0_EXT_REF_GPIO, + }, +}; diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 25095ba7d5..0c0dda8fbe 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -7,6 +7,10 @@ config SOC_ADC_SUPPORTED bool default y +config SOC_ANA_CMPR_SUPPORTED + bool + default y + config SOC_DEDICATED_GPIO_SUPPORTED bool default y @@ -423,6 +427,10 @@ config SOC_DEDIC_PERIPH_ALWAYS_ENABLE bool default y +config SOC_ANA_CMPR_NUM + int + default 1 + config SOC_I2C_NUM int default 2 diff --git a/components/soc/esp32h2/include/soc/ana_cmpr_channel.h b/components/soc/esp32h2/include/soc/ana_cmpr_channel.h new file mode 100644 index 0000000000..1df89f6723 --- /dev/null +++ b/components/soc/esp32h2/include/soc/ana_cmpr_channel.h @@ -0,0 +1,10 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define ANA_CMPR0_EXT_REF_GPIO 10 /*!< The GPIO that can be used as external reference voltage */ +#define ANA_CMPR0_SRC_GPIO 11 /*!< The GPIO that used for inputting the source signal to compare */ diff --git a/components/soc/esp32h2/include/soc/clk_tree_defs.h b/components/soc/esp32h2/include/soc/clk_tree_defs.h index 959060688c..39a6b9d6db 100644 --- a/components/soc/esp32h2/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h2/include/soc/clk_tree_defs.h @@ -330,6 +330,22 @@ typedef enum { SDM_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M as the default clock choice */ } soc_periph_sdm_clk_src_t; +///////////////////////////////////////////////////Analog Comparator//////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of Analog Comparator + */ +#define SOC_ANA_CMPR_CLKS {SOC_MOD_CLK_PLL_F48M, SOC_MOD_CLK_XTAL} + +/** + * @brief Sigma Delta Modulator clock source + */ +typedef enum { + ANA_CMPR_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL clock as the source clock */ + ANA_CMPR_CLK_SRC_PLL_F48M = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M clock as the source clock */ + ANA_CMPR_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M as the default clock choice */ +} soc_periph_ana_cmpr_clk_src_t; + //////////////////////////////////////////////////GPIO Glitch Filter//////////////////////////////////////////////////// /** diff --git a/components/soc/esp32h2/include/soc/gpio_ext_struct.h b/components/soc/esp32h2/include/soc/gpio_ext_struct.h index 815d6d9e5e..1c9e6f3985 100644 --- a/components/soc/esp32h2/include/soc/gpio_ext_struct.h +++ b/components/soc/esp32h2/include/soc/gpio_ext_struct.h @@ -75,8 +75,8 @@ typedef union { */ uint32_t xpd_comp:1; /** mode_comp : R/W; bitpos: [1]; default: 0; - * 1 to enable external reference from PAD[0]. 0 to enable internal reference, - * meanwhile PAD[0] can be used as a regular GPIO. + * 1 to enable external reference from PAD[10]. 0 to enable internal reference, + * meanwhile PAD[10] can be used as a regular GPIO. */ uint32_t mode_comp:1; /** dref_comp : R/W; bitpos: [4:2]; default: 0; diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 2614da02ae..12c36981b0 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -26,6 +26,7 @@ /*-------------------------- COMMON CAPS ---------------------------------------*/ #define SOC_ADC_SUPPORTED 1 +#define SOC_ANA_CMPR_SUPPORTED 1 #define SOC_DEDICATED_GPIO_SUPPORTED 1 #define SOC_UART_SUPPORTED 1 #define SOC_GDMA_SUPPORTED 1 @@ -196,6 +197,9 @@ #define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */ #define SOC_DEDIC_PERIPH_ALWAYS_ENABLE (1) /*!< The dedicated GPIO (a.k.a. fast GPIO) is featured by some customized CPU instructions, which is always enabled */ +/*------------------------- Analog Comparator CAPS ---------------------------*/ +#define SOC_ANA_CMPR_NUM (1U) + /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32-H2 has 2 I2C #define SOC_I2C_NUM (2U) diff --git a/components/soc/include/soc/ana_cmpr_periph.h b/components/soc/include/soc/ana_cmpr_periph.h new file mode 100644 index 0000000000..9f3f3c36c1 --- /dev/null +++ b/components/soc/include/soc/ana_cmpr_periph.h @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "soc/soc_caps.h" +#include "soc/ana_cmpr_channel.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int src_gpio; + int ext_ref_gpio; +} ana_cmpr_conn_t; + +extern const ana_cmpr_conn_t ana_cmpr_io_map[SOC_ANA_CMPR_NUM]; + +#ifdef __cplusplus +} +#endif diff --git a/examples/peripherals/dac/dac_cosine_wave/main/dac_cosine_example_main.c b/examples/peripherals/dac/dac_cosine_wave/main/dac_cosine_example_main.c index 99b21d6cd5..5616794465 100644 --- a/examples/peripherals/dac/dac_cosine_wave/main/dac_cosine_example_main.c +++ b/examples/peripherals/dac/dac_cosine_wave/main/dac_cosine_example_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 */ From 24361f232d1a884594fcfd2f8014f7329656ce3f Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 7 Mar 2023 12:09:07 +0800 Subject: [PATCH 4/5] ana_cmpr: add an example and test cases --- components/driver/.build-test-rules.yml | 4 + .../driver/analog_comparator/ana_cmpr.c | 27 +++- .../include/driver/ana_cmpr_types.h | 2 +- .../analog_comparator/CMakeLists.txt | 18 +++ .../test_apps/analog_comparator/README.md | 2 + .../analog_comparator/main/CMakeLists.txt | 11 ++ .../analog_comparator/main/test_ana_cmpr.c | 86 +++++++++++ .../analog_comparator/main/test_ana_cmpr.h | 43 ++++++ .../main/test_ana_cmpr_common.c | 39 +++++ .../main/test_ana_cmpr_iram.c | 76 +++++++++ .../analog_comparator/main/test_app_main.c | 54 +++++++ .../analog_comparator/pytest_ana_cmpr.py | 19 +++ .../analog_comparator/sdkconfig.ci.iram_safe | 7 + .../analog_comparator/sdkconfig.ci.release | 5 + .../analog_comparator/sdkconfig.defaults | 2 + .../hal/esp32h2/include/hal/ana_cmpr_ll.h | 4 + examples/peripherals/.build-test-rules.yml | 4 + .../analog_comparator/CMakeLists.txt | 8 + .../peripherals/analog_comparator/README.md | 144 ++++++++++++++++++ .../peripherals/analog_comparator/ext_ref.png | Bin 0 -> 9204 bytes .../analog_comparator/hysteresis_ref.png | Bin 0 -> 8042 bytes .../analog_comparator/main/CMakeLists.txt | 2 + .../analog_comparator/main/Kconfig.projbuild | 28 ++++ .../main/ana_cmpr_example_main.c | 140 +++++++++++++++++ .../pytest_ana_cmpr_example.py | 26 ++++ .../analog_comparator/sdkconfig.ci.ext | 2 + .../analog_comparator/sdkconfig.ci.intl | 2 + .../analog_comparator/static_50p_ref.png | Bin 0 -> 9600 bytes 28 files changed, 747 insertions(+), 8 deletions(-) create mode 100644 components/driver/test_apps/analog_comparator/CMakeLists.txt create mode 100644 components/driver/test_apps/analog_comparator/README.md create mode 100644 components/driver/test_apps/analog_comparator/main/CMakeLists.txt create mode 100644 components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c create mode 100644 components/driver/test_apps/analog_comparator/main/test_ana_cmpr.h create mode 100644 components/driver/test_apps/analog_comparator/main/test_ana_cmpr_common.c create mode 100644 components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c create mode 100644 components/driver/test_apps/analog_comparator/main/test_app_main.c create mode 100644 components/driver/test_apps/analog_comparator/pytest_ana_cmpr.py create mode 100644 components/driver/test_apps/analog_comparator/sdkconfig.ci.iram_safe create mode 100644 components/driver/test_apps/analog_comparator/sdkconfig.ci.release create mode 100644 components/driver/test_apps/analog_comparator/sdkconfig.defaults create mode 100644 examples/peripherals/analog_comparator/CMakeLists.txt create mode 100644 examples/peripherals/analog_comparator/README.md create mode 100644 examples/peripherals/analog_comparator/ext_ref.png create mode 100644 examples/peripherals/analog_comparator/hysteresis_ref.png create mode 100644 examples/peripherals/analog_comparator/main/CMakeLists.txt create mode 100644 examples/peripherals/analog_comparator/main/Kconfig.projbuild create mode 100644 examples/peripherals/analog_comparator/main/ana_cmpr_example_main.c create mode 100644 examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py create mode 100644 examples/peripherals/analog_comparator/sdkconfig.ci.ext create mode 100644 examples/peripherals/analog_comparator/sdkconfig.ci.intl create mode 100644 examples/peripherals/analog_comparator/static_50p_ref.png diff --git a/components/driver/.build-test-rules.yml b/components/driver/.build-test-rules.yml index 7aefd1f0ab..fc4e3f03bd 100644 --- a/components/driver/.build-test-rules.yml +++ b/components/driver/.build-test-rules.yml @@ -1,5 +1,9 @@ # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps +components/driver/test_apps/analog_comparator: + disable: + - if: SOC_ANA_CMPR_SUPPORTED != 1 + components/driver/test_apps/dac_test_apps/dac: disable: - if: SOC_DAC_SUPPORTED != 1 diff --git a/components/driver/analog_comparator/ana_cmpr.c b/components/driver/analog_comparator/ana_cmpr.c index c042455668..1054550bb8 100644 --- a/components/driver/analog_comparator/ana_cmpr.c +++ b/components/driver/analog_comparator/ana_cmpr.c @@ -20,6 +20,7 @@ #include "esp_pm.h" #include "esp_heap_caps.h" #include "esp_intr_alloc.h" +#include "esp_memory_utils.h" #include "soc/periph_defs.h" #include "soc/ana_cmpr_periph.h" #include "hal/ana_cmpr_ll.h" @@ -30,6 +31,7 @@ struct ana_cmpr_t { ana_cmpr_unit_t unit; /*!< Analog comparator unit id */ analog_cmpr_dev_t *dev; /*!< Analog comparator unit device address */ + ana_cmpr_ref_source_t ref_src; /*!< Analog comparator reference source, internal or external */ bool is_enabled; /*!< Whether the Analog comparator unit is enabled */ ana_cmpr_event_callbacks_t cbs; /*!< The callback group that set by user */ intr_handle_t intr_handle; /*!< Interrupt handle */ @@ -46,9 +48,11 @@ struct ana_cmpr_t { /* Memory allocation caps which decide the section that memory supposed to allocate */ #if CONFIG_ANA_CMPR_ISR_IRAM_SAFE -#define ANA_CMPR_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#define ANA_CMPR_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM) #else -#define ANA_CMPR_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#define ANA_CMPR_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#define ANA_CMPR_INTR_FLAG ESP_INTR_FLAG_LEVEL1 #endif /* Driver tag */ @@ -99,6 +103,7 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * /* Assign analog comparator unit */ s_ana_cmpr[unit]->dev = ANALOG_CMPR_LL_GET_HW(); + s_ana_cmpr[unit]->ref_src = config->ref_src; s_ana_cmpr[unit]->is_enabled = false; s_ana_cmpr[unit]->pm_lock = NULL; @@ -124,7 +129,7 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * portEXIT_CRITICAL(&s_spinlock); /* Allocate the interrupt, currently the interrupt source of Analog Comparator is shared with GPIO interrupt source */ - esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, + esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ANA_CMPR_INTR_FLAG, s_ana_cmpr_default_intr_handler, s_ana_cmpr[unit], &s_ana_cmpr[unit]->intr_handle); if (config->ref_src == ANA_CMPR_REF_SRC_INTERNAL) { @@ -183,11 +188,13 @@ esp_err_t ana_cmpr_set_intl_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_int { ANA_CMPR_NULL_POINTER_CHECK_ISR(cmpr); ANA_CMPR_NULL_POINTER_CHECK_ISR(ref_cfg); + ESP_RETURN_ON_FALSE_ISR(cmpr->ref_src == ANA_CMPR_REF_SRC_INTERNAL, ESP_ERR_INVALID_STATE, + TAG, "the reference channel is not internal, no need to configure internal reference"); /* Set internal reference voltage */ - portENTER_CRITICAL_ISR(&s_spinlock); + portENTER_CRITICAL_SAFE(&s_spinlock); analog_cmpr_ll_set_internal_ref_voltage(cmpr->dev, ref_cfg->ref_volt); - portEXIT_CRITICAL_ISR(&s_spinlock); + portEXIT_CRITICAL_SAFE(&s_spinlock); ESP_EARLY_LOGD(TAG, "unit %d internal voltage level %"PRIu32, (int)cmpr->unit, ref_cfg->ref_volt); @@ -202,9 +209,9 @@ esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_ /* Transfer the time to clock cycles */ uint32_t wait_cycle = (uint32_t)(dbc_cfg->wait_us * cmpr->src_clk_freq_hz) / 1000000; /* Set the waiting clock cycles */ - portENTER_CRITICAL_ISR(&s_spinlock); + portENTER_CRITICAL_SAFE(&s_spinlock); analog_cmpr_ll_set_debounce_cycle(cmpr->dev, wait_cycle); - portEXIT_CRITICAL_ISR(&s_spinlock); + portEXIT_CRITICAL_SAFE(&s_spinlock); ESP_EARLY_LOGD(TAG, "unit %d debounce wait cycle %"PRIu32, (int)cmpr->unit, wait_cycle); @@ -217,6 +224,12 @@ esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cm ANA_CMPR_NULL_POINTER_CHECK(cbs); ESP_RETURN_ON_FALSE(!cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG, "please disable the analog comparator before registering the callbacks"); +#if CONFIG_ANA_CMPR_ISR_IRAM_SAFE + if (cbs->on_cross) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_cross), ESP_ERR_INVALID_ARG, TAG, + "ANA_CMPR_ISR_IRAM_SAFE enabled but the callback function not in IRAM"); + } +#endif /* Save the callback group */ memcpy(&(cmpr->cbs), cbs, sizeof(ana_cmpr_event_callbacks_t)); diff --git a/components/driver/analog_comparator/include/driver/ana_cmpr_types.h b/components/driver/analog_comparator/include/driver/ana_cmpr_types.h index d2ea26fc74..8f96c25a3c 100644 --- a/components/driver/analog_comparator/include/driver/ana_cmpr_types.h +++ b/components/driver/analog_comparator/include/driver/ana_cmpr_types.h @@ -90,7 +90,7 @@ typedef int ana_cmpr_clk_src_t; * */ typedef struct { - // Currently no data + // No data for now } ana_cmpr_cross_event_data_t; /** diff --git a/components/driver/test_apps/analog_comparator/CMakeLists.txt b/components/driver/test_apps/analog_comparator/CMakeLists.txt new file mode 100644 index 0000000000..1b4500c607 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/CMakeLists.txt @@ -0,0 +1,18 @@ +# This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test_ana_cmpr) + +if(CONFIG_COMPILER_DUMP_RTL_FILES) + add_custom_target(check_test_app_sections ALL + COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py + --rtl-dir ${CMAKE_BINARY_DIR}/esp-idf/driver/ + --elf-file ${CMAKE_BINARY_DIR}/test_ana_cmpr.elf + find-refs + --from-sections=.iram0.text + --to-sections=.flash.text + --exit-code + DEPENDS ${elf} + ) +endif() diff --git a/components/driver/test_apps/analog_comparator/README.md b/components/driver/test_apps/analog_comparator/README.md new file mode 100644 index 0000000000..8161d00f6d --- /dev/null +++ b/components/driver/test_apps/analog_comparator/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32-H2 | +| ----------------- | -------- | diff --git a/components/driver/test_apps/analog_comparator/main/CMakeLists.txt b/components/driver/test_apps/analog_comparator/main/CMakeLists.txt new file mode 100644 index 0000000000..beb627afb1 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/CMakeLists.txt @@ -0,0 +1,11 @@ +set(srcs "test_app_main.c" + "test_ana_cmpr_common.c" + "test_ana_cmpr.c") + +if(CONFIG_ANA_CMPR_ISR_IRAM_SAFE) + list(APPEND srcs "test_ana_cmpr_iram.c") +endif() + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS "." + WHOLE_ARCHIVE) diff --git a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c new file mode 100644 index 0000000000..18389f407b --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_ana_cmpr.h" + +TEST_CASE("ana_cmpr_unit_install_uninstall", "[ana_cmpr]") +{ + ana_cmpr_handle_t cmpr = NULL; + ana_cmpr_config_t config = { + .unit = SOC_ANA_CMPR_NUM, // Set a wrong unit + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_INTERNAL, + .intr_type = ANA_CMPR_INTR_ANY_CROSS, + }; + /* Allocate a wrong unit */ + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, ana_cmpr_new_unit(&config, &cmpr)); + /* Allocate a correct unit */ + config.unit = ANA_CMPR_UNIT_0; + TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); + /* Try to allocate a existed unit */ + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_new_unit(&config, &cmpr)); + /* Set the internal reference before enable */ + ana_cmpr_intl_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, + }; + TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + /* Enable the unit */ + TEST_ESP_OK(ana_cmpr_enable(cmpr)); + /* Set the internal reference after enable */ + ref_cfg.ref_volt = ANA_CMPR_REF_VOLT_30_PCT_VDD; + TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + /* Try tp delete unit after enable */ + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_del_unit(cmpr)); + /* Disable the unit */ + TEST_ESP_OK(ana_cmpr_disable(cmpr)); + /* Try to delete the unit with a wrong handle */ + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_del_unit((void *)&cmpr)); + /* Delete the unit */ + TEST_ESP_OK(ana_cmpr_del_unit(cmpr)); + + /* Try to set internal reference for a external unit */ + config.ref_src = ANA_CMPR_REF_SRC_EXTERNAL; + TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + TEST_ESP_OK(ana_cmpr_del_unit(cmpr)); +} + +TEST_CASE("ana_cmpr_internal_reference", "[ana_cmpr]") +{ + int src_chan = test_init_src_chan_gpio(); + uint32_t cnt = 0; + + ana_cmpr_handle_t cmpr = NULL; + ana_cmpr_config_t config = { + .unit = ANA_CMPR_UNIT_0, + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_INTERNAL, + .intr_type = ANA_CMPR_INTR_ANY_CROSS, + }; + TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); + ana_cmpr_intl_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, + }; + TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + ana_cmpr_debounce_config_t dbc_cfg = { + .wait_us = 10.0, + }; + TEST_ESP_OK(ana_cmpr_set_debounce(cmpr, &dbc_cfg)); + ana_cmpr_event_callbacks_t cbs = { + .on_cross = test_ana_cmpr_on_cross_callback, + }; + + TEST_ESP_OK(ana_cmpr_register_event_callbacks(cmpr, &cbs, &cnt)); + TEST_ESP_OK(ana_cmpr_enable(cmpr)); + cnt = 0; + for (int i = 1; i <= 10; i++) { + test_simulate_src_signal(src_chan, i % 2); + esp_rom_delay_us(100); + TEST_ASSERT(cnt == i); + } + TEST_ESP_OK(ana_cmpr_disable(cmpr)); + TEST_ESP_OK(ana_cmpr_del_unit(cmpr)); +} diff --git a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.h b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.h new file mode 100644 index 0000000000..13566bfc84 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.h @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_rom_sys.h" +#include "soc/soc_caps.h" +#include "driver/ana_cmpr.h" + +/** + * @brief Test default on cross callback + * + * @param cmpr Analog Comparator handle + * @param edata Event data + * @param user_ctx User context, need to input a unint32_t counter + * @return + * - true Need to yield + * - false Don't need yield + */ +bool test_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, const ana_cmpr_cross_event_data_t *edata, void *user_ctx); + +/** + * @brief Initialize Analog Comparator source channel GPIO + * + * @return + * - int Source channel GPIO number + */ +int test_init_src_chan_gpio(void); + +/** + * @brief Simulate source channel signal + * + * @param src_chan Source channel GPIO number + * @param val 0 to set low, others to set high + */ +void test_simulate_src_signal(int src_chan, uint32_t val); diff --git a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_common.c b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_common.c new file mode 100644 index 0000000000..9db12a0d07 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_common.c @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_ana_cmpr.h" +#include "hal/gpio_ll.h" +#include "driver/gpio.h" +#include "esp_attr.h" + +bool IRAM_ATTR test_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, const ana_cmpr_cross_event_data_t *edata, void *user_ctx) +{ + uint32_t *count = (uint32_t *)user_ctx; + (*count)++; + return false; +} + +int test_init_src_chan_gpio(void) +{ + int src_chan_num = -1; + TEST_ESP_OK(ana_cmpr_get_gpio(ANA_CMPR_UNIT_0, ANA_CMPR_SOURCE_CHAN, &src_chan_num)); + TEST_ASSERT(src_chan_num > 0); + gpio_config_t io_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = (1ULL << src_chan_num), + .pull_down_en = false, + .pull_up_en = false, + }; + TEST_ESP_OK(gpio_config(&io_conf)); + TEST_ESP_OK(gpio_set_level(src_chan_num, 0)); + return src_chan_num; +} + +void IRAM_ATTR test_simulate_src_signal(int src_chan, uint32_t val) +{ + gpio_set_level(src_chan, val); +} diff --git a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c new file mode 100644 index 0000000000..3b929fb267 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c @@ -0,0 +1,76 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_ana_cmpr.h" +#include "unity_test_utils.h" +#include "unity_test_utils_cache.h" + +typedef struct { + ana_cmpr_handle_t handle; + uint32_t count; + int src_chan; +} test_ana_cmpr_data_t; + +/** + * @brief Global debounce configuration + * @note Why it is global? + * If we declare a local variable in 'float' type when cache disabled, + * it may be allocated in the flash, which can lead crash when trying to access it. + */ +static ana_cmpr_debounce_config_t IRAM_ATTR s_dbc_cfg = { + .wait_us = 1.0, +}; + +static void IRAM_ATTR test_ana_cmpr_iram_safety(void *args) +{ + test_ana_cmpr_data_t *data = (test_ana_cmpr_data_t *)args; + ana_cmpr_intl_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, + }; + ana_cmpr_set_intl_reference(data->handle, &ref_cfg); + ana_cmpr_set_debounce(data->handle, &s_dbc_cfg); + data->count = 0; + for (int i = 1; i <= 10; i++) { + test_simulate_src_signal(data->src_chan, i % 2); + esp_rom_delay_us(100); + } +} + +TEST_CASE("ana_cmpr_internal_reference_iram_safe", "[ana_cmpr]") +{ + test_ana_cmpr_data_t test_data = { + .handle = NULL, + .count = 0, + .src_chan = -1, + }; + test_data.src_chan = test_init_src_chan_gpio(); + + ana_cmpr_handle_t cmpr = NULL; + ana_cmpr_config_t config = { + .unit = ANA_CMPR_UNIT_0, + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_INTERNAL, + .intr_type = ANA_CMPR_INTR_ANY_CROSS, + }; + TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); + test_data.handle = cmpr; + ana_cmpr_intl_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, + }; + TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + TEST_ESP_OK(ana_cmpr_set_debounce(cmpr, &s_dbc_cfg)); + ana_cmpr_event_callbacks_t cbs = { + .on_cross = test_ana_cmpr_on_cross_callback, + }; + TEST_ESP_OK(ana_cmpr_register_event_callbacks(cmpr, &cbs, &test_data.count)); + TEST_ESP_OK(ana_cmpr_enable(cmpr)); + + unity_utils_run_cache_disable_stub(test_ana_cmpr_iram_safety, &test_data); + TEST_ASSERT_EQUAL_INT(test_data.count, 10); + + TEST_ESP_OK(ana_cmpr_disable(cmpr)); + TEST_ESP_OK(ana_cmpr_del_unit(cmpr)); +} diff --git a/components/driver/test_apps/analog_comparator/main/test_app_main.c b/components/driver/test_apps/analog_comparator/main/test_app_main.c new file mode 100644 index 0000000000..9b6762fcc8 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/test_app_main.c @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" + +// Some resources are lazy allocated in analog comparator driver, the threshold is left for that case +#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); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); +} + +void app_main(void) +{ + +// _ _ _ _ ____ __ __ ____ ____ _____ _ +// / \ | \ | | / \ / ___| \/ | _ \| _ \ |_ _|__ ___| |_ +// / _ \ | \| | / _ \ | | | |\/| | |_) | |_) | | |/ _ \/ __| __| +// / ___ \| |\ |/ ___ \ | |___| | | | __/| _ < | | __/\__ \ |_ +// /_/ \_\_| \_/_/ \_\ \____|_| |_|_| |_| \_\ |_|\___||___/\__| + + printf(" _ _ _ _ ____ __ __ ____ ____ _____ _ \n"); + printf(" / \\ | \\ | | / \\ / ___| \\/ | _ \\| _ \\ |_ _|__ ___| |_ \n"); + printf(" / _ \\ | \\| | / _ \\ | | | |\\/| | |_) | |_) | | |/ _ \\/ __| __|\n"); + printf(" / ___ \\| |\\ |/ ___ \\ | |___| | | | __/| _ < | | __/\\__ \\ |_ \n"); + printf(" /_/ \\_\\_| \\_/_/ \\_\\ \\____|_| |_|_| |_| \\_\\ |_|\\___||___/\\__|\n"); + printf("\n"); + unity_run_menu(); +} diff --git a/components/driver/test_apps/analog_comparator/pytest_ana_cmpr.py b/components/driver/test_apps/analog_comparator/pytest_ana_cmpr.py new file mode 100644 index 0000000000..1cc5cf4971 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/pytest_ana_cmpr.py @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32h2 +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'iram_safe', + 'release', + ], + indirect=True, +) +def test_ana_cmpr(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/driver/test_apps/analog_comparator/sdkconfig.ci.iram_safe b/components/driver/test_apps/analog_comparator/sdkconfig.ci.iram_safe new file mode 100644 index 0000000000..9d68c306bf --- /dev/null +++ b/components/driver/test_apps/analog_comparator/sdkconfig.ci.iram_safe @@ -0,0 +1,7 @@ +CONFIG_COMPILER_DUMP_RTL_FILES=y +CONFIG_ANA_CMPR_ISR_IRAM_SAFE=y +CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM=y +CONFIG_GPIO_CTRL_FUNC_IN_IRAM=y +CONFIG_COMPILER_OPTIMIZATION_NONE=y +# place non-ISR FreeRTOS functions in Flash +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y diff --git a/components/driver/test_apps/analog_comparator/sdkconfig.ci.release b/components/driver/test_apps/analog_comparator/sdkconfig.ci.release new file mode 100644 index 0000000000..91d93f163e --- /dev/null +++ b/components/driver/test_apps/analog_comparator/sdkconfig.ci.release @@ -0,0 +1,5 @@ +CONFIG_PM_ENABLE=y +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/driver/test_apps/analog_comparator/sdkconfig.defaults b/components/driver/test_apps/analog_comparator/sdkconfig.defaults new file mode 100644 index 0000000000..b308cb2ddd --- /dev/null +++ b/components/driver/test_apps/analog_comparator/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT=n diff --git a/components/hal/esp32h2/include/hal/ana_cmpr_ll.h b/components/hal/esp32h2/include/hal/ana_cmpr_ll.h index 31e0026cd2..ffedbfde61 100644 --- a/components/hal/esp32h2/include/hal/ana_cmpr_ll.h +++ b/components/hal/esp32h2/include/hal/ana_cmpr_ll.h @@ -38,6 +38,7 @@ static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en) * @param hw Analog comparator register base address * @param volt_level The voltage level of the internal reference, range [0.0V, 0.7VDD], step 0.1VDD */ +__attribute__((always_inline)) static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw, uint32_t volt_level) { hw->pad_comp_config.dref_comp = volt_level; @@ -90,6 +91,7 @@ static inline void analog_cmpr_ll_set_cross_intr_type(analog_cmpr_dev_t *hw, uin * @param hw Analog comparator register base address * @param cycle The debounce cycle */ +__attribute__((always_inline)) static inline void analog_cmpr_ll_set_debounce_cycle(analog_cmpr_dev_t *hw, uint32_t cycle) { hw->pad_comp_filter.zero_det_filter_cnt = cycle; @@ -116,6 +118,7 @@ static inline void analog_cmpr_ll_enable_intr(analog_cmpr_dev_t *hw, uint32_t ma * * @param hw Analog comparator register base address */ +__attribute__((always_inline)) static inline uint32_t analog_cmpr_ll_get_intr_status(analog_cmpr_dev_t *hw) { return hw->int_st.val; @@ -127,6 +130,7 @@ static inline uint32_t analog_cmpr_ll_get_intr_status(analog_cmpr_dev_t *hw) * @param hw Analog comparator register base address * @param mask Interrupt status word */ +__attribute__((always_inline)) static inline void analog_cmpr_ll_clear_intr(analog_cmpr_dev_t *hw, uint32_t mask) { hw->int_clr.val = mask; diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 6d8c66f57d..28b1931547 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -8,6 +8,10 @@ examples/peripherals/adc/oneshot_read: disable: - if: SOC_ADC_SUPPORTED != 1 +examples/peripherals/analog_comparator: + disable: + - if: SOC_ANA_CMPR_SUPPORTED != 1 + examples/peripherals/dac: disable: - if: SOC_DAC_SUPPORTED != 1 diff --git a/examples/peripherals/analog_comparator/CMakeLists.txt b/examples/peripherals/analog_comparator/CMakeLists.txt new file mode 100644 index 0000000000..fa9f99dcd0 --- /dev/null +++ b/examples/peripherals/analog_comparator/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(analog_comparator_example) diff --git a/examples/peripherals/analog_comparator/README.md b/examples/peripherals/analog_comparator/README.md new file mode 100644 index 0000000000..8a6adb523c --- /dev/null +++ b/examples/peripherals/analog_comparator/README.md @@ -0,0 +1,144 @@ +| Supported Targets | ESP32-H2 | +| ----------------- | -------- | + +# Analog Comparator Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example is going to show how to use the Analog Comparator. + +## How to Use Example + +### Hardware Requirement + +* A development board with any supported Espressif SOC chip (see `Supported Targets` table above) +* A USB cable for power supply and programming +* A device to generate the source signal. For example, you can use a ESP SoC that support DAC peripheral (like ESP32 or ESP32S2) to generate source signal, or just use a signal generator. + +#### Required Additionally for External Reference + +* One more external signal for the reference. You can input a static voltage or a wave, for example, the static voltage can be gotten by the resistor divider, and the wave can be generated by either ESP SoC or a signal generator. + +### Example Connection + +Let's take ESP32-H2 and ESP32 for example, and we use the DAC on ESP32 as the signal generator (you can use a real signal generator instead if you have one). + +#### Internal Reference + +Download this example into ESP32-H2 and any DAC examples in `examples/peripherals/dac` directory into ESP32. + +``` + ┌──────────────┐ ┌──────────────┐ + │ ESP32-H2 │ │ ESP32 │ + │ │ source signal │ │ +┌────┤GPIO0 GPIO11│◄────┬──────────┤GPIO25 │ +│ │ │ │ │ │ +│ │ GND├─────┼────┬─────┤GND │ +│ │ │ │ │ │ │ +│ └──────────────┘ │ │ └──────────────┘ +│ │ │ +│ ┌──────────────┐ │ │ +│ │ Oscilloscope │ │ │ +│ │ │ │ │ +└───►│Probe1 Probe2│◄────┘ │ + │ │ │ + │ GND├──────────┘ + │ │ + └──────────────┘ +``` + +#### External Reference + +For the static external reference, we can use resistor divider to get the static voltage. + +``` + ┌──────────────┐ ┌──────────────┐ + │ ESP32-H2 │ │ ESP32 │ + │ │ source signal │ │ +┌────┤GPIO0 GPIO11│◄────┬──────────┤GPIO25 │ +│ │ │ ref│signal │ │ +│ │ GPIO10│◄────┼──────┐ ┌─┤GND │ +│ │ │ │ │ │ │ │ +│ │ GND├─────┼─┬────┼─┘ └──────────────┘ +│ │ │ │ │ │ VDD +│ └──────────────┘ │ │ │ ─┬─ +│ │ │ │ │ +│ │ │ │ ├┐ +│ ┌──────────────┐ │ │ │ ││R1 +│ │ Oscilloscope │ │ │ │ ├┘ +│ │ │ │ │ └──────────┤ +└───►│Probe1 Probe2│◄────┘ │ │ + │ │ │ ├┐ + │ GND├───────┤ ││R2 + │ │ │ ├┘ + └──────────────┘ │ │ + └───────────────┤ + │ + ─┴─ + GND +``` + +Also, we can generate a different signal on another DAC channel on ESP32, you can customize your DAC wave using `examples/peripherals/dac/dac_continuous/signal_generator` example. + +``` + ┌──────────────┐ ┌──────────────┐ + │ ESP32-H2 │ │ ESP32 │ + │ │ source signal │ │ +┌────┤GPIO0 GPIO11│◄────┬──────────┤GPIO25 │ +│ │ │ ref│signal │ │ +│ │ GPIO10│◄────┼──────────┤GPIO26 │ +│ │ │ │ │ │ +│ │ GND├─────┼───┬──────┤GND │ +│ │ │ │ │ │ │ +│ └──────────────┘ │ │ └──────────────┘ +│ │ │ +│ │ │ +│ ┌──────────────┐ │ │ +│ │ Oscilloscope │ │ │ +│ │ │ │ │ +└───►│Probe1 Probe2│◄────┘ │ + │ │ │ + │ GND├─────────┘ + │ │ + └──────────────┘ +``` + +### Configure the Project + +You can decide to adopt internal reference or external reference in the example menu config, and you can also enable hysteresis comparator for the internal reference in the menu config. + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT build flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +### Static Internal Reference + +The internal voltage is set to 50% VDD, and input a 50 Hz sine wave as source signal (blue line), the output GPIO toggles every time the sine wave crossing the reference voltage (yellow line) + +![static_intl_ref](./static_50p_ref.png) + +### Hysteresis Internal Reference + +The internal voltage is set to 30% VDD and 70% VDD alternately in this case, the source signal is a 100 Hz sine wave (blue line), the output GPIO toggles every time the source signal exceed 70% VDD and lower than 30% VDD. + +![hysteresis_cmpr](./hysteresis_ref.png) + +### External Reference + +Here we input a 100 Hz sine wave (blue line) as the source signal and input a 1 KHz triangle wave as the reference signal, the output wave (yellow line) can be regarded as a SPWM (Sinusoidal PWM) wave. + +![ext_ref](./ext_ref.png) + +## Troubleshooting + +For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/analog_comparator/ext_ref.png b/examples/peripherals/analog_comparator/ext_ref.png new file mode 100644 index 0000000000000000000000000000000000000000..e73485331ea13356dbb79aa9ffd6bcbd21e8dac2 GIT binary patch literal 9204 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 KXjg0Ae*9l^LS@+i literal 0 HcmV?d00001 diff --git a/examples/peripherals/analog_comparator/hysteresis_ref.png b/examples/peripherals/analog_comparator/hysteresis_ref.png new file mode 100644 index 0000000000000000000000000000000000000000..e2707f6db71b95aa01354f9fe820e903846fc323 GIT binary patch literal 8042 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 XtXD89GvdCX<2|^qtx~CE{o+3W43$4W literal 0 HcmV?d00001 diff --git a/examples/peripherals/analog_comparator/main/CMakeLists.txt b/examples/peripherals/analog_comparator/main/CMakeLists.txt new file mode 100644 index 0000000000..e017eb4889 --- /dev/null +++ b/examples/peripherals/analog_comparator/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "ana_cmpr_example_main.c" + INCLUDE_DIRS ".") diff --git a/examples/peripherals/analog_comparator/main/Kconfig.projbuild b/examples/peripherals/analog_comparator/main/Kconfig.projbuild new file mode 100644 index 0000000000..1e2f780b37 --- /dev/null +++ b/examples/peripherals/analog_comparator/main/Kconfig.projbuild @@ -0,0 +1,28 @@ +menu "Analog Comparator Example Configuration" + + choice EXAMPLE_REFERENCE_SOURCE + prompt "Analog Comparator reference source" + default EXAMPLE_INTERNAL_REF + help + Decide the reference signal comes from internal or external + + config EXAMPLE_INTERNAL_REF + bool "Internal reference" + help + The source signal will refer to an internal voltage, which related to VDD. + + config EXAMPLE_EXTERNAL_REF + bool "External reference" + help + The source signal will refer to the external signal on a specific GPIO. + endchoice + + config EXAMPLE_HYSTERESIS_COMPARATOR + depends on EXAMPLE_INTERNAL_REF + bool "Enable hysteresis comparator" + default n + help + The internal reference voltage will be set to 30% VDD and 70% VDD alternately + every time the interrupt triggered. + +endmenu diff --git a/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.c b/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.c new file mode 100644 index 0000000000..a885fa6a76 --- /dev/null +++ b/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.c @@ -0,0 +1,140 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "driver/ana_cmpr.h" +#include "esp_log.h" + +#define EXAMPLE_ANA_CMPR_UNIT ANA_CMPR_UNIT_0 // Analog Comparator unit +#define EXAMPLE_WAIT_TIME_PROP (0.1) // The wait time proportion in one relative signal period +#define EXAMPLE_WAITE_TIME_US(freq_approx) (1000000.0 * EXAMPLE_WAIT_TIME_PROP / (freq_approx)) + +#define EXAMPLE_MONITOR_GPIO_NUM (0) // The gpio to monitor the on cross callback + +static const char *TAG = "ana_cmpr_example"; + +static bool IRAM_ATTR example_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, + const ana_cmpr_cross_event_data_t *edata, + void *user_ctx) +{ +#if CONFIG_EXAMPLE_HYSTERESIS_COMPARATOR + static ana_cmpr_intl_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_70_PCT_VDD, + }; + bool is_70p = ref_cfg.ref_volt == ANA_CMPR_REF_VOLT_70_PCT_VDD; + /* Toggle the GPIO, monitor the gpio on a oscilloscope. */ + gpio_set_level(EXAMPLE_MONITOR_GPIO_NUM, is_70p); + /* Set the internal reference voltage to 30% VDD and 70 %VDD alternately */ + ana_cmpr_set_intl_reference(cmpr, &ref_cfg); + ref_cfg.ref_volt = is_70p ? ANA_CMPR_REF_VOLT_30_PCT_VDD : ANA_CMPR_REF_VOLT_70_PCT_VDD; +#else + static int lvl = 0; + /* Toggle the GPIO, monitor the gpio on a oscilloscope. */ + gpio_set_level(EXAMPLE_MONITOR_GPIO_NUM, lvl); + lvl = !lvl; +#endif + return false; +} + +void example_init_analog_comparator(void) +{ + /* Step 0: Show the source channel and reference channel GPIO */ + int src_gpio = -1; + int ext_ref_gpio = -1; + ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &src_gpio)); + ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_EXT_REF_CHAN, &ext_ref_gpio)); + ESP_LOGI(TAG, "Analog Comparator source gpio %d, external reference gpio %d", src_gpio, ext_ref_gpio); + + ana_cmpr_handle_t cmpr = NULL; + +#if CONFIG_EXAMPLE_INTERNAL_REF + /* Step 1: Allocate the new analog comparator unit */ + ana_cmpr_config_t config = { + .unit = EXAMPLE_ANA_CMPR_UNIT, + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_INTERNAL, + .intr_type = ANA_CMPR_INTR_ANY_CROSS, + }; + ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr)); + ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference"); + + /* Step 1.1: As we are using the internal reference source, we need to configure the internal reference */ + ana_cmpr_intl_ref_config_t ref_cfg = { +#if CONFIG_EXAMPLE_HYSTERESIS_COMPARATOR + /* Set the initial internal reference voltage to 70% VDD, it will be updated in the callback every time the interrupt triggered */ + .ref_volt = ANA_CMPR_REF_VOLT_70_PCT_VDD +#else + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, +#endif + }; + ESP_ERROR_CHECK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); +#else + /* Step 1: Allocate the new analog comparator unit */ + ana_cmpr_config_t config = { + .unit = EXAMPLE_ANA_CMPR_UNIT, + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_EXTERNAL, + .intr_type = ANA_CMPR_INTR_ANY_CROSS, + }; + ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr)); + ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference"); +#endif + + /* Step 2: (Optional) Set the debounce configuration + * It's an optional configuration, if the wait time is set in debounce configuration, + * the cross interrupt will be disabled temporary after it is triggered, and it will be enabled + * automatically enabled after `wait_us`, so that the duplicate interrupts + * can be suppressed while the source signal crossing the reference signal. */ + ana_cmpr_debounce_config_t dbc_cfg = { + /* Normally the `wait_us` is related to how fast the source signal or reference signal changes + * comparing to another one. This example adopts an approximate frequency as the relative signal + * frequency, and set the default wait time to EXAMPLE_WAIT_TIME_PROP of the relative signal period. + * We need to estimate an appropriate `freq_approx` and EXAMPLE_WAIT_TIME_PROP + * to make sure the interrupt neither triggers duplicate interrupts, nor misses the next crossing interrupt. + * Here we take 1 KHz for example */ + .wait_us = EXAMPLE_WAITE_TIME_US(1000), + }; + ESP_ERROR_CHECK(ana_cmpr_set_debounce(cmpr, &dbc_cfg)); + + /* Step 3: Register the event callbacks */ + ana_cmpr_event_callbacks_t cbs = { + .on_cross = example_ana_cmpr_on_cross_callback, + }; + ESP_ERROR_CHECK(ana_cmpr_register_event_callbacks(cmpr, &cbs, NULL)); + + /* Step 4: Enable the analog comparator unit */ + ESP_ERROR_CHECK(ana_cmpr_enable(cmpr)); + +#if CONFIG_EXAMPLE_INTERNAL_REF + ESP_LOGI(TAG, "Analog comparator enabled, reference voltage: %d%% * VDD", (int)ref_cfg.ref_volt * 10); +#else + ESP_LOGI(TAG, "Analog comparator enabled, external reference selected"); +#endif +} + +void example_init_monitor_gpio(void) +{ + gpio_config_t io_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = (1ULL << EXAMPLE_MONITOR_GPIO_NUM), + .pull_down_en = false, + .pull_up_en = false, + }; + gpio_config(&io_conf); + gpio_set_level(EXAMPLE_MONITOR_GPIO_NUM, 0); +} + +void app_main(void) +{ + /* Initialize GPIO to monitor the comparator interrupt */ + example_init_monitor_gpio(); + /* Initialize Analog Comparator */ + example_init_analog_comparator(); +} diff --git a/examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py b/examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py new file mode 100644 index 0000000000..a5bba766e5 --- /dev/null +++ b/examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32h2 +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'intl', + 'ext', + ], + indirect=True, +) +def test_ana_cmpr_example(dut: Dut) -> None: + sdkconfig = dut.app.sdkconfig + dut.expect('ana_cmpr_example: Analog Comparator source gpio 11, external reference gpio 10', timeout=10) + if sdkconfig['EXAMPLE_INTERNAL_REF']: + dut.expect('ana_cmpr_example: Allocate Analog Comparator with internal reference', timeout=10) + dut.expect(r'ana_cmpr_example: Analog comparator enabled, reference voltage: [0-9]+% \* VDD', timeout=10) + elif sdkconfig['EXAMPLE_EXTERNAL_REF']: + dut.expect('ana_cmpr_example: Allocate Analog Comparator with internal reference', timeout=10) + dut.expect('ana_cmpr_example: Analog comparator enabled, external reference selected', timeout=10) diff --git a/examples/peripherals/analog_comparator/sdkconfig.ci.ext b/examples/peripherals/analog_comparator/sdkconfig.ci.ext new file mode 100644 index 0000000000..3ec04884ce --- /dev/null +++ b/examples/peripherals/analog_comparator/sdkconfig.ci.ext @@ -0,0 +1,2 @@ +CONFIG_EXAMPLE_INTERNAL_REF=n +CONFIG_EXAMPLE_EXTERNAL_REF=y diff --git a/examples/peripherals/analog_comparator/sdkconfig.ci.intl b/examples/peripherals/analog_comparator/sdkconfig.ci.intl new file mode 100644 index 0000000000..ae9cdfdb82 --- /dev/null +++ b/examples/peripherals/analog_comparator/sdkconfig.ci.intl @@ -0,0 +1,2 @@ +CONFIG_EXAMPLE_INTERNAL_REF=y +CONFIG_EXAMPLE_EXTERNAL_REF=n diff --git a/examples/peripherals/analog_comparator/static_50p_ref.png b/examples/peripherals/analog_comparator/static_50p_ref.png new file mode 100644 index 0000000000000000000000000000000000000000..202b0ad680ad86c5867791f4c6e460a544c98cd9 GIT binary patch literal 9600 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

So;Hph}I(BUo;$v-%pDyi7$uU;8v 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 i*q+X{yeoT3? Date: Mon, 13 Mar 2023 12:34:53 +0800 Subject: [PATCH 5/5] ana_cmpr: add programming guide --- components/driver/Kconfig | 4 +- .../driver/analog_comparator/ana_cmpr.c | 67 +++--- .../include/driver/ana_cmpr.h | 31 ++- .../include/driver/ana_cmpr_types.h | 10 +- components/driver/gpio/gpio.c | 3 + components/driver/linker.lf | 3 +- .../analog_comparator/main/test_ana_cmpr.c | 16 +- .../main/test_ana_cmpr_iram.c | 31 ++- .../hal/esp32h2/include/hal/ana_cmpr_ll.h | 5 +- .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 - components/soc/esp32h2/include/soc/soc_caps.h | 1 - docs/conf_common.py | 3 + docs/doxygen/Doxyfile | 2 + .../en/api-reference/peripherals/ana_cmpr.rst | 195 ++++++++++++++++++ docs/en/api-reference/peripherals/index.rst | 1 + .../api-reference/peripherals/ana_cmpr.rst | 1 + .../zh_CN/api-reference/peripherals/index.rst | 1 + .../main/ana_cmpr_example_main.c | 22 +- .../pytest_ana_cmpr_example.py | 2 +- 19 files changed, 317 insertions(+), 85 deletions(-) create mode 100644 docs/en/api-reference/peripherals/ana_cmpr.rst create mode 100644 docs/zh_CN/api-reference/peripherals/ana_cmpr.rst diff --git a/components/driver/Kconfig b/components/driver/Kconfig index 4195b5979d..a8ff75a3ae 100644 --- a/components/driver/Kconfig +++ b/components/driver/Kconfig @@ -287,8 +287,8 @@ menu "Driver Configurations" bool "Place Analog Comparator control functions into IRAM" default n help - Place Analog Comparator control functions (like set_intl_reference) into IRAM, - so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context. + Place Analog Comparator control functions (like ana_cmpr_set_internal_reference) into IRAM, + so that these functions can be IRAM-safe and able to be called in an IRAM interrupt context. Enabling this option can improve driver performance as well. config ANA_CMPR_ENABLE_DEBUG_LOG diff --git a/components/driver/analog_comparator/ana_cmpr.c b/components/driver/analog_comparator/ana_cmpr.c index 1054550bb8..b45391a005 100644 --- a/components/driver/analog_comparator/ana_cmpr.c +++ b/components/driver/analog_comparator/ana_cmpr.c @@ -7,7 +7,7 @@ #include #include #include "sdkconfig.h" -#if CONFIG_SDM_ENABLE_DEBUG_LOG +#if CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG // The local log level must be defined before including esp_log.h // Set the maximum log level for this source file #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG @@ -49,10 +49,10 @@ struct ana_cmpr_t { /* Memory allocation caps which decide the section that memory supposed to allocate */ #if CONFIG_ANA_CMPR_ISR_IRAM_SAFE #define ANA_CMPR_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) -#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM) +#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM) // Shared with GPIO #else #define ANA_CMPR_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT -#define ANA_CMPR_INTR_FLAG ESP_INTR_FLAG_LEVEL1 +#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED) // Shared with GPIO #endif /* Driver tag */ @@ -86,7 +86,7 @@ static void IRAM_ATTR s_ana_cmpr_default_intr_handler(void *usr_data) esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t *ret_cmpr) { -#if CONFIG_SDM_ENABLE_DEBUG_LOG +#if CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG esp_log_level_set(TAG, ESP_LOG_DEBUG); #endif ANA_CMPR_NULL_POINTER_CHECK(config); @@ -120,17 +120,19 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * CLK_TREE_SRC_FREQ_PRECISION_CACHED, &s_ana_cmpr[unit]->src_clk_freq_hz), err, TAG, "get source clock frequency failed"); - ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)(config->clk_src)), err, TAG, "set IO MUX clock source failed"); + ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)(config->clk_src)), err, TAG, + "potential clock source conflicts from other IOMUX peripherals"); /* Configure the register */ portENTER_CRITICAL(&s_spinlock); - analog_cmpr_ll_ref_source(s_ana_cmpr[unit]->dev, config->ref_src); - analog_cmpr_ll_set_cross_intr_type(s_ana_cmpr[unit]->dev, config->intr_type); + analog_cmpr_ll_set_ref_source(s_ana_cmpr[unit]->dev, config->ref_src); + analog_cmpr_ll_set_cross_type(s_ana_cmpr[unit]->dev, config->cross_type); portEXIT_CRITICAL(&s_spinlock); /* Allocate the interrupt, currently the interrupt source of Analog Comparator is shared with GPIO interrupt source */ - esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ANA_CMPR_INTR_FLAG, - s_ana_cmpr_default_intr_handler, s_ana_cmpr[unit], &s_ana_cmpr[unit]->intr_handle); + ESP_GOTO_ON_ERROR(esp_intr_alloc_intrstatus(ETS_GPIO_INTR_SOURCE, ANA_CMPR_INTR_FLAG, (uint32_t)analog_cmpr_ll_get_intr_status_reg(s_ana_cmpr[unit]->dev), + ANALOG_CMPR_LL_EVENT_CROSS, s_ana_cmpr_default_intr_handler, s_ana_cmpr[unit], &s_ana_cmpr[unit]->intr_handle), + err, TAG, "allocate interrupt failed"); if (config->ref_src == ANA_CMPR_REF_SRC_INTERNAL) { ESP_LOGD(TAG, "unit %d allocated, source signal: GPIO %d, reference signal: internal", @@ -144,9 +146,8 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * return ESP_OK; err: - /* Free the resources if allocation failed */ - free(s_ana_cmpr[unit]); - s_ana_cmpr[unit] = NULL; + /* Delete the unit if allocation failed */ + ana_cmpr_del_unit(s_ana_cmpr[unit]); return ret; } @@ -164,18 +165,16 @@ esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr) ESP_RETURN_ON_FALSE(unit >= ANA_CMPR_UNIT_0, ESP_ERR_INVALID_ARG, TAG, "wrong analog comparator handle"); ESP_RETURN_ON_FALSE(!cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG, "this analog comparator unit not disabled yet"); - /* Disable the Analog Comparator interrupt */ - portENTER_CRITICAL(&s_spinlock); - analog_cmpr_ll_enable_intr(cmpr->dev, ANALOG_CMPR_LL_EVENT_CROSS, false); - portEXIT_CRITICAL(&s_spinlock); - /* Delete the pm lock if the unit has */ if (cmpr->pm_lock) { ESP_RETURN_ON_ERROR(esp_pm_lock_delete(cmpr->pm_lock), TAG, "delete pm lock failed"); } /* Free interrupt and other resources */ - esp_intr_free(cmpr->intr_handle); + if (cmpr->intr_handle) { + esp_intr_free(cmpr->intr_handle); + } + free(s_ana_cmpr[unit]); s_ana_cmpr[unit] = NULL; @@ -184,7 +183,7 @@ esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr) return ESP_OK; } -esp_err_t ana_cmpr_set_intl_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_intl_ref_config_t *ref_cfg) +esp_err_t ana_cmpr_set_internal_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_internal_ref_config_t *ref_cfg) { ANA_CMPR_NULL_POINTER_CHECK_ISR(cmpr); ANA_CMPR_NULL_POINTER_CHECK_ISR(ref_cfg); @@ -207,7 +206,7 @@ esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_ ANA_CMPR_NULL_POINTER_CHECK_ISR(dbc_cfg); /* Transfer the time to clock cycles */ - uint32_t wait_cycle = (uint32_t)(dbc_cfg->wait_us * cmpr->src_clk_freq_hz) / 1000000; + uint32_t wait_cycle = (uint32_t)(dbc_cfg->wait_us * (cmpr->src_clk_freq_hz / 1000000)); /* Set the waiting clock cycles */ portENTER_CRITICAL_SAFE(&s_spinlock); analog_cmpr_ll_set_debounce_cycle(cmpr->dev, wait_cycle); @@ -218,6 +217,21 @@ esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_ return ESP_OK; } +esp_err_t ana_cmpr_set_cross_type(ana_cmpr_handle_t cmpr, ana_cmpr_cross_type_t cross_type) +{ + ANA_CMPR_NULL_POINTER_CHECK_ISR(cmpr); + ESP_RETURN_ON_FALSE_ISR(cross_type >= ANA_CMPR_CROSS_DISABLE && cross_type <= ANA_CMPR_CROSS_ANY, + ESP_ERR_INVALID_ARG, TAG, "invalid cross type"); + + portENTER_CRITICAL_SAFE(&s_spinlock); + analog_cmpr_ll_set_cross_type(cmpr->dev, cross_type); + portEXIT_CRITICAL_SAFE(&s_spinlock); + + ESP_EARLY_LOGD(TAG, "unit %d cross type updated to %d", (int)cmpr->unit, cross_type); + + return ESP_OK; +} + esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cmpr_event_callbacks_t *cbs, void *user_data) { ANA_CMPR_NULL_POINTER_CHECK(cmpr); @@ -227,7 +241,11 @@ esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cm #if CONFIG_ANA_CMPR_ISR_IRAM_SAFE if (cbs->on_cross) { ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_cross), ESP_ERR_INVALID_ARG, TAG, - "ANA_CMPR_ISR_IRAM_SAFE enabled but the callback function not in IRAM"); + "ANA_CMPR_ISR_IRAM_SAFE enabled but the callback function is not in IRAM"); + } + if (user_data) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(user_data), ESP_ERR_INVALID_ARG, TAG, + "ANA_CMPR_ISR_IRAM_SAFE enabled but the user_data is not in IRAM"); } #endif @@ -235,11 +253,6 @@ esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cm memcpy(&(cmpr->cbs), cbs, sizeof(ana_cmpr_event_callbacks_t)); cmpr->user_data = user_data; - /* Enable the Analog Comparator interrupt */ - portENTER_CRITICAL(&s_spinlock); - analog_cmpr_ll_enable_intr(cmpr->dev, ANALOG_CMPR_LL_EVENT_CROSS, !!(cbs->on_cross)); - portEXIT_CRITICAL(&s_spinlock); - ESP_LOGD(TAG, "unit %d event callback registered", (int)cmpr->unit); return ESP_OK; @@ -260,6 +273,7 @@ esp_err_t ana_cmpr_enable(ana_cmpr_handle_t cmpr) /* Enable the Analog Comparator */ portENTER_CRITICAL(&s_spinlock); + analog_cmpr_ll_enable_intr(cmpr->dev, ANALOG_CMPR_LL_EVENT_CROSS, !!(cmpr->cbs.on_cross)); analog_cmpr_ll_enable(cmpr->dev, true); portEXIT_CRITICAL(&s_spinlock); @@ -275,6 +289,7 @@ esp_err_t ana_cmpr_disable(ana_cmpr_handle_t cmpr) "the analog comparator not enabled yet"); /* Disable the Analog Comparator */ portENTER_CRITICAL(&s_spinlock); + analog_cmpr_ll_enable_intr(cmpr->dev, ANALOG_CMPR_LL_EVENT_CROSS, false); analog_cmpr_ll_enable(cmpr->dev, false); portEXIT_CRITICAL(&s_spinlock); diff --git a/components/driver/analog_comparator/include/driver/ana_cmpr.h b/components/driver/analog_comparator/include/driver/ana_cmpr.h index 5e1780e5c3..4cd09852b1 100644 --- a/components/driver/analog_comparator/include/driver/ana_cmpr.h +++ b/components/driver/analog_comparator/include/driver/ana_cmpr.h @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ + #include #include #include "esp_err.h" @@ -26,7 +27,7 @@ typedef struct { * For internal reference, the reference voltage should be set to `internal_ref_volt`, * for external reference, the reference signal should be connect to `ANA_CMPRx_EXT_REF_GPIO` */ - ana_cmpr_intr_type_t intr_type; /*!< The crossing types that can trigger interrupt */ + ana_cmpr_cross_type_t cross_type; /*!< The crossing types that can trigger interrupt */ } ana_cmpr_config_t; /** @@ -34,21 +35,21 @@ typedef struct { * */ typedef struct { - ana_cmpr_ref_voltage_t ref_volt; /*!< The internal reference voltage. It can specify several dozen percent from the VDD power supply, - * currently supports 0%~70% VDD with step 10% + ana_cmpr_ref_voltage_t ref_volt; /*!< The internal reference voltage. It can be specified to a certain fixed percentage of + * the VDD power supply, currently supports 0%~70% VDD with a step 10% */ -} ana_cmpr_intl_ref_config_t; +} ana_cmpr_internal_ref_config_t; /** * @brief Analog comparator debounce filter configuration * */ typedef struct { - float wait_us; /*!< The wait time of re-enabling the interrupt after the last triggering, + uint32_t wait_us; /*!< The wait time of re-enabling the interrupt after the last triggering, * it is used to avoid the spurious triggering while the source signal crossing the reference signal. * The value should regarding how fast the source signal changes, e.g., a rapid signal requires * a small wait time, otherwise the next crosses may be missed. - * (Unit: micro second, resolution = 1 / SRC_CLK_FREQ) + * (Unit: micro second) */ } ana_cmpr_debounce_config_t; @@ -99,8 +100,9 @@ esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr); * @return * - ESP_OK Set denounce configuration success * - ESP_ERR_INVALID_ARG NULL pointer of the parameters + * - ESP_ERR_INVALID_STATE The reference source is not `ANA_CMPR_REF_SRC_INTERNAL` */ -esp_err_t ana_cmpr_set_intl_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_intl_ref_config_t *ref_cfg); +esp_err_t ana_cmpr_set_internal_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_internal_ref_config_t *ref_cfg); /** * @brief Set debounce configuration to the analog comparator @@ -116,6 +118,21 @@ esp_err_t ana_cmpr_set_intl_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_int */ esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_config_t *dbc_cfg); +/** + * @brief Set the source signal cross type + * @note The initial cross type is configured in `ana_cmpr_new_unit`, this function can update the cross type + * @note This function is allowed to run within ISR context including intr callbacks + * @note This function will be placed into IRAM if `CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` is on, + * so that it's allowed to be executed when Cache is disabled + * + * @param[in] cmpr The handle of analog comparator unit + * @param[in] cross_type The source signal cross type that can trigger the interrupt + * @return + * - ESP_OK Set denounce configuration success + * - ESP_ERR_INVALID_ARG NULL pointer of the parameters + */ +esp_err_t ana_cmpr_set_cross_type(ana_cmpr_handle_t cmpr, ana_cmpr_cross_type_t cross_type); + /** * @brief Register analog comparator interrupt event callbacks * @note This function can only be called before enabling the unit diff --git a/components/driver/analog_comparator/include/driver/ana_cmpr_types.h b/components/driver/analog_comparator/include/driver/ana_cmpr_types.h index 8f96c25a3c..a04ae0b52f 100644 --- a/components/driver/analog_comparator/include/driver/ana_cmpr_types.h +++ b/components/driver/analog_comparator/include/driver/ana_cmpr_types.h @@ -44,11 +44,11 @@ typedef enum { * */ typedef enum { - ANA_CMPR_INTR_DISABLE, /*!< Disable the cross event interrupt */ - ANA_CMPR_INTR_POS_CROSS, /*!< Enable the positive cross event interrupt */ - ANA_CMPR_INTR_NEG_CROSS, /*!< Enable the negative cross event interrupt */ - ANA_CMPR_INTR_ANY_CROSS, /*!< Enable the both positive & negative cross event interrupt */ -} ana_cmpr_intr_type_t; + ANA_CMPR_CROSS_DISABLE, /*!< Disable the cross event interrupt */ + ANA_CMPR_CROSS_POS, /*!< Positive cross can trigger event interrupt */ + ANA_CMPR_CROSS_NEG, /*!< Negative cross can trigger event interrupt */ + ANA_CMPR_CROSS_ANY, /*!< Any cross can trigger event interrupt */ +} ana_cmpr_cross_type_t; /** * @brief Analog comparator internal reference voltage diff --git a/components/driver/gpio/gpio.c b/components/driver/gpio/gpio.c index 971b2ac5d7..2a45dc356b 100644 --- a/components/driver/gpio/gpio.c +++ b/components/driver/gpio/gpio.c @@ -582,6 +582,9 @@ esp_err_t gpio_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, gpio_isr_alloc_t p; p.source = ETS_GPIO_INTR_SOURCE; p.intr_alloc_flags = intr_alloc_flags; +#if SOC_ANA_CMPR_SUPPORTED + p.intr_alloc_flags |= ESP_INTR_FLAG_SHARED; +#endif p.fn = fn; p.arg = arg; p.handle = handle; diff --git a/components/driver/linker.lf b/components/driver/linker.lf index 544ceff855..1f6f247879 100644 --- a/components/driver/linker.lf +++ b/components/driver/linker.lf @@ -19,8 +19,9 @@ entries: if SDM_CTRL_FUNC_IN_IRAM = y: sdm: sdm_channel_set_pulse_density (noflash) if ANA_CMPR_CTRL_FUNC_IN_IRAM = y: - ana_cmpr: ana_cmpr_set_intl_reference (noflash) + ana_cmpr: ana_cmpr_set_internal_reference (noflash) ana_cmpr: ana_cmpr_set_debounce (noflash) + ana_cmpr: ana_cmpr_set_cross_type (noflash) if DAC_CTRL_FUNC_IN_IRAM = y: dac_oneshot: dac_oneshot_output_voltage (noflash) dac_continuous: dac_continuous_write_asynchronously (noflash) diff --git a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c index 18389f407b..8235113afb 100644 --- a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c +++ b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c @@ -13,7 +13,7 @@ TEST_CASE("ana_cmpr_unit_install_uninstall", "[ana_cmpr]") .unit = SOC_ANA_CMPR_NUM, // Set a wrong unit .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, .ref_src = ANA_CMPR_REF_SRC_INTERNAL, - .intr_type = ANA_CMPR_INTR_ANY_CROSS, + .cross_type = ANA_CMPR_CROSS_ANY, }; /* Allocate a wrong unit */ TEST_ESP_ERR(ESP_ERR_INVALID_ARG, ana_cmpr_new_unit(&config, &cmpr)); @@ -23,15 +23,15 @@ TEST_CASE("ana_cmpr_unit_install_uninstall", "[ana_cmpr]") /* Try to allocate a existed unit */ TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_new_unit(&config, &cmpr)); /* Set the internal reference before enable */ - ana_cmpr_intl_ref_config_t ref_cfg = { + ana_cmpr_internal_ref_config_t ref_cfg = { .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, }; - TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + TEST_ESP_OK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg)); /* Enable the unit */ TEST_ESP_OK(ana_cmpr_enable(cmpr)); /* Set the internal reference after enable */ ref_cfg.ref_volt = ANA_CMPR_REF_VOLT_30_PCT_VDD; - TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + TEST_ESP_OK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg)); /* Try tp delete unit after enable */ TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_del_unit(cmpr)); /* Disable the unit */ @@ -44,7 +44,7 @@ TEST_CASE("ana_cmpr_unit_install_uninstall", "[ana_cmpr]") /* Try to set internal reference for a external unit */ config.ref_src = ANA_CMPR_REF_SRC_EXTERNAL; TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); - TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_set_internal_reference(cmpr, &ref_cfg)); TEST_ESP_OK(ana_cmpr_del_unit(cmpr)); } @@ -58,13 +58,13 @@ TEST_CASE("ana_cmpr_internal_reference", "[ana_cmpr]") .unit = ANA_CMPR_UNIT_0, .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, .ref_src = ANA_CMPR_REF_SRC_INTERNAL, - .intr_type = ANA_CMPR_INTR_ANY_CROSS, + .cross_type = ANA_CMPR_CROSS_ANY, }; TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); - ana_cmpr_intl_ref_config_t ref_cfg = { + ana_cmpr_internal_ref_config_t ref_cfg = { .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, }; - TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + TEST_ESP_OK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg)); ana_cmpr_debounce_config_t dbc_cfg = { .wait_us = 10.0, }; diff --git a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c index 3b929fb267..ce0d5425f9 100644 --- a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c +++ b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c @@ -14,29 +14,23 @@ typedef struct { int src_chan; } test_ana_cmpr_data_t; -/** - * @brief Global debounce configuration - * @note Why it is global? - * If we declare a local variable in 'float' type when cache disabled, - * it may be allocated in the flash, which can lead crash when trying to access it. - */ -static ana_cmpr_debounce_config_t IRAM_ATTR s_dbc_cfg = { - .wait_us = 1.0, -}; - static void IRAM_ATTR test_ana_cmpr_iram_safety(void *args) { test_ana_cmpr_data_t *data = (test_ana_cmpr_data_t *)args; - ana_cmpr_intl_ref_config_t ref_cfg = { + ana_cmpr_internal_ref_config_t ref_cfg = { .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, }; - ana_cmpr_set_intl_reference(data->handle, &ref_cfg); - ana_cmpr_set_debounce(data->handle, &s_dbc_cfg); + ana_cmpr_set_internal_reference(data->handle, &ref_cfg); + ana_cmpr_debounce_config_t dbc_cfg = { + .wait_us = 1, + }; + ana_cmpr_set_debounce(data->handle, &dbc_cfg); data->count = 0; for (int i = 1; i <= 10; i++) { test_simulate_src_signal(data->src_chan, i % 2); esp_rom_delay_us(100); } + ana_cmpr_set_cross_type(data->handle, ANA_CMPR_CROSS_POS); } TEST_CASE("ana_cmpr_internal_reference_iram_safe", "[ana_cmpr]") @@ -53,15 +47,18 @@ TEST_CASE("ana_cmpr_internal_reference_iram_safe", "[ana_cmpr]") .unit = ANA_CMPR_UNIT_0, .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, .ref_src = ANA_CMPR_REF_SRC_INTERNAL, - .intr_type = ANA_CMPR_INTR_ANY_CROSS, + .cross_type = ANA_CMPR_CROSS_ANY, }; TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); test_data.handle = cmpr; - ana_cmpr_intl_ref_config_t ref_cfg = { + ana_cmpr_internal_ref_config_t ref_cfg = { .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, }; - TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); - TEST_ESP_OK(ana_cmpr_set_debounce(cmpr, &s_dbc_cfg)); + TEST_ESP_OK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg)); + ana_cmpr_debounce_config_t dbc_cfg = { + .wait_us = 10, + }; + TEST_ESP_OK(ana_cmpr_set_debounce(cmpr, &dbc_cfg)); ana_cmpr_event_callbacks_t cbs = { .on_cross = test_ana_cmpr_on_cross_callback, }; diff --git a/components/hal/esp32h2/include/hal/ana_cmpr_ll.h b/components/hal/esp32h2/include/hal/ana_cmpr_ll.h index ffedbfde61..a818ea8b47 100644 --- a/components/hal/esp32h2/include/hal/ana_cmpr_ll.h +++ b/components/hal/esp32h2/include/hal/ana_cmpr_ll.h @@ -63,7 +63,7 @@ static inline float analog_cmpr_ll_get_internal_ref_voltage(analog_cmpr_dev_t *h * @param hw Analog comparator register base address * @param ref_src reference source, 0 for internal, 1 for external GPIO pad (GPIO10) */ -static inline void analog_cmpr_ll_ref_source(analog_cmpr_dev_t *hw, uint32_t ref_src) +static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, uint32_t ref_src) { hw->pad_comp_config.mode_comp = ref_src; } @@ -78,7 +78,8 @@ static inline void analog_cmpr_ll_ref_source(analog_cmpr_dev_t *hw, uint32_t ref * - 2: enable negative cross interrupt (input analog goes from high to low and across the reference voltage) * - 3: enable any positive or negative cross interrupt */ -static inline void analog_cmpr_ll_set_cross_intr_type(analog_cmpr_dev_t *hw, uint8_t type) +__attribute__((always_inline)) +static inline void analog_cmpr_ll_set_cross_type(analog_cmpr_dev_t *hw, uint8_t type) { hw->pad_comp_config.zero_det_mode = type; } diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 0c0dda8fbe..1fbfcdc5ca 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -87,10 +87,6 @@ config SOC_SDM_SUPPORTED bool default y -config SOC_ANALOG_CMPR_SUPPORTED - bool - default y - config SOC_ETM_SUPPORTED bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 12c36981b0..297dd44882 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -46,7 +46,6 @@ #define SOC_RTC_MEM_SUPPORTED 1 #define SOC_I2S_SUPPORTED 1 #define SOC_SDM_SUPPORTED 1 -#define SOC_ANALOG_CMPR_SUPPORTED 1 #define SOC_ETM_SUPPORTED 1 #define SOC_RMT_SUPPORTED 1 #define SOC_PARLIO_SUPPORTED 1 diff --git a/docs/conf_common.py b/docs/conf_common.py index 6c379cfc4f..1b6120bacb 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -127,6 +127,8 @@ ADC_DOCS = ['api-reference/peripherals/adc_oneshot.rst', 'api-reference/peripherals/adc_calibration.rst'] ADC_DMA_DOCS = ['api-reference/peripherals/adc_continuous.rst'] +ANA_CMPR_DOCS = ['api-reference/peripherals/ana_cmpr.rst'] + ESP32_DOCS = ['api-reference/system/himem.rst', 'api-guides/romconsole.rst', 'api-reference/system/ipc.rst', @@ -194,6 +196,7 @@ conditional_include_dict = {'SOC_BT_SUPPORTED':BT_DOCS, 'SOC_RTC_MEM_SUPPORTED': RTC_MEM_DOCS, 'SOC_ADC_SUPPORTED':ADC_DOCS, 'SOC_ADC_DMA_SUPPORTED':ADC_DMA_DOCS, + 'SOC_ANA_CMPR_SUPPORTED': ANA_CMPR_DOCS, 'SOC_SDM_SUPPORTED':SDM_DOCS, 'SOC_WIFI_MESH_SUPPORT':WIFI_MESH_DOCS, 'esp32':ESP32_DOCS, diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 63be6bbe0f..85a656d49d 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -61,6 +61,8 @@ INPUT = \ $(PROJECT_PATH)/components/bt/host/nimble/esp-hci/include/esp_nimble_hci.h \ $(PROJECT_PATH)/components/bt/include/esp32/include/esp_bt.h \ $(PROJECT_PATH)/components/console/esp_console.h \ + $(PROJECT_PATH)/components/driver/analog_comparator/include/driver/ana_cmpr.h \ + $(PROJECT_PATH)/components/driver/analog_comparator/include/driver/ana_cmpr_types.h \ $(PROJECT_PATH)/components/driver/dac/include/driver/dac_continuous.h \ $(PROJECT_PATH)/components/driver/dac/include/driver/dac_cosine.h \ $(PROJECT_PATH)/components/driver/dac/include/driver/dac_oneshot.h \ diff --git a/docs/en/api-reference/peripherals/ana_cmpr.rst b/docs/en/api-reference/peripherals/ana_cmpr.rst new file mode 100644 index 0000000000..1534f6add5 --- /dev/null +++ b/docs/en/api-reference/peripherals/ana_cmpr.rst @@ -0,0 +1,195 @@ +Analog Comparator +================= + +{IDF_TARGET_ANA_CMPR_NUM: default="NOT UPDATED", esp32h2="one"} +{IDF_TARGET_ANA_CMPR_SRC_CHAN: default="NOT UPDATED", esp32h2="GPIO11"} +{IDF_TARGET_ANA_CMPR_EXT_REF_CHAN: default="NOT UPDATED", esp32h2="GPIO10"} + +Introduction +------------ + +Analog Comparator is a peripheral that can be used to compare a source signal with the internal reference voltage or an external reference signal. + +It is a cost effective way to replace an amplifier comparator in some scenarios. But unlike the continuous comparing of the amplifier comparator, ESP Analog Comparator is driven by a source clock, which decides the sampling frequency. + +Analog Comparator on {IDF_TARGET_NAME} has {IDF_TARGET_ANA_CMPR_NUM} unit(s), the channels in the unit(s) are: + +**UNIT0** + +- Source Channel: {IDF_TARGET_ANA_CMPR_SRC_CHAN} +- External Reference Channel: {IDF_TARGET_ANA_CMPR_EXT_REF_CHAN} +- Internal Reference Channel: Range 0% ~ 70% VDD, step 10% VDD + +Functional Overview +------------------- + +The following sections of this document cover the typical steps to install and operate an Analog Comparator unit: + +- `Resource Allocation <#resource-allocation>`__ - covers which parameters should be set up to get a unit handle and how to recycle the resources when it finishes working. +- `Further Configurations <#further-configurations>`__ - covers the other configurations that might need to specific and what they are used for. +- `Enable and Disable Unit <#enable-and-disable-unit>`__ - covers how to enable and disable the unit. +- `Power Management <#power-management>`__ - describes how different source clock selections can affect power consumption. +- `IRAM Safe <#iram-safe>`__ - lists which functions are supposed to work even when the cache is disabled. +- `Thread Safety <#thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver. +- `Kconfig Options <#kconfig-options>`__ - lists the supported Kconfig options that can be used to make a different effect on driver behavior. + +Resource Allocation +^^^^^^^^^^^^^^^^^^^ + +An Analog Comparator unit channel is represented by :cpp:type:`ana_cmpr_handle_t`. Each unit can support either an internal or an external reference. + +To allocate the resource of the Analog Comparator unit, :cpp:func:`ana_cmpr_new_unit` need to be called to get the handle of the unit. Configurations :cpp:type:`ana_cmpr_config_t` need to be specified while allocating the unit: + +- :cpp:member:`ana_cmpr_config_t::unit` selects the Analog Comparator unit. +- :cpp:member:`ana_cmpr_config_t::clk_src` selects the source clock for Analog Comparator, it can affect the sampling frequency. Note that the clock source of the Analog Comparator comes from the io mux, it is shared with GPIO extension peripherals like SDM (Sigma-Delta Modulation) and Glitch Filter. The configuration will fail if you specific different clock sources for multiple GPIO extension peripherals. The default clock sources of these peripherals are same, typically, we select :cpp:enumerator:`soc_periph_ana_cmpr_clk_src_t::ANA_CMPR_CLK_SRC_DEFAULT` as the clock source. +- :cpp:member:`ana_cmpr_config_t::ref_src` selects the reference source from internal voltage or external signal (from {IDF_TARGET_ANA_CMPR_EXT_REF_CHAN}). +- :cpp:member:`ana_cmpr_config_t::cross_type` selects which kind of cross type can trigger the interrupt. + +The function :cpp:func:`ana_cmpr_new_unit` can fail due to various errors such as insufficient memory, invalid arguments, etc. If a previously created Analog Comparator unit is no longer required, you should recycle it by calling :cpp:func:`ana_cmpr_del_unit`. It allows the underlying HW channel to be used for other purposes. Before deleting an Analog Comparator unit handle, you should disable it by :cpp:func:`ana_cmpr_unit_disable` in advance, or make sure it has not enabled yet by :cpp:func:`ana_cmpr_unit_enable`. + +.. code:: c + + #include "driver/ana_cmpr.h" + + ana_cmpr_handle_t cmpr = NULL; + ana_cmpr_config_t config = { + .unit = ANA_CMPR_UNIT_0, + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_INTERNAL, + .cross_type = ANA_CMPR_CROSS_ANY, + }; + ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr)); + // ... + ESP_ERROR_CHECK(ana_cmpr_del_unit(cmpr)); + +Further Configurations +^^^^^^^^^^^^^^^^^^^^^^ + +- :cpp:func:`ana_cmpr_set_intl_reference` - Specify the internal reference voltage when :cpp:enumerator:`ana_cmpr_ref_source_t::ANA_CMPR_REF_SRC_INTERNAL` is selected as reference source. + +It requires :cpp:member:`ana_cmpr_internal_ref_config_t::ref_volt` to specify the voltage. The voltage related to the VDD power supply, which can only support a certain fixed percentage of VDD. Currently on {IDF_TARGET_NAME}, the internal reference voltage can be range to 0~70% VDD with a step 10%. + +.. code:: c + + #include "driver/ana_cmpr.h" + + ana_cmpr_internal_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, + }; + ESP_ERROR_CHECK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg)); + +- :cpp:func:`ana_cmpr_set_debounce` - Set the debounce configuration. + +It requires :cpp:member:`ana_cmpr_debounce_config_t::wait_us` to set the interrupt waiting time. The interrupt will be disabled temporary for :cpp:member:`ana_cmpr_debounce_config_t::wait_us` micro seconds, so that the frequent triggering can be avoid while the source signal crossing the reference signal. That is, the waiting time is supposed to be inverse ratio to the relative frequency between the source and reference. If the waiting time is set too short, it can't bypass the jitter totally, but if too long, the next crossing interrupt might be missed. + +.. code:: c + + #include "driver/ana_cmpr.h" + + ana_cmpr_debounce_config_t dbc_cfg = { + .wait_us = 1, + }; + ESP_ERROR_CHECK(ana_cmpr_set_debounce(cmpr, &dbc_cfg)); + +- :cpp:func:`ana_cmpr_set_cross_type` - Set the source signal cross type. + +The initial cross type is set int :cpp:func:`ana_cmpr_new_unit`, this function can update the cross type, even in ISR context. + +.. code:: c + + #include "driver/ana_cmpr.h" + + ESP_ERROR_CHECK(ana_cmpr_set_cross_type(cmpr, ANA_CMPR_CROSS_POS)); + +- :cpp:func:`ana_cmpr_register_event_callbacks` - Register the callbacks. + +Currently it supports :cpp:member:`ana_cmpr_event_callbacks_t::on_cross`, it will be called when the crossing event (specified by :cpp:member:`ana_cmpr_config_t::cross_type`) occurs. + +.. code:: c + + #include "driver/ana_cmpr.h" + + static bool IRAM_ATTR example_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, + const ana_cmpr_cross_event_data_t *edata, + void *user_ctx) + { + // ... + return false; + } + ana_cmpr_event_callbacks_t cbs = { + .on_cross = example_ana_cmpr_on_cross_callback, + }; + ESP_ERROR_CHECK(ana_cmpr_register_event_callbacks(cmpr, &cbs, NULL)); + +.. note:: + + When :ref:`CONFIG_ANA_CMPR_ISR_IRAM_SAFE` is enabled, you should guarantee the callback context and involved data to be in internal RAM by add the attribute ``IRAM_ATTR``. (See more in `IRAM Safe <#iram-safe>`__) + +Enable and Disable Unit +^^^^^^^^^^^^^^^^^^^^^^^ + +- :cpp:func:`ana_cmpr_enable` - Enable the Analog Comparator unit. +- :cpp:func:`ana_cmpr_disable` - Disable the Analog Comparator unit. + +After the Analog Comparator unit is enabled and the crossing event interrupt is enabled, a power management lock will be acquired if the power management is enabled (see `Power Management <#power-management>`__). Under the **enable** state, only :cpp:func:`ana_cmpr_set_intl_reference` and :cpp:func:`ana_cmpr_set_debounce` can be called, other functions can only be called after the unit is disabled. + +Calling :cpp:func:`ana_cmpr_disable` will do the opposite. + +Power Management +^^^^^^^^^^^^^^^^ + +When power management is enabled (i.e. :ref:`CONFIG_PM_ENABLE` is on), the system will adjust the APB frequency before going into light sleep, thus potentially changing the resolution of the Analog Comparator. + +However, the driver can prevent the system from changing APB frequency by acquiring a power management lock of type :cpp:enumerator:`ESP_PM_NO_LIGHT_SLEEP`. Whenever the driver creates a Analog Comparator unit instance that has selected the clock source like :cpp:enumerator:`ANA_CMPR_CLK_SRC_DEFAULT` or :cpp:enumerator:`ANA_CMPR_CLK_SRC_XTAL` as its clock source, the driver will guarantee that the power management lock is acquired when enable the channel by :cpp:func:`ana_cmpr_enable`. Likewise, the driver releases the lock when :cpp:func:`ana_cmpr_disable` is called for that channel. + +IRAM Safe +^^^^^^^^^ + +By default, the Analog Comparator interrupt will be deferred when the Cache is disabled for reasons like programming/erasing Flash. Thus the alarm interrupt will not get executed in time, which is not expected in a real-time application. + +There's a Kconfig option :ref:`CONFIG_ANA_CMPR_ISR_IRAM_SAFE` that will: + +1. Enable the interrupt being serviced even when cache is disabled +2. Place all functions that used by the ISR into IRAM [1]_ +3. Place driver object into DRAM (in case it's allocated on PSRAM) + +This will allow the interrupt to run while the cache is disabled but will come at the cost of increased IRAM consumption. + +There's a Kconfig option :ref:`CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` that can put commonly used IO control functions into IRAM as well. So that these functions can also be executable when the cache is disabled. These IO control functions are listed as follows: + +- :cpp:func:`ana_cmpr_set_internal_reference` +- :cpp:func:`ana_cmpr_set_debounce` +- :cpp:func:`ana_cmpr_set_cross_type` + +Thread Safety +^^^^^^^^^^^^^ + +The factory function :cpp:func:`ana_cmpr_new_unit` is guaranteed to be thread safe by the driver, which means, user can call it from different RTOS tasks without protection by extra locks. +The following functions are allowed to run under ISR context, the driver uses a critical section to prevent them being called concurrently in both task and ISR. + +- :cpp:func:`ana_cmpr_set_internal_reference` +- :cpp:func:`ana_cmpr_set_debounce` +- :cpp:func:`ana_cmpr_set_cross_type` + +Other functions that take the :cpp:type:`ana_cmpr_handle_t` as the first positional parameter, are not treated as thread safe. Which means the user should avoid calling them from multiple tasks. + +Kconfig Options +^^^^^^^^^^^^^^^ + +- :ref:`CONFIG_ANA_CMPR_ISR_IRAM_SAFE` controls whether the default ISR handler can work when cache is disabled, see `IRAM Safe <#iram-safe>`__ for more information. +- :ref:`CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` controls where to place the Analog Comparator control functions (IRAM or Flash), see `IRAM Safe <#iram-safe>`__ for more information. +- :ref:`CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG` is used to enabled the debug log output. Enabling this option will increase the firmware binary size. + +Application Example +------------------- + +* :example:`peripherals/analog_comparator` shows the basic usage of the analog comparator, and other potential usages like hysteresis comparator and SPWM generator. + +API Reference +------------- + +.. include-build-file:: inc/ana_cmpr.inc +.. include-build-file:: inc/ana_cmpr_types.inc + +.. [1] + :cpp:member:`ana_cmpr_event_callbacks_t::on_cross` callback and the functions invoked by itself should also be placed in IRAM, you need to take care of them by themselves. diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst index eeedfff718..5fd46d82e1 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -9,6 +9,7 @@ Peripherals API :SOC_ADC_SUPPORTED: adc_oneshot :SOC_ADC_DMA_SUPPORTED: adc_continuous :SOC_ADC_SUPPORTED: adc_calibration + :SOC_ANA_CMPR_SUPPORTED: ana_cmpr clk_tree :SOC_DAC_SUPPORTED: dac :SOC_ETM_SUPPORTED: etm diff --git a/docs/zh_CN/api-reference/peripherals/ana_cmpr.rst b/docs/zh_CN/api-reference/peripherals/ana_cmpr.rst new file mode 100644 index 0000000000..ab03d327dd --- /dev/null +++ b/docs/zh_CN/api-reference/peripherals/ana_cmpr.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/peripherals/ana_cmpr.rst diff --git a/docs/zh_CN/api-reference/peripherals/index.rst b/docs/zh_CN/api-reference/peripherals/index.rst index 6accad66da..7b436e0553 100644 --- a/docs/zh_CN/api-reference/peripherals/index.rst +++ b/docs/zh_CN/api-reference/peripherals/index.rst @@ -9,6 +9,7 @@ :SOC_ADC_SUPPORTED: adc_oneshot :SOC_ADC_DMA_SUPPORTED: adc_continuous :SOC_ADC_SUPPORTED: adc_calibration + :SOC_ANA_CMPR_SUPPORTED: ana_cmpr clk_tree :SOC_DAC_SUPPORTED: dac :SOC_ETM_SUPPORTED: etm diff --git a/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.c b/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.c index a885fa6a76..dff4003724 100644 --- a/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.c +++ b/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.c @@ -13,25 +13,25 @@ #define EXAMPLE_ANA_CMPR_UNIT ANA_CMPR_UNIT_0 // Analog Comparator unit #define EXAMPLE_WAIT_TIME_PROP (0.1) // The wait time proportion in one relative signal period -#define EXAMPLE_WAITE_TIME_US(freq_approx) (1000000.0 * EXAMPLE_WAIT_TIME_PROP / (freq_approx)) +#define EXAMPLE_WAITE_TIME_US(freq_approx) (uint32_t)(1000000 * EXAMPLE_WAIT_TIME_PROP / (freq_approx)) #define EXAMPLE_MONITOR_GPIO_NUM (0) // The gpio to monitor the on cross callback static const char *TAG = "ana_cmpr_example"; -static bool IRAM_ATTR example_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, +static bool example_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, const ana_cmpr_cross_event_data_t *edata, void *user_ctx) { #if CONFIG_EXAMPLE_HYSTERESIS_COMPARATOR - static ana_cmpr_intl_ref_config_t ref_cfg = { + static ana_cmpr_internal_ref_config_t ref_cfg = { .ref_volt = ANA_CMPR_REF_VOLT_70_PCT_VDD, }; bool is_70p = ref_cfg.ref_volt == ANA_CMPR_REF_VOLT_70_PCT_VDD; - /* Toggle the GPIO, monitor the gpio on a oscilloscope. */ + /* Toggle the GPIO, monitor the gpio on an oscilloscope. */ gpio_set_level(EXAMPLE_MONITOR_GPIO_NUM, is_70p); /* Set the internal reference voltage to 30% VDD and 70 %VDD alternately */ - ana_cmpr_set_intl_reference(cmpr, &ref_cfg); + ana_cmpr_set_internal_reference(cmpr, &ref_cfg); ref_cfg.ref_volt = is_70p ? ANA_CMPR_REF_VOLT_30_PCT_VDD : ANA_CMPR_REF_VOLT_70_PCT_VDD; #else static int lvl = 0; @@ -59,13 +59,13 @@ void example_init_analog_comparator(void) .unit = EXAMPLE_ANA_CMPR_UNIT, .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, .ref_src = ANA_CMPR_REF_SRC_INTERNAL, - .intr_type = ANA_CMPR_INTR_ANY_CROSS, + .cross_type = ANA_CMPR_CROSS_ANY, }; ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr)); ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference"); /* Step 1.1: As we are using the internal reference source, we need to configure the internal reference */ - ana_cmpr_intl_ref_config_t ref_cfg = { + ana_cmpr_internal_ref_config_t ref_cfg = { #if CONFIG_EXAMPLE_HYSTERESIS_COMPARATOR /* Set the initial internal reference voltage to 70% VDD, it will be updated in the callback every time the interrupt triggered */ .ref_volt = ANA_CMPR_REF_VOLT_70_PCT_VDD @@ -73,17 +73,17 @@ void example_init_analog_comparator(void) .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, #endif }; - ESP_ERROR_CHECK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + ESP_ERROR_CHECK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg)); #else /* Step 1: Allocate the new analog comparator unit */ ana_cmpr_config_t config = { .unit = EXAMPLE_ANA_CMPR_UNIT, .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, .ref_src = ANA_CMPR_REF_SRC_EXTERNAL, - .intr_type = ANA_CMPR_INTR_ANY_CROSS, + .cross_type = ANA_CMPR_CROSS_ANY, }; ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr)); - ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference"); + ESP_LOGI(TAG, "Allocate Analog Comparator with external reference"); #endif /* Step 2: (Optional) Set the debounce configuration @@ -92,7 +92,7 @@ void example_init_analog_comparator(void) * automatically enabled after `wait_us`, so that the duplicate interrupts * can be suppressed while the source signal crossing the reference signal. */ ana_cmpr_debounce_config_t dbc_cfg = { - /* Normally the `wait_us` is related to how fast the source signal or reference signal changes + /* Normally the `wait_us` is related to the relative frequency between the source and reference signal * comparing to another one. This example adopts an approximate frequency as the relative signal * frequency, and set the default wait time to EXAMPLE_WAIT_TIME_PROP of the relative signal period. * We need to estimate an appropriate `freq_approx` and EXAMPLE_WAIT_TIME_PROP diff --git a/examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py b/examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py index a5bba766e5..edd9e49067 100644 --- a/examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py +++ b/examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py @@ -22,5 +22,5 @@ def test_ana_cmpr_example(dut: Dut) -> None: dut.expect('ana_cmpr_example: Allocate Analog Comparator with internal reference', timeout=10) dut.expect(r'ana_cmpr_example: Analog comparator enabled, reference voltage: [0-9]+% \* VDD', timeout=10) elif sdkconfig['EXAMPLE_EXTERNAL_REF']: - dut.expect('ana_cmpr_example: Allocate Analog Comparator with internal reference', timeout=10) + dut.expect('ana_cmpr_example: Allocate Analog Comparator with external reference', timeout=10) dut.expect('ana_cmpr_example: Analog comparator enabled, external reference selected', timeout=10)