From ff7a11e5393dd2ea9ecb81714873db436432d2f8 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 31 Jul 2023 10:43:54 +0800 Subject: [PATCH] feat(ana_cmpr): supported etm in analog comparator example --- .../driver/analog_comparator/ana_cmpr.c | 84 +++++++-- .../driver/analog_comparator/ana_cmpr_etm.c | 55 +----- .../analog_comparator/ana_cmpr_private.h | 20 +++ .../include/driver/ana_cmpr.h | 6 + .../include/driver/ana_cmpr_etm.h | 29 ++- .../include/driver/ana_cmpr_types.h | 14 +- components/driver/gpio/gpio.c | 2 +- .../driver/test_apps/.build-test-rules.yml | 4 + .../test_apps/analog_comparator/README.md | 4 +- .../analog_comparator/main/test_ana_cmpr.c | 7 +- .../main/test_ana_cmpr_common.c | 2 +- .../main/test_ana_cmpr_iram.c | 3 +- .../include/esp_private/etm_interface.h | 2 +- .../esp_hw_support/port/esp32c6/io_mux.c | 1 + .../esp_hw_support/port/esp32h2/io_mux.c | 1 + .../esp_hw_support/port/esp32p4/io_mux.c | 34 ++++ .../test_apps/etm/main/CMakeLists.txt | 5 + .../test_apps/etm/main/test_ana_cmpr_etm.c | 167 ++++++++++++++++++ .../hal/esp32h2/include/hal/ana_cmpr_ll.h | 36 ++-- .../hal/esp32p4/include/hal/ana_cmpr_ll.h | 10 +- components/hal/esp32p4/include/hal/gpio_ll.h | 4 + components/soc/esp32h2/ana_cmpr_periph.c | 13 +- .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32h2/include/soc/ana_cmpr_struct.h | 36 ++++ .../soc/esp32h2/include/soc/gpio_ext_struct.h | 5 - components/soc/esp32h2/include/soc/soc_caps.h | 3 +- .../soc/esp32h2/ld/esp32h2.peripherals.ld | 1 - components/soc/esp32p4/ana_cmpr_periph.c | 2 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 6 +- .../soc/esp32p4/include/soc/clk_tree_defs.h | 2 +- components/soc/esp32p4/include/soc/soc_caps.h | 7 +- components/soc/include/soc/ana_cmpr_periph.h | 6 +- docs/doxygen/Doxyfile | 1 + .../en/api-reference/peripherals/ana_cmpr.rst | 13 +- docs/en/api-reference/peripherals/etm.rst | 5 +- docs/zh_CN/api-reference/peripherals/etm.rst | 5 +- examples/peripherals/.build-test-rules.yml | 4 + .../peripherals/analog_comparator/README.md | 12 +- .../analog_comparator/main/CMakeLists.txt | 10 +- .../analog_comparator/main/Kconfig.projbuild | 17 +- .../main/ana_cmpr_example_etm.c | 133 ++++++++++++++ .../main/ana_cmpr_example_intr.c | 122 +++++++++++++ .../main/ana_cmpr_example_main.c | 121 +------------ .../main/ana_cmpr_example_main.h | 45 +++++ 44 files changed, 796 insertions(+), 267 deletions(-) create mode 100644 components/driver/analog_comparator/ana_cmpr_private.h create mode 100644 components/esp_hw_support/test_apps/etm/main/test_ana_cmpr_etm.c create mode 100644 components/soc/esp32h2/include/soc/ana_cmpr_struct.h create mode 100644 examples/peripherals/analog_comparator/main/ana_cmpr_example_etm.c create mode 100644 examples/peripherals/analog_comparator/main/ana_cmpr_example_intr.c create mode 100644 examples/peripherals/analog_comparator/main/ana_cmpr_example_main.h diff --git a/components/driver/analog_comparator/ana_cmpr.c b/components/driver/analog_comparator/ana_cmpr.c index c560f179344f..f417c2a02a31 100644 --- a/components/driver/analog_comparator/ana_cmpr.c +++ b/components/driver/analog_comparator/ana_cmpr.c @@ -25,6 +25,7 @@ #include "soc/ana_cmpr_periph.h" #include "hal/ana_cmpr_ll.h" #include "driver/ana_cmpr.h" +#include "driver/gpio.h" #include "esp_private/io_mux.h" #include "esp_private/esp_clk.h" @@ -36,6 +37,7 @@ struct ana_cmpr_t { ana_cmpr_event_callbacks_t cbs; /*!< The callback group that set by user */ intr_handle_t intr_handle; /*!< Interrupt handle */ uint32_t intr_mask; /*!< Interrupt mask */ + int intr_priority; /*!< Interrupt priority */ 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 */ @@ -44,16 +46,16 @@ struct ana_cmpr_t { /* 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, \ +#define ANA_CMPR_UNIT_CHECK(unit) ESP_RETURN_ON_FALSE((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) -#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM) // Shared with GPIO +#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_IRAM) #else #define ANA_CMPR_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT -#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED) // Shared with GPIO +#define ANA_CMPR_INTR_FLAG (0) #endif /* Driver tag */ @@ -71,20 +73,20 @@ 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; + ana_cmpr_cross_event_data_t evt_data = {.cross_type = ANA_CMPR_CROSS_ANY}; /* 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 & cmpr_handle->intr_mask)) { -#if SOC_ANA_CMPR_SUPPORT_MULTI_INTR +#if SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE if (status & ANALOG_CMPR_LL_POS_CROSS_MASK(cmpr_handle->unit)) { evt_data.cross_type = ANA_CMPR_CROSS_POS; } else if (status & ANALOG_CMPR_LL_NEG_CROSS_MASK(cmpr_handle->unit)) { evt_data.cross_type = ANA_CMPR_CROSS_NEG; } -#endif // SOC_ANA_CMPR_SUPPORT_MULTI_INTR +#endif // SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE need_yield = cmpr_handle->cbs.on_cross(cmpr_handle, &evt_data, cmpr_handle->user_data); } if (need_yield) { @@ -92,6 +94,22 @@ static void IRAM_ATTR s_ana_cmpr_default_intr_handler(void *usr_data) } } +static esp_err_t s_ana_cmpr_init_gpio(ana_cmpr_handle_t cmpr, bool is_external_ref) +{ + uint64_t pin_mask = BIT64(ana_cmpr_periph[cmpr->unit].src_gpio); + if (is_external_ref) { + pin_mask |= BIT64(ana_cmpr_periph[cmpr->unit].ext_ref_gpio); + } + gpio_config_t ana_cmpr_gpio_cfg = { + .pin_bit_mask = pin_mask, + .mode = GPIO_MODE_DISABLE, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE, + }; + return gpio_config(&ana_cmpr_gpio_cfg); +} + esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t *ret_cmpr) { #if CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG @@ -101,6 +119,7 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * ANA_CMPR_NULL_POINTER_CHECK(ret_cmpr); ana_cmpr_unit_t unit = config->unit; ANA_CMPR_UNIT_CHECK(unit); + ESP_RETURN_ON_FALSE(config->intr_priority >= 0 && config->intr_priority <= 7, ESP_ERR_INVALID_ARG, TAG, "interrupt priority should be within 0~7"); ESP_RETURN_ON_FALSE(!s_ana_cmpr[unit], ESP_ERR_INVALID_STATE, TAG, "unit has been allocated already"); esp_err_t ret = ESP_OK; @@ -112,6 +131,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(unit); s_ana_cmpr[unit]->ref_src = config->ref_src; + s_ana_cmpr[unit]->intr_priority = config->intr_priority; s_ana_cmpr[unit]->is_enabled = false; s_ana_cmpr[unit]->pm_lock = NULL; @@ -123,6 +143,10 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * ESP_GOTO_ON_ERROR(ret, err, TAG, "create NO_LIGHT_SLEEP, lock failed"); #endif + if (!config->flags.io_loop_back) { + ESP_GOTO_ON_ERROR(s_ana_cmpr_init_gpio(s_ana_cmpr[unit], config->ref_src == ANA_CMPR_REF_SRC_EXTERNAL), err, TAG, "failed to initialize GPIO"); + } + /* Analog clock comes from IO MUX, but IO MUX clock might be shared with other submodules as well */ ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)config->clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, @@ -134,23 +158,19 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * /* Configure the register */ portENTER_CRITICAL(&s_spinlock); analog_cmpr_ll_set_ref_source(s_ana_cmpr[unit]->dev, config->ref_src); -#if !SOC_ANA_CMPR_SUPPORT_MULTI_INTR +#if !SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE analog_cmpr_ll_set_cross_type(s_ana_cmpr[unit]->dev, config->cross_type); -#endif // SOC_ANA_CMPR_SUPPORT_MULTI_INTR - portEXIT_CRITICAL(&s_spinlock); - - /* Allocate the interrupt, currently the interrupt source of Analog Comparator is shared with GPIO interrupt source */ +#endif // SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE + /* Record the interrupt mask, the interrupt will be lazy installed when register the callbacks */ s_ana_cmpr[unit]->intr_mask = analog_cmpr_ll_get_intr_mask_by_type(s_ana_cmpr[unit]->dev, config->cross_type); - ESP_GOTO_ON_ERROR(esp_intr_alloc_intrstatus(ana_cmpr_io_map[unit].intr_src, ANA_CMPR_INTR_FLAG, (uint32_t)analog_cmpr_ll_get_intr_status_reg(s_ana_cmpr[unit]->dev), - s_ana_cmpr[unit]->intr_mask, s_ana_cmpr_default_intr_handler, s_ana_cmpr[unit], &s_ana_cmpr[unit]->intr_handle), - err, TAG, "allocate interrupt failed"); + portEXIT_CRITICAL(&s_spinlock); 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); + (int)unit, ana_cmpr_periph[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); + (int)unit, ana_cmpr_periph[unit].src_gpio, ana_cmpr_periph[unit].ext_ref_gpio); } *ret_cmpr = s_ana_cmpr[unit]; @@ -230,12 +250,19 @@ esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_ esp_err_t ana_cmpr_set_cross_type(ana_cmpr_handle_t cmpr, ana_cmpr_cross_type_t cross_type) { +#if SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE + /* Not support to set the cross type after initialized, because it relies on the interrupt types to distinguish the edge, + * i.e. have to re-allocate the interrupt to change the cross type */ + (void)cmpr; + (void)cross_type; + return ESP_ERR_NOT_SUPPORTED; +#else 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); -#if !SOC_ANA_CMPR_SUPPORT_MULTI_INTR +#if !SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE analog_cmpr_ll_set_cross_type(cmpr->dev, cross_type); #endif cmpr->intr_mask = analog_cmpr_ll_get_intr_mask_by_type(cmpr->dev, cross_type); @@ -244,6 +271,7 @@ esp_err_t ana_cmpr_set_cross_type(ana_cmpr_handle_t cmpr, ana_cmpr_cross_type_t ESP_EARLY_LOGD(TAG, "unit %d cross type updated to %d", (int)cmpr->unit, cross_type); return ESP_OK; +#endif } esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cmpr_event_callbacks_t *cbs, void *user_data) @@ -263,6 +291,16 @@ esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cm } #endif + /* Allocate the interrupt, the interrupt source of Analog Comparator is shared with GPIO interrupt source on ESP32H2 */ + if (!cmpr->intr_handle) { + int intr_flags = ANA_CMPR_INTR_FLAG | (cmpr->intr_priority ? BIT(cmpr->intr_priority) : ESP_INTR_FLAG_LOWMED); +#if SOC_ANA_CMPR_INTR_SHARE_WITH_GPIO + intr_flags |= ESP_INTR_FLAG_SHARED; +#endif // SOC_ANA_CMPR_INTR_SHARE_WITH_GPIO + ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(ana_cmpr_periph[cmpr->unit].intr_src, intr_flags, (uint32_t)analog_cmpr_ll_get_intr_status_reg(cmpr->dev), + cmpr->intr_mask, s_ana_cmpr_default_intr_handler, cmpr, &cmpr->intr_handle), TAG, "allocate interrupt failed"); + } + /* Save the callback group */ memcpy(&(cmpr->cbs), cbs, sizeof(ana_cmpr_event_callbacks_t)); cmpr->user_data = user_data; @@ -327,10 +365,10 @@ esp_err_t ana_cmpr_get_gpio(ana_cmpr_unit_t unit, ana_cmpr_channel_type_t chan_t /* 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; + *gpio_num = ana_cmpr_periph[unit].src_gpio; break; case ANA_CMPR_EXT_REF_CHAN: - *gpio_num = ana_cmpr_io_map[unit].ext_ref_gpio; + *gpio_num = ana_cmpr_periph[unit].ext_ref_gpio; break; default: ESP_LOGE(TAG, "invalid channel type"); @@ -339,3 +377,11 @@ esp_err_t ana_cmpr_get_gpio(ana_cmpr_unit_t unit, ana_cmpr_channel_type_t chan_t return ESP_OK; } + +ana_cmpr_unit_t ana_cmpr_priv_get_unit_by_handle(ana_cmpr_handle_t cmpr) +{ + if (!cmpr) { + return -1; + } + return cmpr->unit; +} diff --git a/components/driver/analog_comparator/ana_cmpr_etm.c b/components/driver/analog_comparator/ana_cmpr_etm.c index 0c9494c680df..02dc491269de 100644 --- a/components/driver/analog_comparator/ana_cmpr_etm.c +++ b/components/driver/analog_comparator/ana_cmpr_etm.c @@ -21,81 +21,42 @@ #include "driver/ana_cmpr_types.h" #include "driver/ana_cmpr_etm.h" #include "esp_private/etm_interface.h" +#include "ana_cmpr_private.h" static const char *TAG = "ana-cmpr-etm"; #define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT -typedef struct ana_cmpr_etm_event_t ana_cmpr_etm_event_t; - typedef struct { - portMUX_TYPE spinlock; - ana_cmpr_etm_event_t *events[SOC_ANA_CMPR_ETM_EVENTS_PER_UNIT]; -} ana_cmpr_etm_unit_t; - -struct ana_cmpr_etm_event_t { esp_etm_event_t base; - ana_cmpr_unit_t unit; - ana_cmpr_event_type_t type; -}; - -static ana_cmpr_etm_unit_t s_ana_cmpr_etm_unit[SOC_ANA_CMPR_NUM] = { - [0 ... SOC_ANA_CMPR_NUM - 1] = { - .spinlock = portMUX_INITIALIZER_UNLOCKED, - .events[0 ... SOC_ANA_CMPR_ETM_EVENTS_PER_UNIT - 1] = NULL, - }, -}; - -static esp_err_t ana_cmpr_etm_event_register_to_unit(ana_cmpr_etm_event_t *evt) -{ - ESP_RETURN_ON_FALSE(!s_ana_cmpr_etm_unit[evt->unit].events[evt->type], - ESP_ERR_INVALID_STATE, TAG, "this event has been registered on the unit"); - portENTER_CRITICAL(&s_ana_cmpr_etm_unit[evt->unit].spinlock); - s_ana_cmpr_etm_unit[evt->unit].events[evt->type] = evt; - portEXIT_CRITICAL(&s_ana_cmpr_etm_unit[evt->unit].spinlock); - return ESP_OK; -} - -static esp_err_t ana_cmpr_etm_event_unregister_from_unit(ana_cmpr_etm_event_t *evt) -{ - ESP_RETURN_ON_FALSE(s_ana_cmpr_etm_unit[evt->unit].events[evt->type] == evt, - ESP_ERR_INVALID_ARG, TAG, "the event handle is not match to registered handle"); - portENTER_CRITICAL(&s_ana_cmpr_etm_unit[evt->unit].spinlock); - s_ana_cmpr_etm_unit[evt->unit].events[evt->type] = NULL; - portEXIT_CRITICAL(&s_ana_cmpr_etm_unit[evt->unit].spinlock); - return ESP_OK; -} +} ana_cmpr_etm_event_t; static esp_err_t ana_cmpr_del_etm_event(esp_etm_event_handle_t base_event) { ana_cmpr_etm_event_t *event = __containerof(base_event, ana_cmpr_etm_event_t, base); - ESP_RETURN_ON_ERROR(ana_cmpr_etm_event_unregister_from_unit(event), TAG, "unregister the event from the unit"); free(event); event = NULL; return ESP_OK; } -esp_err_t ana_cmpr_new_etm_event(const ana_cmpr_etm_event_config_t *config, esp_etm_event_handle_t *ret_event) +esp_err_t ana_cmpr_new_etm_event(ana_cmpr_handle_t cmpr, const ana_cmpr_etm_event_config_t *config, esp_etm_event_handle_t *ret_event) { #if CONFIG_ETM_ENABLE_DEBUG_LOG esp_log_level_set(TAG, ESP_LOG_DEBUG); #endif esp_err_t ret = ESP_OK; ana_cmpr_etm_event_t *event = NULL; - ESP_GOTO_ON_FALSE(config && ret_event, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); - + ana_cmpr_unit_t unit = ana_cmpr_priv_get_unit_by_handle(cmpr); + ESP_RETURN_ON_FALSE(((int)unit) >= 0, ESP_ERR_INVALID_ARG, TAG, "invalid analog comparator handle"); + ESP_RETURN_ON_FALSE(config && ret_event, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); event = heap_caps_calloc(1, sizeof(ana_cmpr_etm_event_t), ETM_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(event, ESP_ERR_NO_MEM, err, TAG, "no mem for analog comparator event"); - event->unit = config->unit; - event->type = config->event_type; - // register the event channel to the group - ESP_GOTO_ON_ERROR(ana_cmpr_etm_event_register_to_unit(event), err, TAG, "register event channel to group failed"); - uint32_t event_id = ANALOG_CMPR_LL_ETM_SOURCE(config->unit, config->event_type); + uint32_t event_id = ANALOG_CMPR_LL_ETM_SOURCE(unit, 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; - ESP_LOGD(TAG, "new event @%p, event_id=%"PRIu32", unit_id=%d", event, event_id, config->unit); + ESP_LOGD(TAG, "new event @%p, event_id=%"PRIu32", unit_id=%d", event, event_id, unit); *ret_event = &event->base; return ESP_OK; diff --git a/components/driver/analog_comparator/ana_cmpr_private.h b/components/driver/analog_comparator/ana_cmpr_private.h new file mode 100644 index 000000000000..4bbacb9c0cc2 --- /dev/null +++ b/components/driver/analog_comparator/ana_cmpr_private.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "driver/ana_cmpr_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +ana_cmpr_unit_t ana_cmpr_priv_get_unit_by_handle(ana_cmpr_handle_t cmpr); + +#ifdef __cplusplus +} +#endif diff --git a/components/driver/analog_comparator/include/driver/ana_cmpr.h b/components/driver/analog_comparator/include/driver/ana_cmpr.h index 4cd09852b13b..d10b1e0a74f5 100644 --- a/components/driver/analog_comparator/include/driver/ana_cmpr.h +++ b/components/driver/analog_comparator/include/driver/ana_cmpr.h @@ -28,6 +28,12 @@ typedef struct { * for external reference, the reference signal should be connect to `ANA_CMPRx_EXT_REF_GPIO` */ ana_cmpr_cross_type_t cross_type; /*!< The crossing types that can trigger interrupt */ + int intr_priority; /*!< The interrupt priority, range 0~7, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) + * otherwise the larger the higher, 7 is NMI */ + struct { + uint32_t io_loop_back:1; /*!< Enable this field when the other signals that output on the comparision pins are supposed to be fed back. + * Normally used for debug/test scenario */ + } flags; /*!< Analog comparator driver flags */ } ana_cmpr_config_t; /** diff --git a/components/driver/analog_comparator/include/driver/ana_cmpr_etm.h b/components/driver/analog_comparator/include/driver/ana_cmpr_etm.h index 08b205db860d..dce83452386d 100644 --- a/components/driver/analog_comparator/include/driver/ana_cmpr_etm.h +++ b/components/driver/analog_comparator/include/driver/ana_cmpr_etm.h @@ -17,17 +17,36 @@ extern "C" { #endif +/** + * @brief Analog Comparator ETM Events for each unit + * + */ typedef enum { - ANA_CMPR_EVENT_POS_CROSS, - ANA_CMPR_EVENT_NEG_CROSS, + 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 + * + */ typedef struct { - ana_cmpr_unit_t unit; - ana_cmpr_event_type_t event_type; /*!< Which kind of cross type can trigger the ETM event module */ + ana_cmpr_event_type_t event_type; /*!< Which kind of cross type can trigger the ETM event module */ } ana_cmpr_etm_event_config_t; -esp_err_t ana_cmpr_new_etm_event(const ana_cmpr_etm_event_config_t *config, esp_etm_event_handle_t *ret_event); +/** + * @brief Allocate a new Analog Comparator ETM event + * + * @param[in] cmpr Analog Comparator handle that allocated by `ana_cmpr_new_unit` + * @param[in] config Analog Comparator ETM event configuration + * @param[out] ret_event The returned generic handle of ETM event, which is used to connect to a task in the ETM driver + * @return + * - ESP_OK Success to create the new ETM event handle + * - ESP_ERR_NO_MEM No memory for the ETM event + * - ESP_ERR_INVALID_ARG NULL pointer of the input parameters + * - ESP_ERR_INVALID_STATE The event on the unit has been registered + */ +esp_err_t ana_cmpr_new_etm_event(ana_cmpr_handle_t cmpr, const ana_cmpr_etm_event_config_t *config, esp_etm_event_handle_t *ret_event); #ifdef __cplusplus } 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 52a92b5eb141..978509262097 100644 --- a/components/driver/analog_comparator/include/driver/ana_cmpr_types.h +++ b/components/driver/analog_comparator/include/driver/ana_cmpr_types.h @@ -18,12 +18,9 @@ extern "C" { * @brief Analog comparator unit * */ -typedef enum { - ANA_CMPR_UNIT_0, /*!< Analog Comparator unit 0 */ -#if SOC_ANA_CMPR_NUM == 2 - ANA_CMPR_UNIT_1, /*!< Analog Comparator unit 1 */ -#endif -} ana_cmpr_unit_t; +typedef int ana_cmpr_unit_t; + +#define ANA_CMPR_UNIT_0 0 /*!< @deprecated Analog comparator unit 0 */ /** * @brief Analog comparator reference source @@ -94,10 +91,9 @@ typedef int ana_cmpr_clk_src_t; * */ typedef struct { -#if SOC_ANA_CMPR_SUPPORT_MULTI_INTR ana_cmpr_cross_type_t cross_type; /*!< The cross type of the target signal to the reference signal. - * Will either be ANA_CMPR_CROSS_POS or ANA_CMPR_CROSS_NEG */ -#endif + * Will either be ANA_CMPR_CROSS_POS or ANA_CMPR_CROSS_NEG + * Always be ANA_CMPR_CROSS_ANY if target does not support independent interrupt (like ESP32H2) */ } ana_cmpr_cross_event_data_t; /** diff --git a/components/driver/gpio/gpio.c b/components/driver/gpio/gpio.c index 3cea507013c2..b6f4324607ed 100644 --- a/components/driver/gpio/gpio.c +++ b/components/driver/gpio/gpio.c @@ -594,7 +594,7 @@ esp_err_t gpio_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, p.source = ETS_GPIO_INTR0_SOURCE; #endif p.intr_alloc_flags = intr_alloc_flags; -#if SOC_ANA_CMPR_SUPPORTED +#if SOC_ANA_CMPR_INTR_SHARE_WITH_GPIO p.intr_alloc_flags |= ESP_INTR_FLAG_SHARED; #endif p.fn = fn; diff --git a/components/driver/test_apps/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml index d13e5809a912..5af096497f9d 100644 --- a/components/driver/test_apps/.build-test-rules.yml +++ b/components/driver/test_apps/.build-test-rules.yml @@ -3,6 +3,10 @@ components/driver/test_apps/analog_comparator: disable: - if: SOC_ANA_CMPR_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: not supported yet components/driver/test_apps/dac_test_apps/dac: disable: diff --git a/components/driver/test_apps/analog_comparator/README.md b/components/driver/test_apps/analog_comparator/README.md index 8161d00f6d8e..bde3cf8e7385 100644 --- a/components/driver/test_apps/analog_comparator/README.md +++ b/components/driver/test_apps/analog_comparator/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-H2 | -| ----------------- | -------- | +| Supported Targets | ESP32-H2 | ESP32-P4 | +| ----------------- | -------- | -------- | 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 53a69ea9c7f0..b24776e455ed 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 @@ -18,7 +18,7 @@ TEST_CASE("ana_cmpr_unit_install_uninstall", "[ana_cmpr]") /* 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; + config.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)); @@ -51,14 +51,15 @@ TEST_CASE("ana_cmpr_unit_install_uninstall", "[ana_cmpr]") TEST_CASE("ana_cmpr_internal_reference", "[ana_cmpr]") { int src_chan = test_init_src_chan_gpio(); - uint32_t cnt = 0; + uint32_t cnt = 0; ana_cmpr_handle_t cmpr = NULL; ana_cmpr_config_t config = { - .unit = ANA_CMPR_UNIT_0, + .unit = 0, .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, .ref_src = ANA_CMPR_REF_SRC_INTERNAL, .cross_type = ANA_CMPR_CROSS_ANY, + .flags.io_loop_back = 1, }; TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); ana_cmpr_internal_ref_config_t ref_cfg = { 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 index 9db12a0d07fe..0feb218ea666 100644 --- 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 @@ -19,7 +19,7 @@ bool IRAM_ATTR test_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, const ana 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_ESP_OK(ana_cmpr_get_gpio(0, ANA_CMPR_SOURCE_CHAN, &src_chan_num)); TEST_ASSERT(src_chan_num > 0); gpio_config_t io_conf = { .intr_type = GPIO_INTR_DISABLE, 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 ce0d5425f995..44da8afacd6e 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 @@ -44,10 +44,11 @@ TEST_CASE("ana_cmpr_internal_reference_iram_safe", "[ana_cmpr]") ana_cmpr_handle_t cmpr = NULL; ana_cmpr_config_t config = { - .unit = ANA_CMPR_UNIT_0, + .unit = 0, .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, .ref_src = ANA_CMPR_REF_SRC_INTERNAL, .cross_type = ANA_CMPR_CROSS_ANY, + .flags.io_loop_back = 1, }; TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); test_data.handle = cmpr; diff --git a/components/esp_hw_support/include/esp_private/etm_interface.h b/components/esp_hw_support/include/esp_private/etm_interface.h index 47958aa7e604..a7c7e4253886 100644 --- a/components/esp_hw_support/include/esp_private/etm_interface.h +++ b/components/esp_hw_support/include/esp_private/etm_interface.h @@ -25,7 +25,7 @@ typedef enum { ETM_TRIG_PERIPH_GPTIMER, /*!< ETM trigger source: GPTimer */ ETM_TRIG_PERIPH_SYSTIMER, /*!< ETM trigger source: Systimer */ ETM_TRIG_PERIPH_MCPWM, /*!< ETM trigger source: MCPWM */ - ETM_TRIG_PERIPH_ANA_CMPR, /*!< ETM trigger source: Analog Comparator */ + ETM_TRIG_PERIPH_ANA_CMPR, /*!< ETM trigger source: Analog Comparator */ } etm_trigger_peripheral_t; /** diff --git a/components/esp_hw_support/port/esp32c6/io_mux.c b/components/esp_hw_support/port/esp32c6/io_mux.c index ea7446b2baaf..e5679e40b4bd 100644 --- a/components/esp_hw_support/port/esp32c6/io_mux.c +++ b/components/esp_hw_support/port/esp32c6/io_mux.c @@ -28,5 +28,6 @@ esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) } gpio_ll_iomux_set_clk_src(clk_src); + return ESP_OK; } diff --git a/components/esp_hw_support/port/esp32h2/io_mux.c b/components/esp_hw_support/port/esp32h2/io_mux.c index a621deb8a31c..653c0b298129 100644 --- a/components/esp_hw_support/port/esp32h2/io_mux.c +++ b/components/esp_hw_support/port/esp32h2/io_mux.c @@ -28,5 +28,6 @@ esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) } gpio_ll_iomux_set_clk_src(clk_src); + return ESP_OK; } diff --git a/components/esp_hw_support/port/esp32p4/io_mux.c b/components/esp_hw_support/port/esp32p4/io_mux.c index e69de29bb2d1..10e021aba0f8 100644 --- a/components/esp_hw_support/port/esp32p4/io_mux.c +++ b/components/esp_hw_support/port/esp32p4/io_mux.c @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "freertos/FreeRTOS.h" +#include "esp_private/io_mux.h" +#include "esp_private/periph_ctrl.h" +#include "hal/gpio_ll.h" + +static portMUX_TYPE s_io_mux_spinlock = portMUX_INITIALIZER_UNLOCKED; +static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) + +esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) +{ + bool clk_conflict = false; + // check is the IO MUX has been set to another clock source + portENTER_CRITICAL(&s_io_mux_spinlock); + if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) { + clk_conflict = true; + } else { + s_io_mux_clk_src = clk_src; + } + portEXIT_CRITICAL(&s_io_mux_spinlock); + + if (clk_conflict) { + return ESP_ERR_INVALID_STATE; + } + PERIPH_RCC_ATOMIC() { + gpio_ll_iomux_set_clk_src(clk_src); + } + return ESP_OK; +} diff --git a/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt b/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt index 14c910836c8e..e7a895debdcb 100644 --- a/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt @@ -21,6 +21,11 @@ if(CONFIG_SOC_MCPWM_SUPPORT_ETM) list(APPEND srcs "test_mcpwm_etm.c") endif() +if(CONFIG_SOC_ANA_CMPR_SUPPORT_ETM AND CONFIG_SOC_TIMER_SUPPORT_ETM) + # Analog Comparator event test relies on GPTIMER task + list(APPEND srcs "test_ana_cmpr_etm.c") +endif() + # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} diff --git a/components/esp_hw_support/test_apps/etm/main/test_ana_cmpr_etm.c b/components/esp_hw_support/test_apps/etm/main/test_ana_cmpr_etm.c new file mode 100644 index 000000000000..348662862807 --- /dev/null +++ b/components/esp_hw_support/test_apps/etm/main/test_ana_cmpr_etm.c @@ -0,0 +1,167 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "unity.h" +#include "unity_test_utils.h" +#include "esp_attr.h" +#include "esp_etm.h" +#include "driver/gpio.h" +#include "driver/gptimer.h" +#include "driver/ana_cmpr.h" +#include "driver/gptimer_etm.h" +#include "driver/ana_cmpr_etm.h" + +#define TEST_ANA_CMPR_UNIT 0 +#define TEST_TIME_US 5000 + +static gptimer_handle_t s_test_ana_cmpr_gptimer_init(void) +{ + gptimer_handle_t gptimer = NULL; + gptimer_config_t timer_config = { + .clk_src = GPTIMER_CLK_SRC_DEFAULT, + .direction = GPTIMER_COUNT_UP, + .resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 1us + }; + TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer)); + TEST_ESP_OK(gptimer_set_raw_count(gptimer, 0)); + TEST_ESP_OK(gptimer_enable(gptimer)); + return gptimer; +} + +static void s_test_ana_cmpr_gptimer_deinit(gptimer_handle_t gptimer) +{ + TEST_ESP_OK(gptimer_disable(gptimer)); + TEST_ESP_OK(gptimer_del_timer(gptimer)); +} + +static ana_cmpr_handle_t s_test_ana_cmpr_init(void) +{ + ana_cmpr_handle_t cmpr = NULL; + + ana_cmpr_config_t config = { + .unit = TEST_ANA_CMPR_UNIT, + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_INTERNAL, + .cross_type = ANA_CMPR_CROSS_ANY, + }; + TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); + + ana_cmpr_internal_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, + }; + 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)); + TEST_ESP_OK(ana_cmpr_enable(cmpr)); + + return cmpr; +} + +static void s_test_ana_cmpr_deinit(ana_cmpr_handle_t cmpr) +{ + TEST_ESP_OK(ana_cmpr_disable(cmpr)); + TEST_ESP_OK(ana_cmpr_del_unit(cmpr)); +} + +static int s_test_ana_cmpr_src_gpio_init(void) +{ + int gpio_num = -1; + TEST_ESP_OK(ana_cmpr_get_gpio(TEST_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &gpio_num)); + gpio_config_t io_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = (1ULL << gpio_num), + .pull_down_en = false, + .pull_up_en = false, + }; + gpio_config(&io_conf); + gpio_set_level(gpio_num, 1); + return gpio_num; +} + +typedef struct { + esp_etm_event_handle_t cmpr_pos_evt; + esp_etm_event_handle_t cmpr_neg_evt; + esp_etm_task_handle_t gptimer_start_task; + esp_etm_task_handle_t gptimer_stop_task; + esp_etm_channel_handle_t etm_pos_handle; + esp_etm_channel_handle_t etm_neg_handle; +} test_ana_cmpr_etm_handles_t; + +static test_ana_cmpr_etm_handles_t s_test_ana_cmpr_init_etm(ana_cmpr_handle_t cmpr, gptimer_handle_t gptimer) +{ + test_ana_cmpr_etm_handles_t etm_handles = {}; + + /* Allocate the analog comparator positive & negative cross events */ + ana_cmpr_etm_event_config_t evt_cfg = { + .event_type = ANA_CMPR_EVENT_POS_CROSS, + }; + TEST_ESP_OK(ana_cmpr_new_etm_event(cmpr, &evt_cfg, &etm_handles.cmpr_pos_evt)); + evt_cfg.event_type = GPIO_ETM_EVENT_EDGE_NEG; + TEST_ESP_OK(ana_cmpr_new_etm_event(cmpr, &evt_cfg, &etm_handles.cmpr_neg_evt)); + + /* Allocate the GPTimer tasks */ + gptimer_etm_task_config_t gptimer_etm_task_conf = { + .task_type = GPTIMER_ETM_TASK_START_COUNT, + }; + TEST_ESP_OK(gptimer_new_etm_task(gptimer, &gptimer_etm_task_conf, &etm_handles.gptimer_start_task)); + gptimer_etm_task_conf.task_type = GPTIMER_ETM_TASK_STOP_COUNT; + TEST_ESP_OK(gptimer_new_etm_task(gptimer, &gptimer_etm_task_conf, &etm_handles.gptimer_stop_task)); + + /* Allocate the Event Task Matrix channels */ + esp_etm_channel_config_t etm_cfg = {}; + TEST_ESP_OK(esp_etm_new_channel(&etm_cfg, &etm_handles.etm_pos_handle)); + TEST_ESP_OK(esp_etm_new_channel(&etm_cfg, &etm_handles.etm_neg_handle)); + /* Bind the events and tasks */ + TEST_ESP_OK(esp_etm_channel_connect(etm_handles.etm_pos_handle, etm_handles.cmpr_pos_evt, etm_handles.gptimer_start_task)); + TEST_ESP_OK(esp_etm_channel_connect(etm_handles.etm_neg_handle, etm_handles.cmpr_neg_evt, etm_handles.gptimer_stop_task)); + /* Enable the ETM channels */ + TEST_ESP_OK(esp_etm_channel_enable(etm_handles.etm_pos_handle)); + TEST_ESP_OK(esp_etm_channel_enable(etm_handles.etm_neg_handle)); + + return etm_handles; +} + +static void s_test_ana_cmpr_deinit_etm(test_ana_cmpr_etm_handles_t handles) +{ + TEST_ESP_OK(esp_etm_channel_disable(handles.etm_pos_handle)); + TEST_ESP_OK(esp_etm_channel_disable(handles.etm_pos_handle)); + + TEST_ESP_OK(esp_etm_del_task(handles.gptimer_start_task)); + TEST_ESP_OK(esp_etm_del_task(handles.gptimer_stop_task)); + + TEST_ESP_OK(esp_etm_del_event(handles.cmpr_pos_evt)); + TEST_ESP_OK(esp_etm_del_event(handles.cmpr_neg_evt)); + + TEST_ESP_OK(esp_etm_del_channel(handles.etm_pos_handle)); + TEST_ESP_OK(esp_etm_del_channel(handles.etm_neg_handle)); +} + +TEST_CASE("analog_comparator_etm_event", "[etm]") +{ + gptimer_handle_t gptimer = s_test_ana_cmpr_gptimer_init(); + ana_cmpr_handle_t cmpr = s_test_ana_cmpr_init(); + int src_gpio = s_test_ana_cmpr_src_gpio_init(); + test_ana_cmpr_etm_handles_t handles = s_test_ana_cmpr_init_etm(cmpr, gptimer); + + gpio_set_level(src_gpio, 0); + esp_rom_delay_us(TEST_TIME_US); + gpio_set_level(src_gpio, 1); + + uint64_t cnt_us = 0; + TEST_ESP_OK(gptimer_get_raw_count(gptimer, &cnt_us)); + + s_test_ana_cmpr_deinit_etm(handles); + s_test_ana_cmpr_deinit(cmpr); + s_test_ana_cmpr_gptimer_deinit(gptimer); + + TEST_ASSERT_UINT64_WITHIN(TEST_TIME_US * 0.1, 5000, cnt_us); +} diff --git a/components/hal/esp32h2/include/hal/ana_cmpr_ll.h b/components/hal/esp32h2/include/hal/ana_cmpr_ll.h index 834391be3068..d45b43a5fa8b 100644 --- a/components/hal/esp32h2/include/hal/ana_cmpr_ll.h +++ b/components/hal/esp32h2/include/hal/ana_cmpr_ll.h @@ -9,9 +9,9 @@ #include #include "hal/misc.h" #include "hal/assert.h" -#include "soc/gpio_ext_struct.h" +#include "soc/ana_cmpr_struct.h" -#define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR) +#define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit]) #define ANALOG_CMPR_LL_EVENT_CROSS (1 << 0) #ifdef __cplusplus @@ -26,7 +26,7 @@ extern "C" { */ static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en) { - hw->pad_comp_config.xpd_comp = en; + hw->pad_comp_config->xpd_comp = en; } /** @@ -38,7 +38,7 @@ static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en) __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; + hw->pad_comp_config->dref_comp = volt_level; } /** @@ -49,7 +49,7 @@ static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw */ static inline float analog_cmpr_ll_get_internal_ref_voltage(analog_cmpr_dev_t *hw) { - return hw->pad_comp_config.dref_comp * 0.1F; + return hw->pad_comp_config->dref_comp * 0.1F; } /** @@ -62,7 +62,7 @@ static inline float analog_cmpr_ll_get_internal_ref_voltage(analog_cmpr_dev_t *h */ 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; + hw->pad_comp_config->mode_comp = ref_src; } /** @@ -78,7 +78,7 @@ static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, uint32_t __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; + hw->pad_comp_config->zero_det_mode = type; } /** @@ -86,16 +86,14 @@ static inline void analog_cmpr_ll_set_cross_type(analog_cmpr_dev_t *hw, uint8_t * @note Only one interrupt on H2 * * @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 + * @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, uint8_t type) { + (void)type; return ANALOG_CMPR_LL_EVENT_CROSS; } @@ -110,7 +108,7 @@ static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *h __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; + hw->pad_comp_filter->zero_det_filter_cnt = cycle; } /** @@ -122,11 +120,13 @@ static inline void analog_cmpr_ll_set_debounce_cycle(analog_cmpr_dev_t *hw, uint */ 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) { - hw->int_ena.val |= mask; + val |= mask; } else { - hw->int_ena.val &= ~mask; + val &= ~mask; } + hw->int_ena->val = val; } /** @@ -137,7 +137,7 @@ static inline void analog_cmpr_ll_enable_intr(analog_cmpr_dev_t *hw, uint32_t ma __attribute__((always_inline)) static inline uint32_t analog_cmpr_ll_get_intr_status(analog_cmpr_dev_t *hw) { - return hw->int_st.val; + return hw->int_st->val; } /** @@ -149,7 +149,7 @@ static inline uint32_t analog_cmpr_ll_get_intr_status(analog_cmpr_dev_t *hw) __attribute__((always_inline)) static inline void analog_cmpr_ll_clear_intr(analog_cmpr_dev_t *hw, uint32_t mask) { - hw->int_clr.val = mask; + hw->int_clr->val = mask; } /** @@ -160,7 +160,7 @@ static inline void analog_cmpr_ll_clear_intr(analog_cmpr_dev_t *hw, uint32_t mas */ static inline volatile void *analog_cmpr_ll_get_intr_status_reg(analog_cmpr_dev_t *hw) { - return &hw->int_st; + return hw->int_st; } #ifdef __cplusplus diff --git a/components/hal/esp32p4/include/hal/ana_cmpr_ll.h b/components/hal/esp32p4/include/hal/ana_cmpr_ll.h index 1ce151c07972..d1075ed64ac7 100644 --- a/components/hal/esp32p4/include/hal/ana_cmpr_ll.h +++ b/components/hal/esp32p4/include/hal/ana_cmpr_ll.h @@ -19,12 +19,14 @@ extern "C" { #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_EVENT_CROSS (1 << 0) +#define ANALOG_CMPR_LL_ETM_EVENTS_PER_UNIT (2) #define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3)) #define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1)) #define ANALOG_CMPR_LL_ETM_SOURCE(unit, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type)) + /** * @brief Enable analog comparator * @@ -92,7 +94,7 @@ static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *h mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit); } if (type & 0x02) { - mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit); + mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit); } return mask; } @@ -120,11 +122,13 @@ static inline void analog_cmpr_ll_set_debounce_cycle(analog_cmpr_dev_t *hw, uint */ 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) { - hw->int_ena->val |= mask; + val |= mask; } else { - hw->int_ena->val &= ~mask; + val &= ~mask; } + hw->int_ena->val = val; } /** diff --git a/components/hal/esp32p4/include/hal/gpio_ll.h b/components/hal/esp32p4/include/hal/gpio_ll.h index 274d5e68102d..61e241428060 100644 --- a/components/hal/esp32p4/include/hal/gpio_ll.h +++ b/components/hal/esp32p4/include/hal/gpio_ll.h @@ -603,6 +603,10 @@ static inline void gpio_ll_iomux_set_clk_src(soc_module_clk_t src) } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define gpio_ll_iomux_set_clk_src(...) (void)__DECLARE_RCC_ATOMIC_ENV; gpio_ll_iomux_set_clk_src(__VA_ARGS__) + /** * @brief Force hold digital io pad. * @note GPIO force hold, whether the chip in sleep mode or wakeup mode. diff --git a/components/soc/esp32h2/ana_cmpr_periph.c b/components/soc/esp32h2/ana_cmpr_periph.c index 8a5bec3c6cf9..e83acba42c9c 100644 --- a/components/soc/esp32h2/ana_cmpr_periph.c +++ b/components/soc/esp32h2/ana_cmpr_periph.c @@ -5,11 +5,22 @@ */ #include "soc/ana_cmpr_periph.h" +#include "soc/ana_cmpr_struct.h" -const ana_cmpr_conn_t ana_cmpr_io_map[SOC_ANA_CMPR_NUM] = { +const ana_cmpr_periph_t ana_cmpr_periph[SOC_ANA_CMPR_NUM] = { [0] = { .src_gpio = ANA_CMPR0_SRC_GPIO, .ext_ref_gpio = ANA_CMPR0_EXT_REF_GPIO, .intr_src = ETS_GPIO_INTR_SOURCE, }, }; + +analog_cmpr_dev_t ANALOG_CMPR[SOC_ANA_CMPR_NUM] = { + [0] = { + .pad_comp_config = &GPIO_EXT.pad_comp_config, + .pad_comp_filter = &GPIO_EXT.pad_comp_filter, + .int_st = &GPIO_EXT.int_st, + .int_ena = &GPIO_EXT.int_ena, + .int_clr = &GPIO_EXT.int_clr, + }, +}; diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 11b7544a2c73..16b41ee5dd1f 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -483,6 +483,10 @@ config SOC_ANA_CMPR_NUM int default 1 +config SOC_ANA_CMPR_INTR_SHARE_WITH_GPIO + bool + default y + config SOC_I2C_NUM int default 2 diff --git a/components/soc/esp32h2/include/soc/ana_cmpr_struct.h b/components/soc/esp32h2/include/soc/ana_cmpr_struct.h new file mode 100644 index 000000000000..b8444fb0be10 --- /dev/null +++ b/components/soc/esp32h2/include/soc/ana_cmpr_struct.h @@ -0,0 +1,36 @@ +/** + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* NOTE: this file is created manually for compatibility */ + +#pragma once + +#include +#include "soc/gpio_ext_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The Analog Comparator Device struct + * @note The field in it are register pointers, which point to the physical address + * of the corresponding configuration register + * @note see 'ana_cmpr_periph.c' for the device instance + */ +typedef struct { + volatile gpio_pad_comp_config_reg_t *pad_comp_config; + volatile gpio_pad_comp_filter_reg_t *pad_comp_filter; + volatile gpio_ext_int_st_reg_t *int_st; + volatile gpio_ext_int_ena_reg_t *int_ena; + volatile gpio_ext_int_clr_reg_t *int_clr; +} analog_cmpr_dev_t; + +extern analog_cmpr_dev_t ANALOG_CMPR[1]; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32h2/include/soc/gpio_ext_struct.h b/components/soc/esp32h2/include/soc/gpio_ext_struct.h index 9b211852e1ff..813ee4bbfcde 100644 --- a/components/soc/esp32h2/include/soc/gpio_ext_struct.h +++ b/components/soc/esp32h2/include/soc/gpio_ext_struct.h @@ -305,15 +305,10 @@ 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 4467ab10bf88..5ac067ee67cf 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -220,7 +220,8 @@ #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) +#define SOC_ANA_CMPR_NUM (1U) +#define SOC_ANA_CMPR_INTR_SHARE_WITH_GPIO (1) /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32-H2 has 2 I2C diff --git a/components/soc/esp32h2/ld/esp32h2.peripherals.ld b/components/soc/esp32h2/ld/esp32h2.peripherals.ld index 9b88f4b68f4a..faac00ad3c6c 100644 --- a/components/soc/esp32h2/ld/esp32h2.peripherals.ld +++ b/components/soc/esp32h2/ld/esp32h2.peripherals.ld @@ -44,7 +44,6 @@ 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 ); diff --git a/components/soc/esp32p4/ana_cmpr_periph.c b/components/soc/esp32p4/ana_cmpr_periph.c index f189bbd28778..df1db2ef6366 100644 --- a/components/soc/esp32p4/ana_cmpr_periph.c +++ b/components/soc/esp32p4/ana_cmpr_periph.c @@ -7,7 +7,7 @@ #include "soc/ana_cmpr_periph.h" #include "soc/ana_cmpr_struct.h" -const ana_cmpr_conn_t ana_cmpr_io_map[SOC_ANA_CMPR_NUM] = { +const ana_cmpr_periph_t ana_cmpr_periph[SOC_ANA_CMPR_NUM] = { [0] = { .src_gpio = ANA_CMPR0_SRC_GPIO, .ext_ref_gpio = ANA_CMPR0_EXT_REF_GPIO, diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index f93ed20ca741..930416a4e834 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -391,7 +391,7 @@ config SOC_ANA_CMPR_NUM int default 2 -config SOC_ANA_CMPR_SUPPORT_MULTI_INTR +config SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE bool default y @@ -399,10 +399,6 @@ config SOC_ANA_CMPR_SUPPORT_ETM bool default y -config SOC_ANA_CMPR_ETM_EVENTS_PER_UNIT - int - default 2 - config SOC_I2C_NUM int default 2 diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index a58f4214dd3b..0a50c5483c24 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -413,7 +413,7 @@ typedef enum { #define SOC_ANA_CMPR_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_XTAL} /** - * @brief Sigma Delta Modulator clock source + * @brief Analog Comparator clock source */ typedef enum { ANA_CMPR_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL clock as the source clock */ diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 987b968e658a..c72c2ba214b4 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -221,10 +221,9 @@ #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 (2U) -#define SOC_ANA_CMPR_SUPPORT_MULTI_INTR (1) -#define SOC_ANA_CMPR_SUPPORT_ETM (1) -#define SOC_ANA_CMPR_ETM_EVENTS_PER_UNIT (2) +#define SOC_ANA_CMPR_NUM (2) +#define SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE (1) // Support positive/negative/any cross interrupt +#define SOC_ANA_CMPR_SUPPORT_ETM (1) /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32-P4 has 2 I2Cs diff --git a/components/soc/include/soc/ana_cmpr_periph.h b/components/soc/include/soc/ana_cmpr_periph.h index c197bdb10a46..ce4738fcd672 100644 --- a/components/soc/include/soc/ana_cmpr_periph.h +++ b/components/soc/include/soc/ana_cmpr_periph.h @@ -8,7 +8,7 @@ #include #include "soc/soc_caps.h" -#include "soc/periph_defs.h" +#include "soc/interrupts.h" #if SOC_ANA_CMPR_SUPPORTED #include "soc/ana_cmpr_channel.h" #endif @@ -22,9 +22,9 @@ typedef struct { int src_gpio; int ext_ref_gpio; int intr_src; -} ana_cmpr_conn_t; +} ana_cmpr_periph_t; -extern const ana_cmpr_conn_t ana_cmpr_io_map[SOC_ANA_CMPR_NUM]; +extern const ana_cmpr_periph_t ana_cmpr_periph[SOC_ANA_CMPR_NUM]; #endif #ifdef __cplusplus diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 777ffd4d7b96..60441c822fdf 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -73,6 +73,7 @@ INPUT = \ $(PROJECT_PATH)/components/bt/host/nimble/esp-hci/include/esp_nimble_hci.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_etm.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 \ diff --git a/docs/en/api-reference/peripherals/ana_cmpr.rst b/docs/en/api-reference/peripherals/ana_cmpr.rst index b686e6b69323..e9d3809649c6 100644 --- a/docs/en/api-reference/peripherals/ana_cmpr.rst +++ b/docs/en/api-reference/peripherals/ana_cmpr.rst @@ -1,7 +1,6 @@ Analog Comparator ================= -{IDF_TARGET_ANA_CMPR_NUM: default="NOT UPDATED", esp32h2="one", esp32p4="two"} {IDF_TARGET_ANA_CMPR_SRC_CHAN0: default="NOT UPDATED", esp32h2="GPIO11", esp32p4="GPIO52"} {IDF_TARGET_ANA_CMPR_EXT_REF_CHAN0: default="NOT UPDATED", esp32h2="GPIO10", esp32p4="GPIO51"} {IDF_TARGET_ANA_CMPR_SRC_CHAN1: default="NOT UPDATED", esp32p4="GPIO54"} @@ -14,13 +13,13 @@ Analog Comparator is a peripheral that can be used to compare a source signal wi 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: +Analog Comparator on {IDF_TARGET_NAME} has {IDF_TARGET_SOC_ANA_CMPR_NUM} unit(s), the channels in the unit(s) are: **UNIT0** - Source Channel: {IDF_TARGET_ANA_CMPR_SRC_CHAN0} - External Reference Channel: {IDF_TARGET_ANA_CMPR_EXT_REF_CHAN0} -- Internal Reference Channel: Range 0% ~ 70% VDD, step 10% VDD +- Internal Reference Channel: Range 0% ~ 70% of the VDD, the step is 10% of the VDD .. only:: esp32p4 @@ -28,7 +27,7 @@ Analog Comparator on {IDF_TARGET_NAME} has {IDF_TARGET_ANA_CMPR_NUM} unit(s), th - Source Channel: {IDF_TARGET_ANA_CMPR_SRC_CHAN1} - External Reference Channel: {IDF_TARGET_ANA_CMPR_EXT_REF_CHAN1} - - Internal Reference Channel: Range 0% ~ 70% VDD, step 10% VDD + - Internal Reference Channel: Range 0% ~ 70% of the VDD, the step is 10% of the VDD Functional Overview ------------------- @@ -56,7 +55,7 @@ To allocate the resource of the Analog Comparator unit, :cpp:func:`ana_cmpr_new_ - :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::ref_src` selects the reference source from internal voltage or external signal. - :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`. @@ -67,7 +66,7 @@ The function :cpp:func:`ana_cmpr_new_unit` can fail due to various errors such a ana_cmpr_handle_t cmpr = NULL; ana_cmpr_config_t config = { - .unit = ANA_CMPR_UNIT_0, + .unit = 0, .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, .ref_src = ANA_CMPR_REF_SRC_INTERNAL, .cross_type = ANA_CMPR_CROSS_ANY, @@ -199,7 +198,7 @@ Kconfig Options ETM Events ^^^^^^^^^^ - To create an analog comparator cross event, you need to include ``driver/ana_cmpr_etm.h`` additionally, and allocate the event by :cpp:func:`ana_cmpr_new_etm_event`. You can refer to :doc:`GPTimer ` for how to connect an event to a task. + To create an analog comparator cross event, you need to include ``driver/ana_cmpr_etm.h`` additionally, and allocate the event by :cpp:func:`ana_cmpr_new_etm_event`. You can refer to :doc:`ETM ` for how to connect an event to a task. Application Example ------------------- diff --git a/docs/en/api-reference/peripherals/etm.rst b/docs/en/api-reference/peripherals/etm.rst index 96165f19f43a..bca698df5dfc 100644 --- a/docs/en/api-reference/peripherals/etm.rst +++ b/docs/en/api-reference/peripherals/etm.rst @@ -70,10 +70,7 @@ Other Peripheral Events :SOC_TIMER_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/gptimer` for how to get the ETM event handle from GPTimer. :SOC_GDMA_SUPPORT_ETM: - Refer to :doc:`/api-reference/system/async_memcpy` for how to get the ETM event handle from async memcpy. :SOC_MCPWM_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/mcpwm` for how to get the ETM event handle from MCPWM. - - .. only:: esp32p4 - - :SOC_ANA_CMPR_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/ana_cmpr` for how to get the ETM event handle from analog comparator. + :SOC_ANA_CMPR_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/ana_cmpr` for how to get the ETM event handle from analog comparator. .. _etm-task: diff --git a/docs/zh_CN/api-reference/peripherals/etm.rst b/docs/zh_CN/api-reference/peripherals/etm.rst index 3f7d5baddc23..8d56935aec34 100644 --- a/docs/zh_CN/api-reference/peripherals/etm.rst +++ b/docs/zh_CN/api-reference/peripherals/etm.rst @@ -70,10 +70,7 @@ GPIO **边沿** 事件是最常见的事件类型,任何 GPIO 管脚均可触 :SOC_TIMER_SUPPORT_ETM: - 要了解如何从 GPTimer 获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/gptimer`。 :SOC_GDMA_SUPPORT_ETM: - 要了解如何从 async memcpy 获取 ETM 事件句柄,请参阅 :doc:`/api-reference/system/async_memcpy`。 :SOC_MCPWM_SUPPORT_ETM: - 要了解如何从 MCPWM 中获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/mcpwm`。 - - .. only:: esp32p4 - - :SOC_ANA_CMPR_SUPPORT_ETM: - 要了解如何从模拟比较器获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/ana_cmpr`。 + :SOC_ANA_CMPR_SUPPORT_ETM: - 要了解如何从模拟比较器获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/ana_cmpr`。 .. _etm-task: diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 02974dcc02ec..c3055b0a6051 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -18,6 +18,10 @@ examples/peripherals/adc/oneshot_read: examples/peripherals/analog_comparator: disable: - if: SOC_ANA_CMPR_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: not supported yet examples/peripherals/dac: disable: diff --git a/examples/peripherals/analog_comparator/README.md b/examples/peripherals/analog_comparator/README.md index 8a6adb523c84..330b1dcc0e30 100644 --- a/examples/peripherals/analog_comparator/README.md +++ b/examples/peripherals/analog_comparator/README.md @@ -1,11 +1,17 @@ -| Supported Targets | ESP32-H2 | -| ----------------- | -------- | +| Supported Targets | ESP32-H2 | ESP32-P4 | +| ----------------- | -------- | -------- | # 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. +This example is going to show how to use the Analog Comparator. The example toggles a GPIO to monitor the positive and negative crosses on the analog comparator unit. + +## Realization + +- If the target supports generating the analog comparator events (like ESP32-P4), the example can toggle the monitoring GPIO via Event Task Matrix (ETM). ETM can bind the analog comparator cross events (positive and negative events) with the GPIO tasks (to set or clear a GPIO), so that every event happens, hardware will execute the corresponding task without CPU involved. + +- If the target does not support to generate the analog comparator events (like ESP32-H2). The example will register an event callback on the analog comparator, and toggle the GPIO in the callback. It requires the CPU to process every event ISR, thus it is not effective as ETM and can't achieve a high resolution. ## How to Use Example diff --git a/examples/peripherals/analog_comparator/main/CMakeLists.txt b/examples/peripherals/analog_comparator/main/CMakeLists.txt index e017eb488976..07070ae02048 100644 --- a/examples/peripherals/analog_comparator/main/CMakeLists.txt +++ b/examples/peripherals/analog_comparator/main/CMakeLists.txt @@ -1,2 +1,10 @@ -idf_component_register(SRCS "ana_cmpr_example_main.c" +set(src "ana_cmpr_example_main.c") + +if(CONFIG_EXAMPLE_USE_ETM) + list(APPEND src "ana_cmpr_example_etm.c") +else() + list(APPEND src "ana_cmpr_example_intr.c") +endif() + +idf_component_register(SRCS ${src} INCLUDE_DIRS ".") diff --git a/examples/peripherals/analog_comparator/main/Kconfig.projbuild b/examples/peripherals/analog_comparator/main/Kconfig.projbuild index 1e2f780b3708..21bd9d1998f7 100644 --- a/examples/peripherals/analog_comparator/main/Kconfig.projbuild +++ b/examples/peripherals/analog_comparator/main/Kconfig.projbuild @@ -1,5 +1,20 @@ menu "Analog Comparator Example Configuration" + choice EXAMPLE_REALIZATION + prompt "Analog Comparator example realization methods" + default EXAMPLE_USE_ETM if SOC_ANA_CMPR_SUPPORT_ETM && SOC_GPIO_SUPPORT_ETM + default EXAMPLE_USE_INTR if !SOC_ANA_CMPR_SUPPORT_ETM || !SOC_GPIO_SUPPORT_ETM + config EXAMPLE_USE_INTR + bool "Use Interrupt" + help + Enable to set the monitor GPIO via interrupt callback + config EXAMPLE_USE_ETM + depends on SOC_ANA_CMPR_SUPPORT_ETM && SOC_GPIO_SUPPORT_ETM + bool "Use ETM" + help + Enable to set the monitor GPIO via Event Task Matrix + endchoice + choice EXAMPLE_REFERENCE_SOURCE prompt "Analog Comparator reference source" default EXAMPLE_INTERNAL_REF @@ -18,7 +33,7 @@ menu "Analog Comparator Example Configuration" endchoice config EXAMPLE_HYSTERESIS_COMPARATOR - depends on EXAMPLE_INTERNAL_REF + depends on EXAMPLE_INTERNAL_REF && !EXAMPLE_USE_ETM bool "Enable hysteresis comparator" default n help diff --git a/examples/peripherals/analog_comparator/main/ana_cmpr_example_etm.c b/examples/peripherals/analog_comparator/main/ana_cmpr_example_etm.c new file mode 100644 index 000000000000..a8dbfce5b109 --- /dev/null +++ b/examples/peripherals/analog_comparator/main/ana_cmpr_example_etm.c @@ -0,0 +1,133 @@ +/* + * 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 "driver/ana_cmpr_etm.h" +#include "driver/gpio_etm.h" +#include "esp_etm.h" +#include "esp_log.h" +#include "ana_cmpr_example_main.h" + +static const char *TAG = "ana_cmpr_example"; + +static void example_etm_bind_ana_cmpr_event_with_gpio_task(ana_cmpr_handle_t cmpr) +{ + /* Allocate the analog comparator positive & negative cross events */ + esp_etm_event_handle_t cmpr_pos_evt = NULL; + esp_etm_event_handle_t cmpr_neg_evt = NULL; + ana_cmpr_etm_event_config_t evt_cfg = { + .event_type = ANA_CMPR_EVENT_POS_CROSS, + }; + ESP_ERROR_CHECK(ana_cmpr_new_etm_event(cmpr, &evt_cfg, &cmpr_pos_evt)); + evt_cfg.event_type = GPIO_ETM_EVENT_EDGE_NEG; + ESP_ERROR_CHECK(ana_cmpr_new_etm_event(cmpr, &evt_cfg, &cmpr_neg_evt)); + + /* Allocate the GPIO set & clear tasks */ + esp_etm_task_handle_t gpio_pos_task = NULL; + esp_etm_task_handle_t gpio_neg_task = NULL; + gpio_etm_task_config_t task_cfg = { + .action = GPIO_ETM_TASK_ACTION_SET, + }; + ESP_ERROR_CHECK(gpio_new_etm_task(&task_cfg, &gpio_pos_task)); + task_cfg.action = GPIO_ETM_TASK_ACTION_CLR; + ESP_ERROR_CHECK(gpio_new_etm_task(&task_cfg, &gpio_neg_task)); + /* Add task to the monitor GPIO */ + ESP_ERROR_CHECK(gpio_etm_task_add_gpio(gpio_pos_task, EXAMPLE_MONITOR_GPIO_NUM)); + ESP_ERROR_CHECK(gpio_etm_task_add_gpio(gpio_neg_task, EXAMPLE_MONITOR_GPIO_NUM)); + + /* Allocate the Event Task Matrix channels */ + esp_etm_channel_handle_t etm_pos_handle; + esp_etm_channel_handle_t etm_neg_handle; + esp_etm_channel_config_t etm_cfg = {}; + ESP_ERROR_CHECK(esp_etm_new_channel(&etm_cfg, &etm_pos_handle)); + ESP_ERROR_CHECK(esp_etm_new_channel(&etm_cfg, &etm_neg_handle)); + /* Bind the events and tasks */ + ESP_ERROR_CHECK(esp_etm_channel_connect(etm_pos_handle, cmpr_pos_evt, gpio_pos_task)); + ESP_ERROR_CHECK(esp_etm_channel_connect(etm_neg_handle, cmpr_neg_evt, gpio_neg_task)); + /* Enable the ETM channels */ + ESP_ERROR_CHECK(esp_etm_channel_enable(etm_pos_handle)); + ESP_ERROR_CHECK(esp_etm_channel_enable(etm_neg_handle)); +} + +ana_cmpr_handle_t example_init_analog_comparator_etm(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, + .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_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)); +#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, + .cross_type = ANA_CMPR_CROSS_ANY, + }; + ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr)); + ESP_LOGI(TAG, "Allocate Analog Comparator with external reference"); +#endif // CONFIG_EXAMPLE_INTERNAL_REF + + /* 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 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 + * 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: 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 + return cmpr; +} + +void example_analog_comparator_etm_app(void) +{ + /* Initialize GPIO to monitor the comparator interrupt */ + example_init_monitor_gpio(); + /* Initialize Analog Comparator */ + ana_cmpr_handle_t cmpr = example_init_analog_comparator_etm(); + /* Connect the analog comparator events and gpio tasks via ETM channels */ + example_etm_bind_ana_cmpr_event_with_gpio_task(cmpr); +} diff --git a/examples/peripherals/analog_comparator/main/ana_cmpr_example_intr.c b/examples/peripherals/analog_comparator/main/ana_cmpr_example_intr.c new file mode 100644 index 000000000000..78fec3e9bc37 --- /dev/null +++ b/examples/peripherals/analog_comparator/main/ana_cmpr_example_intr.c @@ -0,0 +1,122 @@ +/* + * 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" +#include "ana_cmpr_example_main.h" + +static const char *TAG = "ana_cmpr_example"; + +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_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 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_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; + /* 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_intr(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, + .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_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 +#else + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, +#endif + }; + 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, + .cross_type = ANA_CMPR_CROSS_ANY, + }; + ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr)); + ESP_LOGI(TAG, "Allocate Analog Comparator with external 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 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 + * 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_analog_comparator_intr_app(void) +{ + /* Initialize GPIO to monitor the comparator interrupt */ + example_init_monitor_gpio(); + /* Initialize Analog Comparator */ + example_init_analog_comparator_intr(); +} 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 dff400372460..49b7d6ca84a2 100644 --- a/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.c +++ b/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.c @@ -5,118 +5,8 @@ */ #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) (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 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_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 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_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; - /* 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, - .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_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 -#else - .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, -#endif - }; - 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, - .cross_type = ANA_CMPR_CROSS_ANY, - }; - ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr)); - ESP_LOGI(TAG, "Allocate Analog Comparator with external 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 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 - * 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 -} +#include "ana_cmpr_example_main.h" void example_init_monitor_gpio(void) { @@ -133,8 +23,9 @@ void example_init_monitor_gpio(void) void app_main(void) { - /* Initialize GPIO to monitor the comparator interrupt */ - example_init_monitor_gpio(); - /* Initialize Analog Comparator */ - example_init_analog_comparator(); +#if CONFIG_EXAMPLE_USE_ETM + example_analog_comparator_etm_app(); +#else + example_analog_comparator_intr_app(); +#endif } diff --git a/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.h b/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.h new file mode 100644 index 000000000000..48e872b3ae9b --- /dev/null +++ b/examples/peripherals/analog_comparator/main/ana_cmpr_example_main.h @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#pragma once + +#include +#include "sdkconfig.h" +#include "soc/soc_caps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define EXAMPLE_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) (uint32_t)(1000000 * EXAMPLE_WAIT_TIME_PROP / (freq_approx)) + +#define EXAMPLE_MONITOR_GPIO_NUM (0) // The gpio to monitor the on cross callback + +void example_init_monitor_gpio(void); + +#if CONFIG_EXAMPLE_USE_ETM +/** + * @brief Set or clear the monitor GPIO via Event Task Matrix when cross interrupt triggers. + * @note The interrupt of analog comparator is regarded as Event, + * and the the operation of setting/clearing the GPIO is regarded as the corresponding task of the event. +* CPU won't be involved by using Event Task Matrix, so it can achieve relatively higher interrupt frequency + */ +void example_analog_comparator_etm_app(void); +#endif + +/** + * @brief Set or clear the monitor GPIO in the cross interrupt callback. + * @note The GPIO level is set manually in the callback. + * It's more flexible so that we can realize some operation like hysteresis, + * But as the operations are done in callback, CPU is involved, so it can only achieve a low interrupt frequency + */ +void example_analog_comparator_intr_app(void); + +#ifdef __cplusplus +} +#endif