From e258c7c981093ca97887200f28706116e6f1556a Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 9 Apr 2026 16:23:34 +0800 Subject: [PATCH] feat(ana_cmpr): added low level functions for esp32h4 and esp32s31 --- components/esp_driver_ana_cmpr/ana_cmpr.c | 38 +- components/esp_driver_ana_cmpr/ana_cmpr_etm.c | 2 +- .../include/driver/ana_cmpr_etm.h | 9 - .../include/driver/ana_cmpr_types.h | 22 +- .../esp32c5/include/hal/ana_cmpr_ll.h | 150 ++++-- .../esp32c61/include/hal/ana_cmpr_ll.h | 150 ++++-- .../esp32h2/include/hal/ana_cmpr_ll.h | 121 ++++- .../esp32h21/include/hal/ana_cmpr_ll.h | 148 ++++-- .../esp32h4/ana_cmpr_periph.c | 20 + .../esp32h4/include/hal/ana_cmpr_ll.h | 491 ++++++++++++++++++ .../esp32p4/include/hal/ana_cmpr_ll.h | 149 ++++-- .../esp32s31/ana_cmpr_periph.c | 20 + .../esp32s31/include/hal/ana_cmpr_ll.h | 491 ++++++++++++++++++ .../include/hal/ana_cmpr_periph.h | 15 +- .../include/hal/ana_cmpr_types.h | 59 ++- 15 files changed, 1678 insertions(+), 207 deletions(-) create mode 100644 components/esp_hal_ana_cmpr/esp32h4/ana_cmpr_periph.c create mode 100644 components/esp_hal_ana_cmpr/esp32h4/include/hal/ana_cmpr_ll.h create mode 100644 components/esp_hal_ana_cmpr/esp32s31/ana_cmpr_periph.c create mode 100644 components/esp_hal_ana_cmpr/esp32s31/include/hal/ana_cmpr_ll.h diff --git a/components/esp_driver_ana_cmpr/ana_cmpr.c b/components/esp_driver_ana_cmpr/ana_cmpr.c index 9a7cdeefee..6a867836e2 100644 --- a/components/esp_driver_ana_cmpr/ana_cmpr.c +++ b/components/esp_driver_ana_cmpr/ana_cmpr.c @@ -65,9 +65,9 @@ void ana_cmpr_default_intr_handler(void *usr_data) if (cmpr_handle->cbs.on_cross && (status & cmpr_handle->intr_mask)) { // some chip can distinguish the edge of the cross event #if ANALOG_CMPR_LL_SUPPORT(EDGE_TYPE) - if (status & ANALOG_CMPR_LL_POS_CROSS_MASK(cmpr_handle->unit)) { + if (status & ANALOG_CMPR_LL_POS_CROSS_MASK(cmpr_handle->unit, 0)) { evt_data.cross_type = ANA_CMPR_CROSS_POS; - } else if (status & ANALOG_CMPR_LL_NEG_CROSS_MASK(cmpr_handle->unit)) { + } else if (status & ANALOG_CMPR_LL_NEG_CROSS_MASK(cmpr_handle->unit, 0)) { evt_data.cross_type = ANA_CMPR_CROSS_NEG; } #endif // ANALOG_CMPR_LL_SUPPORT(EDGE_TYPE) @@ -123,10 +123,25 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * ana_cmpr_hdl->unit = unit; ana_cmpr_hdl->intr_priority = config->intr_priority; atomic_init(&ana_cmpr_hdl->fsm, ANA_CMPR_FSM_INIT); - + // Enable bus clock + analog_cmpr_ll_enable_bus_clock(unit, true); + // Reset register + analog_cmpr_ll_reset_register(unit); ana_cmpr_clk_src_t clk_src = config->clk_src ? config->clk_src : ANA_CMPR_CLK_SRC_DEFAULT; - // Analog comparator located in the IO MUX, but IO MUX clock might be shared with other submodules as well, check if there's conflict +#if ANALOG_CMPR_LL_GET(IP_VERSION) > 1 + // Reset core + analog_cmpr_ll_reset_core(unit); + // Set clock source (use default if not specified in config) + analog_cmpr_ll_set_clk_src(unit, clk_src); + // Set clock divider to 1 + analog_cmpr_ll_set_clk_div(unit, 1); + // Enable function clock + analog_cmpr_ll_enable_function_clock(unit, true); +#else + // Analog comparator located in the IO MUX module in older chips, so the clock source is shared with IO MUX. + // TODO: Check if the clock source conflicts with other IOMUX consumers ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)clk_src), err, TAG, "clock source conflicts with other IOMUX consumers"); +#endif ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &ana_cmpr_hdl->src_clk_freq_hz), err, TAG, "get source clock frequency failed"); @@ -146,13 +161,13 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * #endif // !ANALOG_CMPR_LL_SUPPORT(EDGE_TYPE) // record the interrupt mask, the interrupt will be lazy installed when register user callbacks // different cross type means different interrupt mask - ana_cmpr_hdl->intr_mask = analog_cmpr_ll_get_intr_mask_by_type(ana_cmpr_hdl->dev, config->cross_type); + ana_cmpr_hdl->intr_mask = analog_cmpr_ll_get_intr_mask_by_type(unit, 0, config->cross_type); // different unit share the same interrupt register, so using a spin lock to protect it portENTER_CRITICAL(&s_spinlock); // disable the interrupt by default, and clear pending status - analog_cmpr_ll_enable_intr(ana_cmpr_hdl->dev, ANALOG_CMPR_LL_ALL_INTR_MASK(unit), false); - analog_cmpr_ll_clear_intr(ana_cmpr_hdl->dev, ANALOG_CMPR_LL_ALL_INTR_MASK(unit)); + analog_cmpr_ll_enable_intr(ana_cmpr_hdl->dev, ANALOG_CMPR_LL_ALL_INTR_MASK(unit, 0), false); + analog_cmpr_ll_clear_intr(ana_cmpr_hdl->dev, ANALOG_CMPR_LL_ALL_INTR_MASK(unit, 0)); portEXIT_CRITICAL(&s_spinlock); // GPIO configuration @@ -191,6 +206,11 @@ esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr) ESP_RETURN_ON_FALSE(unit != -1, ESP_ERR_INVALID_ARG, TAG, "unregistered unit handle"); ESP_RETURN_ON_FALSE(atomic_load(&cmpr->fsm) == ANA_CMPR_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "not in init state"); + // Disable function clock first + analog_cmpr_ll_enable_function_clock(unit, false); + // Disable bus clock last + analog_cmpr_ll_enable_bus_clock(unit, false); + ana_cmpr_destroy_unit(cmpr); // unregister it from the global object array s_ana_cmpr[unit] = NULL; @@ -225,7 +245,7 @@ esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_ uint32_t wait_cycle = dbc_cfg->wait_us * (cmpr->src_clk_freq_hz / 1000000); // the underlying register may be accessed by different threads at the same time, so use spin lock to protect it portENTER_CRITICAL_SAFE(&s_spinlock); - analog_cmpr_ll_set_debounce_cycle(cmpr->dev, wait_cycle); + analog_cmpr_ll_set_cross_debounce_cycle(cmpr->dev, wait_cycle); portEXIT_CRITICAL_SAFE(&s_spinlock); return ESP_OK; @@ -248,7 +268,7 @@ esp_err_t ana_cmpr_set_cross_type(ana_cmpr_handle_t cmpr, ana_cmpr_cross_type_t portENTER_CRITICAL_SAFE(&s_spinlock); analog_cmpr_ll_set_intr_cross_type(cmpr->dev, cross_type); - cmpr->intr_mask = analog_cmpr_ll_get_intr_mask_by_type(cmpr->dev, cross_type); + cmpr->intr_mask = analog_cmpr_ll_get_intr_mask_by_type(cmpr->unit, 0, cross_type); portEXIT_CRITICAL_SAFE(&s_spinlock); return ESP_OK; diff --git a/components/esp_driver_ana_cmpr/ana_cmpr_etm.c b/components/esp_driver_ana_cmpr/ana_cmpr_etm.c index f869224662..f179824a9c 100644 --- a/components/esp_driver_ana_cmpr/ana_cmpr_etm.c +++ b/components/esp_driver_ana_cmpr/ana_cmpr_etm.c @@ -29,7 +29,7 @@ esp_err_t ana_cmpr_new_etm_event(ana_cmpr_handle_t cmpr, const ana_cmpr_etm_even ana_cmpr_etm_event_t *event = heap_caps_calloc(1, sizeof(ana_cmpr_etm_event_t), ETM_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(event, ESP_ERR_NO_MEM, TAG, "no mem for analog comparator event"); - uint32_t event_id = ANALOG_CMPR_LL_ETM_SOURCE(unit, config->event_type); + uint32_t event_id = ANALOG_CMPR_LL_ETM_SOURCE(unit, 0, config->event_type); event->base.del = ana_cmpr_del_etm_event; event->base.event_id = event_id; event->base.trig_periph = ETM_TRIG_PERIPH_ANA_CMPR; diff --git a/components/esp_driver_ana_cmpr/include/driver/ana_cmpr_etm.h b/components/esp_driver_ana_cmpr/include/driver/ana_cmpr_etm.h index dce8345238..87480189c4 100644 --- a/components/esp_driver_ana_cmpr/include/driver/ana_cmpr_etm.h +++ b/components/esp_driver_ana_cmpr/include/driver/ana_cmpr_etm.h @@ -17,15 +17,6 @@ extern "C" { #endif -/** - * @brief Analog Comparator ETM Events for each unit - * - */ -typedef enum { - ANA_CMPR_EVENT_POS_CROSS, /*!< Positive cross event when the source signal becomes higher than the reference signal */ - ANA_CMPR_EVENT_NEG_CROSS, /*!< Negative cross event when the source signal becomes lower than the reference signal */ -} ana_cmpr_event_type_t; - /** * @brief Analog Comparator ETM event configuration * diff --git a/components/esp_driver_ana_cmpr/include/driver/ana_cmpr_types.h b/components/esp_driver_ana_cmpr/include/driver/ana_cmpr_types.h index f48881be87..940d5345ae 100644 --- a/components/esp_driver_ana_cmpr/include/driver/ana_cmpr_types.h +++ b/components/esp_driver_ana_cmpr/include/driver/ana_cmpr_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,14 +22,6 @@ typedef int ana_cmpr_unit_t; #define ANA_CMPR_UNIT_0 0 /*!< @deprecated Analog comparator unit 0 */ -/** - * @brief Analog comparator reference source - */ -typedef enum { - ANA_CMPR_REF_SRC_INTERNAL, /*!< Analog Comparator reference voltage comes from internal, divided from VDD */ - ANA_CMPR_REF_SRC_EXTERNAL, /*!< Analog Comparator reference voltage comes from external pin, e.g. `ANA_CMPR0_EXT_REF_GPIO` */ -} ana_cmpr_ref_source_t; - /** * @brief Analog comparator channel type */ @@ -43,18 +35,6 @@ typedef enum { */ 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 */ diff --git a/components/esp_hal_ana_cmpr/esp32c5/include/hal/ana_cmpr_ll.h b/components/esp_hal_ana_cmpr/esp32c5/include/hal/ana_cmpr_ll.h index d579480455..bfb5e940d6 100644 --- a/components/esp_hal_ana_cmpr/esp32c5/include/hal/ana_cmpr_ll.h +++ b/components/esp_hal_ana_cmpr/esp32c5/include/hal/ana_cmpr_ll.h @@ -23,19 +23,55 @@ extern "C" { // Number of Analog Comparator instances #define ANALOG_CMPR_LL_INST_NUM 1 +// ANA_CMPR IP version +#define ANALOG_CMPR_LL_IP_VERSION 1 + +// Number of pads for each Analog Comparator instance +#define ANALOG_CMPR_LL_PAD_NUM 2 + +// Number of source channels for the comparator +#define ANALOG_CMPR_LL_SRC_CHANNEL_NUM 1 + // Can detect positive/negative/any cross type #define ANALOG_CMPR_LL_SUPPORT_EDGE_TYPE 1 #define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit]) -#define ANALOG_CMPR_LL_GET_UNIT(hw) (0) -#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 0)) -#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1)) -#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 2)) +#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 0)) +#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 1)) +#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 2)) -#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit)) +#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit, src_chan) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan)) -#define ANALOG_CMPR_LL_ETM_SOURCE(unit, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type)) +#define ANALOG_CMPR_LL_ETM_SOURCE(unit, src_chan, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type)) + +/** + * @brief Get the interrupt mask from the given cross type + * + * @param unit_id Unit ID + * @param src_chan Source channel ID + * @param type Cross type + * @return Interrupt mask value + */ +__attribute__((always_inline)) +static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(uint32_t unit_id, uint32_t src_chan, ana_cmpr_cross_type_t type) +{ + uint32_t mask = 0; + switch (type) { + case ANA_CMPR_CROSS_POS: + mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_NEG: + mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_ANY: + mask |= ANALOG_CMPR_LL_ANY_CROSS_MASK(unit_id, src_chan); + break; + default: + break; + } + return mask; +} /** * @brief Enable analog comparator @@ -55,7 +91,7 @@ static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en) * @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) +static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw, ana_cmpr_ref_voltage_t volt_level) { hw->pad_comp_config->dref_comp_0 = volt_level; } @@ -77,38 +113,13 @@ static inline float analog_cmpr_ll_get_internal_ref_voltage(analog_cmpr_dev_t *h * @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) + * @param ref_src reference source, 0 for internal, 1 for external GPIO pad */ -static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_voltage_t ref_src) +static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_source_t ref_src) { hw->pad_comp_config->mode_comp_0 = ref_src; } -/** - * @brief Get the interrupt mask by 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 - * @return interrupt mask - */ -__attribute__((always_inline)) -static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *hw, ana_cmpr_cross_type_t type) -{ - uint32_t unit = ANALOG_CMPR_LL_GET_UNIT(hw); - uint32_t mask = 0; - if (type & 0x01) { - mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit); - } - if (type & 0x02) { - mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit); - } - return mask; -} - /** * @brief Set the debounce cycle for the cross detection * @@ -118,7 +129,7 @@ static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *h * @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) +static inline void analog_cmpr_ll_set_cross_debounce_cycle(analog_cmpr_dev_t *hw, uint32_t cycle) { hw->pad_comp_filter->zero_det_filter_cnt_0 = cycle; } @@ -175,6 +186,75 @@ static inline volatile void *analog_cmpr_ll_get_intr_status_reg(analog_cmpr_dev_ return hw->int_st; } +/** + * @brief Enable the bus clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_bus_clock(int unit_id, bool enable) +{ + (void)unit_id; + (void)enable; +} + +/** + * @brief Reset the Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_register(int unit_id) +{ + (void)unit_id; +} + +/** + * @brief Reset the core logic of Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_core(int unit_id) +{ + (void)unit_id; +} + +/** + * @brief Set the clock source for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param clk_src Clock source, see `ana_cmpr_clk_src_t` + */ +static inline void analog_cmpr_ll_set_clk_src(int unit_id, ana_cmpr_clk_src_t clk_src) +{ + (void)unit_id; + (void)clk_src; +} + +/** + * @brief Enable the function clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_function_clock(int unit_id, bool enable) +{ + (void)unit_id; + (void)enable; +} + +/** + * @brief Set the clock divider for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param div Clock divider value, the output clock frequency is input clock frequency divided by this value. + * Must be greater than 0. + */ +static inline void analog_cmpr_ll_set_clk_div(int unit_id, uint32_t div) +{ + (void)unit_id; + (void)div; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_ana_cmpr/esp32c61/include/hal/ana_cmpr_ll.h b/components/esp_hal_ana_cmpr/esp32c61/include/hal/ana_cmpr_ll.h index d579480455..35720ae3da 100644 --- a/components/esp_hal_ana_cmpr/esp32c61/include/hal/ana_cmpr_ll.h +++ b/components/esp_hal_ana_cmpr/esp32c61/include/hal/ana_cmpr_ll.h @@ -23,19 +23,55 @@ extern "C" { // Number of Analog Comparator instances #define ANALOG_CMPR_LL_INST_NUM 1 +// ANA_CMPR IP version +#define ANALOG_CMPR_LL_IP_VERSION 1 + +// Number of pads for each Analog Comparator instance +#define ANALOG_CMPR_LL_PAD_NUM 2 + +// Number of source channels for the comparator +#define ANALOG_CMPR_LL_SRC_CHANNEL_NUM 1 + // Can detect positive/negative/any cross type #define ANALOG_CMPR_LL_SUPPORT_EDGE_TYPE 1 #define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit]) -#define ANALOG_CMPR_LL_GET_UNIT(hw) (0) -#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 0)) -#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1)) -#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 2)) +#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 0)) +#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 1)) +#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 2)) -#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit)) +#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit, src_chan) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan)) -#define ANALOG_CMPR_LL_ETM_SOURCE(unit, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type)) +#define ANALOG_CMPR_LL_ETM_SOURCE(unit, src_chan, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type)) + +/** + * @brief Get the interrupt mask from the given cross type + * + * @param unit_id Unit ID + * @param src_chan Source channel ID + * @param type Cross type + * @return Interrupt mask value + */ +__attribute__((always_inline)) +static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(uint32_t unit_id, uint32_t src_chan, ana_cmpr_cross_type_t type) +{ + uint32_t mask = 0; + switch (type) { + case ANA_CMPR_CROSS_POS: + mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_NEG: + mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_ANY: + mask |= ANALOG_CMPR_LL_ANY_CROSS_MASK(unit_id, src_chan); + break; + default: + break; + } + return mask; +} /** * @brief Enable analog comparator @@ -55,7 +91,7 @@ static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en) * @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) +static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw, ana_cmpr_ref_voltage_t volt_level) { hw->pad_comp_config->dref_comp_0 = volt_level; } @@ -77,38 +113,13 @@ static inline float analog_cmpr_ll_get_internal_ref_voltage(analog_cmpr_dev_t *h * @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) + * @param ref_src reference source, 0 for internal, 1 for external GPIO pad */ -static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_voltage_t ref_src) +static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_source_t ref_src) { hw->pad_comp_config->mode_comp_0 = ref_src; } -/** - * @brief Get the interrupt mask by 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 - * @return interrupt mask - */ -__attribute__((always_inline)) -static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *hw, ana_cmpr_cross_type_t type) -{ - uint32_t unit = ANALOG_CMPR_LL_GET_UNIT(hw); - uint32_t mask = 0; - if (type & 0x01) { - mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit); - } - if (type & 0x02) { - mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit); - } - return mask; -} - /** * @brief Set the debounce cycle for the cross detection * @@ -118,7 +129,7 @@ static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *h * @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) +static inline void analog_cmpr_ll_set_cross_debounce_cycle(analog_cmpr_dev_t *hw, uint32_t cycle) { hw->pad_comp_filter->zero_det_filter_cnt_0 = cycle; } @@ -175,6 +186,75 @@ static inline volatile void *analog_cmpr_ll_get_intr_status_reg(analog_cmpr_dev_ return hw->int_st; } +/** + * @brief Enable the bus clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_bus_clock(int unit_id, bool enable) +{ + (void)unit_id; + (void)enable; +} + +/** + * @brief Reset the Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_register(int unit_id) +{ + (void)unit_id; +} + +/** + * @brief Reset the core logic of Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_core(int unit_id) +{ + (void)unit_id; +} + +/** + * @brief Set the clock source for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param clk_src Clock source, see `ana_cmpr_clk_src_t` + */ +static inline void analog_cmpr_ll_set_clk_src(int unit_id, ana_cmpr_clk_src_t clk_src) +{ + (void)unit_id; + (void)clk_src; +} + +/** + * @brief Enable the function clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_function_clock(int unit_id, bool enable) +{ + (void)unit_id; + (void)enable; +} + +/** + * @brief Set the clock divider for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param div Clock divider value, the output clock frequency is input clock frequency divided by this value. + * Must be greater than 0. + */ +static inline void analog_cmpr_ll_set_clk_div(int unit_id, uint32_t div) +{ + (void)unit_id; + (void)div; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_ana_cmpr/esp32h2/include/hal/ana_cmpr_ll.h b/components/esp_hal_ana_cmpr/esp32h2/include/hal/ana_cmpr_ll.h index b07d400812..cb5a1569d5 100644 --- a/components/esp_hal_ana_cmpr/esp32h2/include/hal/ana_cmpr_ll.h +++ b/components/esp_hal_ana_cmpr/esp32h2/include/hal/ana_cmpr_ll.h @@ -18,15 +18,41 @@ // Number of Analog Comparator instances #define ANALOG_CMPR_LL_INST_NUM 1 +// ANA_CMPR IP version +#define ANALOG_CMPR_LL_IP_VERSION 1 + +// Number of pads for each Analog Comparator instance +#define ANALOG_CMPR_LL_PAD_NUM 2 + +// Number of source channels for the comparator +#define ANALOG_CMPR_LL_SRC_CHANNEL_NUM 1 + #define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit]) #define ANALOG_CMPR_LL_EVENT_CROSS (1 << 0) -#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit) (ANALOG_CMPR_LL_EVENT_CROSS) +#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit, src_chan) (ANALOG_CMPR_LL_EVENT_CROSS) #ifdef __cplusplus extern "C" { #endif +/** + * @brief Get the interrupt mask from the given cross type + * + * @param unit_id Unit ID + * @param src_chan Source channel ID + * @param type Cross type + * @return Interrupt mask value + */ +__attribute__((always_inline)) +static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(uint32_t unit_id, uint32_t src_chan, ana_cmpr_cross_type_t type) +{ + (void)type; + (void)unit_id; + (void)src_chan; + return ANALOG_CMPR_LL_EVENT_CROSS; +} + /** * @brief Enable analog comparator * @@ -45,7 +71,7 @@ static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en) * @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) +static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw, ana_cmpr_ref_voltage_t volt_level) { hw->pad_comp_config->dref_comp = volt_level; } @@ -67,9 +93,9 @@ static inline uint32_t analog_cmpr_ll_get_internal_ref_voltage(analog_cmpr_dev_t * @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) + * @param ref_src reference source, 0 for internal, 1 for external GPIO pad */ -static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_voltage_t ref_src) +static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_source_t ref_src) { hw->pad_comp_config->mode_comp = ref_src; } @@ -90,22 +116,6 @@ static inline void analog_cmpr_ll_set_intr_cross_type(analog_cmpr_dev_t *hw, ana hw->pad_comp_config->zero_det_mode = type; } -/** - * @brief Get the interrupt mask by trigger type - * @note Only one interrupt on H2 - * - * @param hw Analog comparator register base address - * @param type Not used on H2, because H2 can't distinguish the edge type - * The parameter here only to be compatible with other targets - * @return interrupt mask - */ -__attribute__((always_inline)) -static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *hw, ana_cmpr_cross_type_t type) -{ - (void)type; - return ANALOG_CMPR_LL_EVENT_CROSS; -} - /** * @brief Set the debounce cycle for the cross detection * @@ -115,7 +125,7 @@ static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *h * @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) +static inline void analog_cmpr_ll_set_cross_debounce_cycle(analog_cmpr_dev_t *hw, uint32_t cycle) { hw->pad_comp_filter->zero_det_filter_cnt = cycle; } @@ -172,6 +182,75 @@ static inline volatile void *analog_cmpr_ll_get_intr_status_reg(analog_cmpr_dev_ return hw->int_st; } +/** + * @brief Enable the bus clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_bus_clock(int unit_id, bool enable) +{ + (void)unit_id; + (void)enable; +} + +/** + * @brief Reset the Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_register(int unit_id) +{ + (void)unit_id; +} + +/** + * @brief Reset the core logic of Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_core(int unit_id) +{ + (void)unit_id; +} + +/** + * @brief Set the clock source for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param clk_src Clock source, see `ana_cmpr_clk_src_t` + */ +static inline void analog_cmpr_ll_set_clk_src(int unit_id, ana_cmpr_clk_src_t clk_src) +{ + (void)unit_id; + (void)clk_src; +} + +/** + * @brief Enable the function clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_function_clock(int unit_id, bool enable) +{ + (void)unit_id; + (void)enable; +} + +/** + * @brief Set the clock divider for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param div Clock divider value, the output clock frequency is input clock frequency divided by this value. + * Must be greater than 0. + */ +static inline void analog_cmpr_ll_set_clk_div(int unit_id, uint32_t div) +{ + (void)unit_id; + (void)div; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_ana_cmpr/esp32h21/include/hal/ana_cmpr_ll.h b/components/esp_hal_ana_cmpr/esp32h21/include/hal/ana_cmpr_ll.h index 3762b39da5..9e5461a3c1 100644 --- a/components/esp_hal_ana_cmpr/esp32h21/include/hal/ana_cmpr_ll.h +++ b/components/esp_hal_ana_cmpr/esp32h21/include/hal/ana_cmpr_ll.h @@ -22,17 +22,53 @@ extern "C" { // Number of Analog Comparator instances #define ANALOG_CMPR_LL_INST_NUM 1 +// ANA_CMPR IP version +#define ANALOG_CMPR_LL_IP_VERSION 1 + +// Number of pads for each Analog Comparator instance +#define ANALOG_CMPR_LL_PAD_NUM 2 + +// Number of source channels for the comparator +#define ANALOG_CMPR_LL_SRC_CHANNEL_NUM 1 + // Can detect positive/negative/any cross type #define ANALOG_CMPR_LL_SUPPORT_EDGE_TYPE 1 #define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit]) -#define ANALOG_CMPR_LL_GET_UNIT(hw) (0) -#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 0)) -#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1)) -#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 2)) +#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 0)) +#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 1)) +#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 2)) -#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit)) +#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit, src_chan) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan)) + +/** + * @brief Get the interrupt mask from the given cross type + * + * @param unit_id Unit ID + * @param src_chan Source channel ID + * @param type Cross type + * @return Interrupt mask value + */ +__attribute__((always_inline)) +static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(uint32_t unit_id, uint32_t src_chan, ana_cmpr_cross_type_t type) +{ + uint32_t mask = 0; + switch (type) { + case ANA_CMPR_CROSS_POS: + mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_NEG: + mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_ANY: + mask |= ANALOG_CMPR_LL_ANY_CROSS_MASK(unit_id, src_chan); + break; + default: + break; + } + return mask; +} /** * @brief Enable analog comparator @@ -52,7 +88,7 @@ static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en) * @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) +static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw, ana_cmpr_ref_voltage_t volt_level) { hw->pad_comp_config->ext_dref_comp_0 = volt_level; } @@ -74,38 +110,13 @@ static inline float analog_cmpr_ll_get_internal_ref_voltage(analog_cmpr_dev_t *h * @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) + * @param ref_src reference source, 0 for internal, 1 for external GPIO pad */ -static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_voltage_t ref_src) +static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_source_t ref_src) { hw->pad_comp_config->ext_mode_comp_0 = ref_src; } -/** - * @brief Get the interrupt mask by 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 - * @return interrupt mask - */ -__attribute__((always_inline)) -static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *hw, ana_cmpr_cross_type_t type) -{ - uint32_t unit = ANALOG_CMPR_LL_GET_UNIT(hw); - uint32_t mask = 0; - if (type & 0x01) { - mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit); - } - if (type & 0x02) { - mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit); - } - return mask; -} - /** * @brief Set the debounce cycle for the cross detection * @@ -115,7 +126,7 @@ static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *h * @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) +static inline void analog_cmpr_ll_set_cross_debounce_cycle(analog_cmpr_dev_t *hw, uint32_t cycle) { hw->pad_comp_filter->ext_zero_det_filter_cnt_0 = cycle; } @@ -172,6 +183,75 @@ static inline volatile void *analog_cmpr_ll_get_intr_status_reg(analog_cmpr_dev_ return hw->int_st; } +/** + * @brief Enable the bus clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_bus_clock(int unit_id, bool enable) +{ + (void)unit_id; + (void)enable; +} + +/** + * @brief Reset the Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_register(int unit_id) +{ + (void)unit_id; +} + +/** + * @brief Reset the core logic of Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_core(int unit_id) +{ + (void)unit_id; +} + +/** + * @brief Set the clock source for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param clk_src Clock source, see `ana_cmpr_clk_src_t` + */ +static inline void analog_cmpr_ll_set_clk_src(int unit_id, ana_cmpr_clk_src_t clk_src) +{ + (void)unit_id; + (void)clk_src; +} + +/** + * @brief Enable the function clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_function_clock(int unit_id, bool enable) +{ + (void)unit_id; + (void)enable; +} + +/** + * @brief Set the clock divider for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param div Clock divider value, the output clock frequency is input clock frequency divided by this value. + * Must be greater than 0. + */ +static inline void analog_cmpr_ll_set_clk_div(int unit_id, uint32_t div) +{ + (void)unit_id; + (void)div; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_ana_cmpr/esp32h4/ana_cmpr_periph.c b/components/esp_hal_ana_cmpr/esp32h4/ana_cmpr_periph.c new file mode 100644 index 0000000000..92cd717822 --- /dev/null +++ b/components/esp_hal_ana_cmpr/esp32h4/ana_cmpr_periph.c @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "hal/ana_cmpr_periph.h" + +const ana_cmpr_periph_t ana_cmpr_periph[1] = { + [0] = { + .pad_gpios = { + ANA_CMPR0_PAD0_GPIO, + ANA_CMPR0_PAD1_GPIO, + ANA_CMPR0_PAD2_GPIO, + ANA_CMPR0_PAD3_GPIO, + }, + .intr_src = ETS_ZERO_DET_INTR_SOURCE, + .module_name = "ANA_CMPR_U0", + }, +}; diff --git a/components/esp_hal_ana_cmpr/esp32h4/include/hal/ana_cmpr_ll.h b/components/esp_hal_ana_cmpr/esp32h4/include/hal/ana_cmpr_ll.h new file mode 100644 index 0000000000..e5cdd70453 --- /dev/null +++ b/components/esp_hal_ana_cmpr/esp32h4/include/hal/ana_cmpr_ll.h @@ -0,0 +1,491 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "hal/ana_cmpr_types.h" +#include "soc/zero_det_struct.h" +#include "soc/pcr_struct.h" +#include "soc/soc_etm_source.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// the analog comparator on this target is also called zero detector +typedef zero_dev_t analog_cmpr_dev_t; + +#define ANALOG_CMPR_LL_GET(_attr) ANALOG_CMPR_LL_ ## _attr +#define ANALOG_CMPR_LL_SUPPORT(_feat) ANALOG_CMPR_LL_SUPPORT_ ## _feat + +// Number of Analog Comparator instances +#define ANALOG_CMPR_LL_INST_NUM 1 + +// ANA_CMPR IP version +#define ANALOG_CMPR_LL_IP_VERSION 2 + +// Number of pads for each Analog Comparator instance +#define ANALOG_CMPR_LL_PAD_NUM 4 + +// Number of source channels for the comparator +#define ANALOG_CMPR_LL_SRC_CHANNEL_NUM 3 + +// Can detect positive/negative/any cross type +#define ANALOG_CMPR_LL_SUPPORT_EDGE_TYPE 1 + +#define ANALOG_CMPR_LL_GET_HW(unit) (&ZERO_DET) + +#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) (1UL << ((2 - (src_chan)) * 3 + 0)) +#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) (1UL << ((2 - (src_chan)) * 3 + 1)) +#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan) (1UL << ((2 - (src_chan)) * 3 + 2)) + +#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit, src_chan) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan)) + +#define ANALOG_CMPR_LL_ETM_SOURCE(unit, src_chan, type) (ZERO_DET_EVT_CHANNEL_1_POS + (src_chan) + ((type) * ANALOG_CMPR_LL_SRC_CHANNEL_NUM)) + +/** + * @brief Enable the bus clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_bus_clock(int unit_id, bool enable) +{ + PCR.zero_det_conf.zero_det_clk_en = enable; +} + +/** + * @brief Reset the Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_register(int unit_id) +{ + PCR.zero_det_conf.zero_det_rst_en = 1; + PCR.zero_det_conf.zero_det_rst_en = 0; +} + +/** + * @brief Reset the core logic of Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_core(int unit_id) +{ + (void)unit_id; +} + +/** + * @brief Set the clock source for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param clk_src Clock source, see `ana_cmpr_clk_src_t` + */ +static inline void analog_cmpr_ll_set_clk_src(int unit_id, ana_cmpr_clk_src_t clk_src) +{ + // switch (clk_src) { + // case ANA_CMPR_CLK_SRC_XTAL: + // PCR.zero_det_clk_conf.zero_det_func_clk_sel = 0; + // break; + // case ANA_CMPR_CLK_SRC_RC_FAST: + // PCR.zero_det_clk_conf.zero_det_func_clk_sel = 1; + // break; + // case ANA_CMPR_CLK_SRC_PLL_F48M: + // PCR.zero_det_clk_conf.zero_det_func_clk_sel = 2; + // break; + // default: + // HAL_ASSERT(false); + // break; + // } +} + +/** + * @brief Enable the function clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_function_clock(int unit_id, bool enable) +{ + PCR.zero_det_clk_conf.zero_det_func_clk_en = enable; +} + +/** + * @brief Set the clock divider for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param div Clock divider value, the output clock frequency is input clock frequency divided by this value. + * Must be greater than 0. + */ +static inline void analog_cmpr_ll_set_clk_div(int unit_id, uint32_t div) +{ + (void)unit_id; + (void)div; +} + +/** + * @brief Get the interrupt mask from the given cross type + * + * @param unit_id Unit ID + * @param src_chan Source channel ID + * @param type Cross type + * @return Interrupt mask value + */ +__attribute__((always_inline)) +static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(uint32_t unit_id, uint32_t src_chan, ana_cmpr_cross_type_t type) +{ + uint32_t mask = 0; + switch (type) { + case ANA_CMPR_CROSS_POS: + mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_NEG: + mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_ANY: + mask |= ANALOG_CMPR_LL_ANY_CROSS_MASK(unit_id, src_chan); + break; + default: + break; + } + return mask; +} + +/** + * @brief Enable (power on) 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->det_pad_comp_cfg.det_pad_comp_xpd = en; +} + +/** + * @brief Set the voltage of the internal reference + * + * @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, ana_cmpr_ref_voltage_t volt_level) +{ + hw->det_pad_comp_cfg.det_pad_comp_dref = volt_level; +} + +/** + * @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->det_pad_comp_cfg.det_pad_comp_dref * 0.1F; +} + +/** + * @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 + */ +static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_source_t ref_src) +{ + hw->det_pad_comp_cfg.det_pad_comp_mode = ref_src; +} + +/** + * @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 + */ +__attribute__((always_inline)) +static inline void analog_cmpr_ll_set_cross_debounce_cycle(analog_cmpr_dev_t *hw, uint32_t cycle) +{ + hw->det_filter_cnt.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) +{ + uint32_t val = hw->det_int_ena.val; + if (enable) { + val |= mask; + } else { + val &= ~mask; + } + hw->det_int_ena.val = val; +} + +/** + * @brief Get comparator interrupt status + * + * @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->det_int_st.val; +} + +/** + * @brief Clear comparator interrupt status + * + * @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->det_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->det_int_st; +} + +/** + * @brief Set external reference PAD id + * + * @param hw Analog comparator register base address + * @param vref_pad_id PAD id (0..3) + */ +static inline void analog_cmpr_ll_set_ext_ref_pad(analog_cmpr_dev_t *hw, uint32_t vref_pad_id) +{ + hw->det_conf.det_vref_channel_sel = 1 << vref_pad_id; +} + +/** + * @brief Set comparator source PAD id for one source channel + * + * @param hw Analog comparator register base address + * @param src_chan Source channel id (0..2) + * @param src_pad_id PAD id (0..3) + */ +static inline void analog_cmpr_ll_set_src_pad(analog_cmpr_dev_t *hw, uint32_t src_chan, uint32_t src_pad_id) +{ + uint32_t val = 1 << src_pad_id; + switch (src_chan) { + case 0: + hw->det_conf.det_comp_channel_1_sel = val; + break; + case 1: + hw->det_conf.det_comp_channel_2_sel = val; + break; + default: + hw->det_conf.det_comp_channel_3_sel = val; + break; + } +} + +/** + * @brief Set scan channel mask + * + * @param hw Analog comparator register base address + * @param poll_mask Channel mask (bit0..bit2 => CH1..CH3) + */ +static inline void analog_cmpr_ll_set_scan_mask(analog_cmpr_dev_t *hw, uint32_t poll_mask) +{ + hw->det_conf.det_comp_poll_mask = poll_mask & 0x7; +} + +/** + * @brief Set scan mode + * + * @param hw Analog comparator register base address + * @param scan_mode Scan mode, see `ana_cmpr_scan_mode_t` + */ +static inline void analog_cmpr_ll_set_scan_mode(analog_cmpr_dev_t *hw, ana_cmpr_scan_mode_t scan_mode) +{ + hw->det_conf.det_comp_poll_mode = scan_mode; +} + +/** + * @brief Set channel switch wait cycles + * + * @param hw Analog comparator register base address + * @param period_cycles Wait cycles in PAD_COMP_CLK domain + */ +static inline void analog_cmpr_ll_set_poll_period(analog_cmpr_dev_t *hw, uint32_t period_cycles) +{ + hw->det_poll_period.det_comp_poll_period = period_cycles & 0xFFFF; +} + +/** + * @brief Set the resample limit for the cross detection + * + * @note If the current status is high, N consecutive low levels need to be sampled before switching to low, vice versa. + * + * @param hw Analog comparator register base address + * @param limit_cnt The resample limit count + */ +static inline void analog_cmpr_ll_set_resample_limit(analog_cmpr_dev_t *hw, uint32_t limit_cnt) +{ + hw->det_conf.det_limit_cnt = limit_cnt; +} + +/** + * @brief Set ETM delay event cycles + * + * @param hw Analog comparator register base address + * @param delay_cycles Delay cycles in PAD_COMP_CLK domain + */ +static inline void analog_cmpr_ll_set_etm_delay_cycles(analog_cmpr_dev_t *hw, uint32_t delay_cycles) +{ + hw->det_delay_event_time.det_delay_event_time = delay_cycles & 0xFFFF; +} + +/** + * @brief Enable per-channel delayed ETM event timer + * + * @param hw Analog comparator register base address + * @param src_chan Source channel id (0..2) + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_channel_etm_delay(analog_cmpr_dev_t *hw, uint32_t src_chan, bool enable) +{ + switch (src_chan) { + case 0: + hw->det_conf.det_channel_1_event_timer_en = enable; + break; + case 1: + hw->det_conf.det_channel_2_event_timer_en = enable; + break; + default: + hw->det_conf.det_channel_3_event_timer_en = enable; + break; + } +} + +/** + * @brief Enable channel capture timer for cross detection time stamping + * + * @param hw Analog comparator register base address + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_capture_timer(analog_cmpr_dev_t *hw, bool enable) +{ + hw->det_conf.det_channel_timer_en = enable; +} + +/** + * @brief Set hysteresis level + * + * @param hw Analog comparator register base address + * @param hys_level Hysteresis level enum + */ +static inline void analog_cmpr_ll_set_ref_hys_level(analog_cmpr_dev_t *hw, ana_cmpr_ref_hys_t hys_level) +{ + switch (hys_level) { + case ANA_CMPR_REF_HYS_LEVEL0: + hw->det_pad_comp_cfg.det_pad_comp_hys = 0; + break; + case ANA_CMPR_REF_HYS_LEVEL1: + hw->det_pad_comp_cfg.det_pad_comp_hys = 1; + break; + case ANA_CMPR_REF_HYS_LEVEL2: + hw->det_pad_comp_cfg.det_pad_comp_hys = 2; + break; + default: + hw->det_pad_comp_cfg.det_pad_comp_hys = 4; + break; + } + hw->det_pad_comp_cfg.det_pad_comp_hys_en = hys_level != ANA_CMPR_REF_HYS_LEVEL0; +} + +/** + * @brief Get the current compare result of one source channel + * + * @param hw Analog comparator register base address + * @param src_chan Source channel id (0..2) + * @return true if the source signal is higher than the reference signal, false otherwise + */ +static inline bool analog_cmpr_ll_get_compare_result(analog_cmpr_dev_t *hw, uint32_t src_chan) +{ + switch (src_chan) { + case 0: + return hw->det_channel_status.det_channel_1_pad_comp_status; + case 1: + return hw->det_channel_status.det_channel_2_pad_comp_status; + default: + return hw->det_channel_status.det_channel_3_pad_comp_status; + } +} + +/** + * @brief Get the current capture timer value for a source channel, which can be used for time stamping the cross event + * + * @param hw Analog comparator register base address + * @param src_chan Source channel id (0..2) + * @return Current capture timer value in cycles of PAD_COMP_CLK + */ +static inline uint32_t analog_cmpr_ll_get_current_capture_time(analog_cmpr_dev_t *hw, uint32_t src_chan) +{ + uint32_t reg_val = 0; + switch (src_chan) { + case 0: + reg_val = hw->det_channel_1_timer0.det_channel_1_timer0; + break; + case 1: + reg_val = hw->det_channel_2_timer0.det_channel_2_timer0; + break; + default: + reg_val = hw->det_channel_3_timer0.det_channel_3_timer0; + break; + } + return reg_val; +} + +/** + * @brief Get the previous capture timer value for a source channel, which is the timestamp of the last cross event that triggered an interrupt + * + * @param hw Analog comparator register base address + * @param src_chan Source channel id (0..2) + * @return Previous capture timer value in cycles of PAD_COMP_CLK + */ +static inline uint32_t analog_cmpr_ll_get_previous_capture_time(analog_cmpr_dev_t *hw, uint32_t src_chan) +{ + uint32_t reg_val = 0; + switch (src_chan) { + case 0: + reg_val = hw->det_channel_1_timer1.det_channel_1_timer1; + break; + case 1: + reg_val = hw->det_channel_2_timer1.det_channel_2_timer1; + break; + default: + reg_val = hw->det_channel_3_timer1.det_channel_3_timer1; + break; + } + return reg_val; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_ana_cmpr/esp32p4/include/hal/ana_cmpr_ll.h b/components/esp_hal_ana_cmpr/esp32p4/include/hal/ana_cmpr_ll.h index a3c210503c..c8d03974cc 100644 --- a/components/esp_hal_ana_cmpr/esp32p4/include/hal/ana_cmpr_ll.h +++ b/components/esp_hal_ana_cmpr/esp32p4/include/hal/ana_cmpr_ll.h @@ -23,19 +23,56 @@ extern "C" { // Number of Analog Comparator instances #define ANALOG_CMPR_LL_INST_NUM 2 +// ANA_CMPR IP version +#define ANALOG_CMPR_LL_IP_VERSION 1 + +// Number of pads for each Analog Comparator instance +#define ANALOG_CMPR_LL_PAD_NUM 2 + +// Number of source channels for the comparator +#define ANALOG_CMPR_LL_SRC_CHANNEL_NUM 1 + // Can detect positive/negative/any cross type #define ANALOG_CMPR_LL_SUPPORT_EDGE_TYPE 1 #define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit]) #define ANALOG_CMPR_LL_GET_UNIT(hw) ((hw) == (&ANALOG_CMPR[0]) ? 0 : 1) -#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 0)) -#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1)) -#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 2)) +#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 0)) +#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 1)) +#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan) (1UL << ((unit) * 3 + 2)) -#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit)) +#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit, src_chan) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan)) -#define ANALOG_CMPR_LL_ETM_SOURCE(unit, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type)) +#define ANALOG_CMPR_LL_ETM_SOURCE(unit, src_chan, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type)) + +/** + * @brief Get the interrupt mask from the given cross type + * + * @param unit_id Unit ID + * @param src_chan Source channel ID + * @param type Cross type + * @return Interrupt mask value + */ +__attribute__((always_inline)) +static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(uint32_t unit_id, uint32_t src_chan, ana_cmpr_cross_type_t type) +{ + uint32_t mask = 0; + switch (type) { + case ANA_CMPR_CROSS_POS: + mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_NEG: + mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_ANY: + mask |= ANALOG_CMPR_LL_ANY_CROSS_MASK(unit_id, src_chan); + break; + default: + break; + } + return mask; +} /** * @brief Enable analog comparator @@ -55,7 +92,7 @@ static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en) * @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) +static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw, ana_cmpr_ref_voltage_t volt_level) { hw->pad_comp_config->dref_comp = volt_level; } @@ -77,38 +114,13 @@ static inline float analog_cmpr_ll_get_internal_ref_voltage(analog_cmpr_dev_t *h * @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) + * @param ref_src reference source, 0 for internal, 1 for external GPIO pad */ -static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_voltage_t ref_src) +static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_source_t ref_src) { hw->pad_comp_config->mode_comp = ref_src; } -/** - * @brief Get the interrupt mask by 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 - * @return interrupt mask - */ -__attribute__((always_inline)) -static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *hw, ana_cmpr_cross_type_t type) -{ - uint32_t unit = ANALOG_CMPR_LL_GET_UNIT(hw); - uint32_t mask = 0; - if (type & 0x01) { - mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit); - } - if (type & 0x02) { - mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit); - } - return mask; -} - /** * @brief Set the debounce cycle for the cross detection * @@ -118,7 +130,7 @@ static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *h * @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) +static inline void analog_cmpr_ll_set_cross_debounce_cycle(analog_cmpr_dev_t *hw, uint32_t cycle) { hw->pad_comp_filter->zero_det_filter_cnt = cycle; } @@ -175,6 +187,75 @@ static inline volatile void *analog_cmpr_ll_get_intr_status_reg(analog_cmpr_dev_ return hw->int_st; } +/** + * @brief Enable the bus clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_bus_clock(int unit_id, bool enable) +{ + (void)unit_id; + (void)enable; +} + +/** + * @brief Reset the Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_register(int unit_id) +{ + (void)unit_id; +} + +/** + * @brief Reset the core logic of Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_core(int unit_id) +{ + (void)unit_id; +} + +/** + * @brief Set the clock source for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param clk_src Clock source, see `ana_cmpr_clk_src_t` + */ +static inline void analog_cmpr_ll_set_clk_src(int unit_id, ana_cmpr_clk_src_t clk_src) +{ + (void)unit_id; + (void)clk_src; +} + +/** + * @brief Enable the function clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_function_clock(int unit_id, bool enable) +{ + (void)unit_id; + (void)enable; +} + +/** + * @brief Set the clock divider for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param div Clock divider value, the output clock frequency is input clock frequency divided by this value. + * Must be greater than 0. + */ +static inline void analog_cmpr_ll_set_clk_div(int unit_id, uint32_t div) +{ + (void)unit_id; + (void)div; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_ana_cmpr/esp32s31/ana_cmpr_periph.c b/components/esp_hal_ana_cmpr/esp32s31/ana_cmpr_periph.c new file mode 100644 index 0000000000..92cd717822 --- /dev/null +++ b/components/esp_hal_ana_cmpr/esp32s31/ana_cmpr_periph.c @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "hal/ana_cmpr_periph.h" + +const ana_cmpr_periph_t ana_cmpr_periph[1] = { + [0] = { + .pad_gpios = { + ANA_CMPR0_PAD0_GPIO, + ANA_CMPR0_PAD1_GPIO, + ANA_CMPR0_PAD2_GPIO, + ANA_CMPR0_PAD3_GPIO, + }, + .intr_src = ETS_ZERO_DET_INTR_SOURCE, + .module_name = "ANA_CMPR_U0", + }, +}; diff --git a/components/esp_hal_ana_cmpr/esp32s31/include/hal/ana_cmpr_ll.h b/components/esp_hal_ana_cmpr/esp32s31/include/hal/ana_cmpr_ll.h new file mode 100644 index 0000000000..4cd1262d92 --- /dev/null +++ b/components/esp_hal_ana_cmpr/esp32s31/include/hal/ana_cmpr_ll.h @@ -0,0 +1,491 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "hal/ana_cmpr_types.h" +#include "soc/zero_det_struct.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "soc/soc_etm_source.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// the analog comparator on this target is also called zero detector +typedef zero_det_dev_t analog_cmpr_dev_t; + +#define ANALOG_CMPR_LL_GET(_attr) ANALOG_CMPR_LL_ ## _attr +#define ANALOG_CMPR_LL_SUPPORT(_feat) ANALOG_CMPR_LL_SUPPORT_ ## _feat + +// Number of Analog Comparator instances +#define ANALOG_CMPR_LL_INST_NUM 1 + +// ANA_CMPR IP version +#define ANALOG_CMPR_LL_IP_VERSION 2 + +// Number of pads for each Analog Comparator instance +#define ANALOG_CMPR_LL_PAD_NUM 4 + +// Number of source channels for the comparator +#define ANALOG_CMPR_LL_SRC_CHANNEL_NUM 3 + +// Can detect positive/negative/any cross type +#define ANALOG_CMPR_LL_SUPPORT_EDGE_TYPE 1 + +#define ANALOG_CMPR_LL_GET_HW(unit) (&ZERO_DET) + +#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) (1UL << ((2 - (src_chan)) * 3 + 0)) +#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) (1UL << ((2 - (src_chan)) * 3 + 1)) +#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan) (1UL << ((2 - (src_chan)) * 3 + 2)) + +#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit, src_chan) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit, src_chan) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit, src_chan)) + +#define ANALOG_CMPR_LL_ETM_SOURCE(unit, src_chan, type) (ZERO_DET_EVT_CHANNEL_1_POS + (src_chan) + ((type) * ANALOG_CMPR_LL_SRC_CHANNEL_NUM)) + +/** + * @brief Enable the bus clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_bus_clock(int unit_id, bool enable) +{ + HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_apb_clk_en = enable; +} + +/** + * @brief Reset the Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_register(int unit_id) +{ + HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_apb_rst_en = 1; + HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_apb_rst_en = 0; +} + +/** + * @brief Reset the core logic of Analog Comparator module + * + * @param unit_id Unit ID + */ +static inline void analog_cmpr_ll_reset_core(int unit_id) +{ + HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_core_rst_en = 1; + HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_core_rst_en = 0; +} + +/** + * @brief Set the clock source for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param clk_src Clock source, see `ana_cmpr_clk_src_t` + */ +static inline void analog_cmpr_ll_set_clk_src(int unit_id, ana_cmpr_clk_src_t clk_src) +{ + // switch (clk_src) { + // case ANA_CMPR_CLK_SRC_XTAL: + // HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_clk_src_sel = 0; + // break; + // case ANA_CMPR_CLK_SRC_RC_FAST: + // HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_clk_src_sel = 1; + // break; + // case ANA_CMPR_CLK_SRC_PLL_F80M: + // HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_clk_src_sel = 2; + // break; + // default: + // HAL_ASSERT(false); + // break; + // } +} + +/** + * @brief Set the clock divider for analog comparator PAD_COMP_CLK + * + * @param unit_id Unit ID + * @param div Clock divider value, the output clock frequency is input clock frequency divided by this value. + * Must be greater than 0. + */ +static inline void analog_cmpr_ll_set_clk_div(int unit_id, uint32_t div) +{ + HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_clk_div_num = div - 1; +} + +/** + * @brief Enable the function clock for Analog Comparator module + * + * @param unit_id Unit ID + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_function_clock(int unit_id, bool enable) +{ + HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_clk_en = enable; +} + +/** + * @brief Get the interrupt mask from the given cross type + * + * @param unit_id Unit ID + * @param src_chan Source channel ID + * @param type Cross type + * @return Interrupt mask value + */ +__attribute__((always_inline)) +static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(uint32_t unit_id, uint32_t src_chan, ana_cmpr_cross_type_t type) +{ + uint32_t mask = 0; + switch (type) { + case ANA_CMPR_CROSS_POS: + mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_NEG: + mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit_id, src_chan); + break; + case ANA_CMPR_CROSS_ANY: + mask |= ANALOG_CMPR_LL_ANY_CROSS_MASK(unit_id, src_chan); + break; + default: + break; + } + return mask; +} + +/** + * @brief Enable (power on) 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_cfg.pad_comp_xpd = en; +} + +/** + * @brief Set the voltage of the internal reference + * + * @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, ana_cmpr_ref_voltage_t volt_level) +{ + hw->pad_comp_cfg.pad_comp_dref = volt_level; +} + +/** + * @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_cfg.pad_comp_dref * 0.1F; +} + +/** + * @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 + */ +static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_source_t ref_src) +{ + hw->pad_comp_cfg.pad_comp_mode = ref_src; +} + +/** + * @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 + */ +__attribute__((always_inline)) +static inline void analog_cmpr_ll_set_cross_debounce_cycle(analog_cmpr_dev_t *hw, uint32_t cycle) +{ + hw->filter_cnt.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) +{ + uint32_t val = hw->int_ena.val; + if (enable) { + val |= mask; + } else { + val &= ~mask; + } + hw->int_ena.val = val; +} + +/** + * @brief Get comparator interrupt status + * + * @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; +} + +/** + * @brief Clear comparator interrupt status + * + * @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; +} + +/** + * @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; +} + +/** + * @brief Set external reference PAD id + * + * @param hw Analog comparator register base address + * @param vref_pad_id PAD id (0..3) + */ +static inline void analog_cmpr_ll_set_ext_ref_pad(analog_cmpr_dev_t *hw, uint32_t vref_pad_id) +{ + hw->conf.vref_channel_sel = 1 << vref_pad_id; +} + +/** + * @brief Set comparator source PAD id for one source channel + * + * @param hw Analog comparator register base address + * @param src_chan Source channel id (0..2) + * @param src_pad_id PAD id (0..3) + */ +static inline void analog_cmpr_ll_set_src_pad(analog_cmpr_dev_t *hw, uint32_t src_chan, uint32_t src_pad_id) +{ + uint32_t val = 1 << src_pad_id; + switch (src_chan) { + case 0: + hw->conf.comp_channel_1_sel = val; + break; + case 1: + hw->conf.comp_channel_2_sel = val; + break; + default: + hw->conf.comp_channel_3_sel = val; + break; + } +} + +/** + * @brief Set scan channel mask + * + * @param hw Analog comparator register base address + * @param poll_mask Channel mask (bit0..bit2 => CH1..CH3) + */ +static inline void analog_cmpr_ll_set_scan_mask(analog_cmpr_dev_t *hw, uint32_t poll_mask) +{ + hw->conf.comp_poll_mask = poll_mask & 0x7; +} + +/** + * @brief Set scan mode + * + * @param hw Analog comparator register base address + * @param scan_mode Scan mode, see `ana_cmpr_scan_mode_t` + */ +static inline void analog_cmpr_ll_set_scan_mode(analog_cmpr_dev_t *hw, ana_cmpr_scan_mode_t scan_mode) +{ + hw->conf.comp_poll_mode = scan_mode; +} + +/** + * @brief Set channel switch wait cycles + * + * @param hw Analog comparator register base address + * @param period_cycles Wait cycles in PAD_COMP_CLK domain + */ +static inline void analog_cmpr_ll_set_poll_period(analog_cmpr_dev_t *hw, uint32_t period_cycles) +{ + hw->poll_period.comp_poll_period = period_cycles & 0xFFFF; +} + +/** + * @brief Set the resample limit for the cross detection + * + * @note If the current status is high, N consecutive low levels need to be sampled before switching to low, vice versa. + * + * @param hw Analog comparator register base address + * @param limit_cnt The resample limit count + */ +static inline void analog_cmpr_ll_set_resample_limit(analog_cmpr_dev_t *hw, uint32_t limit_cnt) +{ + hw->conf.limit_cnt = limit_cnt; +} + +/** + * @brief Set ETM delay event cycles + * + * @param hw Analog comparator register base address + * @param delay_cycles Delay cycles in PAD_COMP_CLK domain + */ +static inline void analog_cmpr_ll_set_etm_delay_cycles(analog_cmpr_dev_t *hw, uint32_t delay_cycles) +{ + hw->delay_event_time.delay_event_time = delay_cycles & 0xFFFF; +} + +/** + * @brief Enable per-channel delayed ETM event timer + * + * @param hw Analog comparator register base address + * @param src_chan Source channel id (0..2) + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_channel_etm_delay(analog_cmpr_dev_t *hw, uint32_t src_chan, bool enable) +{ + switch (src_chan) { + case 0: + hw->conf.channel_1_event_timer_en = enable; + break; + case 1: + hw->conf.channel_2_event_timer_en = enable; + break; + default: + hw->conf.channel_3_event_timer_en = enable; + break; + } +} + +/** + * @brief Enable channel capture timer for cross detection time stamping + * + * @param hw Analog comparator register base address + * @param enable true to enable, false to disable + */ +static inline void analog_cmpr_ll_enable_capture_timer(analog_cmpr_dev_t *hw, bool enable) +{ + hw->conf.channel_timer_en = enable; +} + +/** + * @brief Set hysteresis level + * + * @param hw Analog comparator register base address + * @param hys_level Hysteresis level enum + */ +static inline void analog_cmpr_ll_set_ref_hys_level(analog_cmpr_dev_t *hw, ana_cmpr_ref_hys_t hys_level) +{ + switch (hys_level) { + case ANA_CMPR_REF_HYS_LEVEL0: + hw->pad_comp_cfg.pad_comp_hys = 0; + break; + case ANA_CMPR_REF_HYS_LEVEL1: + hw->pad_comp_cfg.pad_comp_hys = 1; + break; + case ANA_CMPR_REF_HYS_LEVEL2: + hw->pad_comp_cfg.pad_comp_hys = 2; + break; + default: + hw->pad_comp_cfg.pad_comp_hys = 4; + break; + } + hw->pad_comp_cfg.pad_comp_hys_en = hys_level != ANA_CMPR_REF_HYS_LEVEL0; +} + +/** + * @brief Get the current compare result of one source channel + * + * @param hw Analog comparator register base address + * @param src_chan Source channel id (0..2) + * @return true if the source signal is higher than the reference signal, false otherwise + */ +static inline bool analog_cmpr_ll_get_compare_result(analog_cmpr_dev_t *hw, uint32_t src_chan) +{ + switch (src_chan) { + case 0: + return hw->channel_status.channel_1_pad_comp_status; + case 1: + return hw->channel_status.channel_2_pad_comp_status; + default: + return hw->channel_status.channel_3_pad_comp_status; + } +} + +/** + * @brief Get the current capture timer value for a source channel, which can be used for time stamping the cross event + * + * @param hw Analog comparator register base address + * @param src_chan Source channel id (0..2) + * @return Current capture timer value in cycles of PAD_COMP_CLK + */ +static inline uint32_t analog_cmpr_ll_get_current_capture_time(analog_cmpr_dev_t *hw, uint32_t src_chan) +{ + uint32_t reg_val = 0; + switch (src_chan) { + case 0: + reg_val = hw->channel_1_timer0.channel_1_timer0; + break; + case 1: + reg_val = hw->channel_2_timer0.channel_2_timer0; + break; + default: + reg_val = hw->channel_3_timer0.channel_3_timer0; + break; + } + return reg_val; +} + +/** + * @brief Get the previous capture timer value for a source channel, which is the timestamp of the last cross event that triggered an interrupt + * + * @param hw Analog comparator register base address + * @param src_chan Source channel id (0..2) + * @return Previous capture timer value in cycles of PAD_COMP_CLK + */ +static inline uint32_t analog_cmpr_ll_get_previous_capture_time(analog_cmpr_dev_t *hw, uint32_t src_chan) +{ + uint32_t reg_val = 0; + switch (src_chan) { + case 0: + reg_val = hw->channel_1_timer1.channel_1_timer1; + break; + case 1: + reg_val = hw->channel_2_timer1.channel_2_timer1; + break; + default: + reg_val = hw->channel_3_timer1.channel_3_timer1; + break; + } + return reg_val; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_ana_cmpr/include/hal/ana_cmpr_periph.h b/components/esp_hal_ana_cmpr/include/hal/ana_cmpr_periph.h index d99d0518ff..f6bd5d3b42 100644 --- a/components/esp_hal_ana_cmpr/include/hal/ana_cmpr_periph.h +++ b/components/esp_hal_ana_cmpr/include/hal/ana_cmpr_periph.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,10 +20,15 @@ extern "C" { #if SOC_ANA_CMPR_SUPPORTED typedef struct { - int src_gpio; - int ext_ref_gpio; - int intr_src; - const char *module_name; + union { + struct { + const int ext_ref_gpio; // External reference GPIO number + const int src_gpio; // Source GPIO number + }; + const int pad_gpios[ANALOG_CMPR_LL_GET(PAD_NUM)]; // Array of GPIO numbers for the pads, indexed by pad number + }; + const int intr_src; // Interrupt source ID + const char *module_name; // Module name } ana_cmpr_periph_t; extern const ana_cmpr_periph_t ana_cmpr_periph[ANALOG_CMPR_LL_GET(INST_NUM)]; diff --git a/components/esp_hal_ana_cmpr/include/hal/ana_cmpr_types.h b/components/esp_hal_ana_cmpr/include/hal/ana_cmpr_types.h index e37764a3e1..3c0136b9dd 100644 --- a/components/esp_hal_ana_cmpr/include/hal/ana_cmpr_types.h +++ b/components/esp_hal_ana_cmpr/include/hal/ana_cmpr_types.h @@ -1,18 +1,20 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once +#include "soc/soc_caps.h" +#include "soc/clk_tree_defs.h" + #ifdef __cplusplus extern "C" { #endif /** * @brief Analog comparator interrupt type - * */ typedef enum { ANA_CMPR_CROSS_DISABLE, /*!< Disable the cross event interrupt */ @@ -23,7 +25,6 @@ typedef enum { /** * @brief Analog comparator internal reference voltage - * */ typedef enum { ANA_CMPR_REF_VOLT_0_PCT_VDD, /*!< Internal reference voltage equals to 0% VDD */ @@ -36,6 +37,58 @@ typedef enum { ANA_CMPR_REF_VOLT_70_PCT_VDD, /*!< Internal reference voltage equals to 70% VDD */ } ana_cmpr_ref_voltage_t; +/** + * @brief Analog comparator reference source + */ +typedef enum { + ANA_CMPR_REF_SRC_INTERNAL, /*!< Analog Comparator reference voltage comes from internal */ + ANA_CMPR_REF_SRC_EXTERNAL, /*!< Analog Comparator reference voltage comes from external pin */ +} ana_cmpr_ref_source_t; + +/** + * @brief Analog comparator internal reference hysteresis level + * + * @note The exact hysteresis voltage is hardware-dependent. The level-to-voltage + * mapping on ESP32-H4 is approximately: + * - LEVEL1: ~0.04V + * - LEVEL2: ~0.08V + * - LEVEL3: ~0.12V + */ +typedef enum { + ANA_CMPR_REF_HYS_LEVEL0, /*!< No hysteresis */ + ANA_CMPR_REF_HYS_LEVEL1, /*!< Hysteresis level 1 */ + ANA_CMPR_REF_HYS_LEVEL2, /*!< Hysteresis level 2 */ + ANA_CMPR_REF_HYS_LEVEL3, /*!< Hysteresis level 3 */ +} ana_cmpr_ref_hys_t; + +/** + * @brief Analog comparator scan mode + */ +typedef enum { + ANA_CMPR_SCAN_MODE_FULL, /*!< One trigger scans all enabled source channels */ + ANA_CMPR_SCAN_MODE_STEP, /*!< One trigger scans one enabled source channel in sequence */ +} ana_cmpr_scan_mode_t; + +/** + * @brief Analog Comparator ETM Events for each unit + */ +typedef enum { + ANA_CMPR_EVENT_POS_CROSS, /*!< Positive cross event when the source signal becomes higher than the reference signal */ + ANA_CMPR_EVENT_NEG_CROSS, /*!< Negative cross event when the source signal becomes lower than the reference signal */ +} ana_cmpr_event_type_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 + #ifdef __cplusplus } #endif