diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 74ac9e75cf5..0a168abb5ad 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -47,6 +47,9 @@ endif() # Analog comparator related source files if(CONFIG_SOC_ANA_CMPR_SUPPORTED) list(APPEND srcs "analog_comparator/ana_cmpr.c") + if(CONFIG_SOC_ANA_CMPR_SUPPORT_ETM) + list(APPEND srcs "analog_comparator/ana_cmpr_etm.c") + endif() endif() # DAC related source files diff --git a/components/driver/analog_comparator/ana_cmpr_etm.c b/components/driver/analog_comparator/ana_cmpr_etm.c new file mode 100644 index 00000000000..0c9494c680d --- /dev/null +++ b/components/driver/analog_comparator/ana_cmpr_etm.c @@ -0,0 +1,108 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "sdkconfig.h" +#if CONFIG_ETM_ENABLE_DEBUG_LOG +// The local log level must be defined before including esp_log.h +// Set the maximum log level for this source file +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#endif +#include "freertos/FreeRTOS.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_check.h" +#include "soc/soc_caps.h" +#include "hal/ana_cmpr_ll.h" +#include "driver/ana_cmpr_types.h" +#include "driver/ana_cmpr_etm.h" +#include "esp_private/etm_interface.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; +} + +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) +{ +#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"); + + 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); + 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); + *ret_event = &event->base; + return ESP_OK; + +err: + if (event) { + free(event); + event = NULL; + } + return ret; +} diff --git a/components/driver/analog_comparator/include/driver/ana_cmpr_etm.h b/components/driver/analog_comparator/include/driver/ana_cmpr_etm.h new file mode 100644 index 00000000000..08b205db860 --- /dev/null +++ b/components/driver/analog_comparator/include/driver/ana_cmpr_etm.h @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_err.h" +#include "esp_etm.h" +#include "driver/ana_cmpr_types.h" + +#if SOC_ANA_CMPR_SUPPORT_ETM + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ANA_CMPR_EVENT_POS_CROSS, + ANA_CMPR_EVENT_NEG_CROSS, +} ana_cmpr_event_type_t; + +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_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); + +#ifdef __cplusplus +} +#endif + +#endif // SOC_ANA_CMPR_SUPPORT_ETM 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 acafb6ccda9..52a92b5eb14 100644 --- a/components/driver/analog_comparator/include/driver/ana_cmpr_types.h +++ b/components/driver/analog_comparator/include/driver/ana_cmpr_types.h @@ -7,6 +7,7 @@ #pragma once #include +#include "soc/soc_caps.h" #include "soc/clk_tree_defs.h" #ifdef __cplusplus @@ -18,7 +19,10 @@ extern "C" { * */ typedef enum { - ANA_CMPR_UNIT_0, /*!< Analog Comparator unit */ + 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; /** 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 351f89c7024..47958aa7e60 100644 --- a/components/esp_hw_support/include/esp_private/etm_interface.h +++ b/components/esp_hw_support/include/esp_private/etm_interface.h @@ -25,6 +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_trigger_peripheral_t; /** diff --git a/components/hal/esp32p4/include/hal/ana_cmpr_ll.h b/components/hal/esp32p4/include/hal/ana_cmpr_ll.h index 9f4abbf6d37..1ce151c0797 100644 --- a/components/hal/esp32p4/include/hal/ana_cmpr_ll.h +++ b/components/hal/esp32p4/include/hal/ana_cmpr_ll.h @@ -10,6 +10,7 @@ #include "hal/misc.h" #include "hal/assert.h" #include "soc/ana_cmpr_struct.h" +#include "soc/soc_etm_source.h" #ifdef __cplusplus extern "C" { @@ -22,6 +23,8 @@ extern "C" { #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 * diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index e5e7e61fd51..f93ed20ca74 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -395,6 +395,14 @@ config SOC_ANA_CMPR_SUPPORT_MULTI_INTR bool default y +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/gpio_struct.h b/components/soc/esp32p4/include/soc/gpio_struct.h index 748d4c2b7db..052c0b9a6db 100644 --- a/components/soc/esp32p4/include/soc/gpio_struct.h +++ b/components/soc/esp32p4/include/soc/gpio_struct.h @@ -553,7 +553,7 @@ typedef union { uint32_t val; } gpio_clock_gate_reg_t; -/** Type of zero_det0_filter_cnt register +/** Type of zero_det_filter_cnt register * GPIO analog comparator zero detect filter count */ typedef union { diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 8cb49267ba9..987b968e658 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -221,8 +221,10 @@ #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_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) /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32-P4 has 2 I2Cs