Merge branch 'refactor/ana_cmpr_driver' into 'master'

refactor(ana_cmpr): enhanced the driver implementation

See merge request espressif/esp-idf!38353
This commit is contained in:
morris
2025-04-14 12:03:25 +08:00
44 changed files with 609 additions and 416 deletions
@@ -1,11 +1,11 @@
set(src "ana_cmpr_example_main.c")
if(CONFIG_EXAMPLE_USE_ETM)
if(CONFIG_EXAMPLE_MONITOR_IO_FROM_ETM)
list(APPEND src "ana_cmpr_example_etm.c")
else()
list(APPEND src "ana_cmpr_example_intr.c")
endif()
idf_component_register(SRCS ${src}
PRIV_REQUIRES esp_driver_ana_cmpr esp_driver_gpio
INCLUDE_DIRS ".")
PRIV_REQUIRES esp_driver_ana_cmpr esp_driver_gpio
INCLUDE_DIRS ".")
@@ -1,39 +1,41 @@
menu "Analog Comparator Example Configuration"
menu "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"
choice EXAMPLE_MONITOR_IO_FROM
prompt "Monitor IO signal comes from"
default EXAMPLE_MONITOR_IO_FROM_ETM if SOC_ANA_CMPR_SUPPORT_ETM && SOC_GPIO_SUPPORT_ETM
default EXAMPLE_MONITOR_IO_FROM_INTR
config EXAMPLE_MONITOR_IO_FROM_INTR
bool "Analog Comparator Interrupt"
help
Enable to set the monitor GPIO via interrupt callback
config EXAMPLE_USE_ETM
config EXAMPLE_MONITOR_IO_FROM_ETM
depends on SOC_ANA_CMPR_SUPPORT_ETM && SOC_GPIO_SUPPORT_ETM
bool "Use ETM"
bool "Analog Comparator Event-Task-Matrix"
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
choice EXAMPLE_REF_FROM
prompt "Analog Comparator reference voltage comes from"
default EXAMPLE_REF_FROM_INTERNAL
help
Decide the reference signal comes from internal or external
Decide the reference voltage comes from internal or external
config EXAMPLE_INTERNAL_REF
bool "Internal reference"
config EXAMPLE_REF_FROM_INTERNAL
bool "Internal"
help
The source signal will refer to an internal voltage, which related to VDD.
The source signal will refer to an internal voltage, which is divided from VDD.
config EXAMPLE_EXTERNAL_REF
bool "External reference"
config EXAMPLE_REF_FROM_EXTERNAL
bool "External pin"
help
The source signal will refer to the external signal on a specific GPIO.
endchoice
config EXAMPLE_HYSTERESIS_COMPARATOR
depends on EXAMPLE_INTERNAL_REF && !EXAMPLE_USE_ETM
depends on EXAMPLE_REF_FROM_INTERNAL && EXAMPLE_MONITOR_IO_FROM_INTR
bool "Enable hysteresis comparator"
default n
help
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -7,16 +7,11 @@
#include <stdio.h>
#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 */
@@ -36,13 +31,13 @@ static void example_etm_bind_ana_cmpr_event_with_gpio_task(ana_cmpr_handle_t cmp
task_cfg.actions[0] = GPIO_ETM_TASK_ACTION_SET;
task_cfg.actions[1] = GPIO_ETM_TASK_ACTION_CLR;
ESP_ERROR_CHECK(gpio_new_etm_task(&task_cfg, &gpio_set_task, &gpio_clr_task));
/* Add task to the monitor GPIO */
/* Bind different tasks to the same GPIO */
ESP_ERROR_CHECK(gpio_etm_task_add_gpio(gpio_set_task, EXAMPLE_MONITOR_GPIO_NUM));
ESP_ERROR_CHECK(gpio_etm_task_add_gpio(gpio_clr_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_handle_t etm_pos_handle = NULL;
esp_etm_channel_handle_t etm_neg_handle = NULL;
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));
@@ -54,18 +49,13 @@ static void example_etm_bind_ana_cmpr_event_with_gpio_task(ana_cmpr_handle_t cmp
ESP_ERROR_CHECK(esp_etm_channel_enable(etm_neg_handle));
}
ana_cmpr_handle_t example_init_analog_comparator_etm(void)
static void 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;
int src_gpio = -1;
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &src_gpio));
#if CONFIG_EXAMPLE_INTERNAL_REF
#if CONFIG_EXAMPLE_REF_FROM_INTERNAL
/* Step 1: Allocate the new analog comparator unit */
ana_cmpr_config_t config = {
.unit = EXAMPLE_ANA_CMPR_UNIT,
@@ -74,13 +64,14 @@ ana_cmpr_handle_t example_init_analog_comparator_etm(void)
.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 = {
/* Set the internal reference voltage to 50% VDD */
.ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD,
};
ESP_ERROR_CHECK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference voltage: %d%% * VDD, source from GPIO %d", (int)ref_cfg.ref_volt * 10, src_gpio);
#else
/* Step 1: Allocate the new analog comparator unit */
ana_cmpr_config_t config = {
@@ -90,8 +81,10 @@ ana_cmpr_handle_t example_init_analog_comparator_etm(void)
.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
int ext_ref_gpio = -1;
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_EXT_REF_CHAN, &ext_ref_gpio));
ESP_LOGI(TAG, "Allocate Analog Comparator with external reference from GPIO %d, source from GPIO %d", ext_ref_gpio, src_gpio);
#endif // CONFIG_EXAMPLE_REF_FROM_INTERNAL
/* Step 2: (Optional) Set the debounce configuration
* It's an optional configuration, if the wait time is set in debounce configuration,
@@ -109,23 +102,19 @@ ana_cmpr_handle_t example_init_analog_comparator_etm(void)
};
ESP_ERROR_CHECK(ana_cmpr_set_debounce(cmpr, &dbc_cfg));
/* Step 3: Enable the analog comparator unit */
ESP_ERROR_CHECK(ana_cmpr_enable(cmpr));
/* Step 3: Connect the analog comparator events and gpio tasks via ETM channels */
example_etm_bind_ana_cmpr_event_with_gpio_task(cmpr);
ESP_LOGI(TAG, "Connected analog comparator events and GPIO tasks");
#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;
/* Step 4: Enable the analog comparator unit */
ESP_ERROR_CHECK(ana_cmpr_enable(cmpr));
ESP_LOGI(TAG, "Analog comparator enabled");
}
void example_analog_comparator_etm_app(void)
{
/* Initialize GPIO to monitor the comparator interrupt */
/* Initialize GPIO to monitor the comparator cross event */
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);
example_init_analog_comparator_etm();
}
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -7,13 +7,8 @@
#include <stdio.h>
#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)
@@ -37,18 +32,13 @@ static bool example_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr,
return false;
}
void example_init_analog_comparator_intr(void)
static 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;
int src_gpio = -1;
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &src_gpio));
#if CONFIG_EXAMPLE_INTERNAL_REF
#if CONFIG_EXAMPLE_REF_FROM_INTERNAL
/* Step 1: Allocate the new analog comparator unit */
ana_cmpr_config_t config = {
.unit = EXAMPLE_ANA_CMPR_UNIT,
@@ -57,7 +47,6 @@ void example_init_analog_comparator_intr(void)
.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 = {
@@ -65,10 +54,12 @@ void example_init_analog_comparator_intr(void)
/* 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
/* Set the internal reference voltage to 50% VDD */
.ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD,
#endif
#endif // CONFIG_EXAMPLE_HYSTERESIS_COMPARATOR
};
ESP_ERROR_CHECK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference voltage: %d%% * VDD, source from GPIO %d", (int)ref_cfg.ref_volt * 10, src_gpio);
#else
/* Step 1: Allocate the new analog comparator unit */
ana_cmpr_config_t config = {
@@ -78,8 +69,10 @@ void example_init_analog_comparator_intr(void)
.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
int ext_ref_gpio = -1;
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_EXT_REF_CHAN, &ext_ref_gpio));
ESP_LOGI(TAG, "Allocate Analog Comparator with external reference from GPIO %d, source from GPIO %d", ext_ref_gpio, src_gpio);
#endif // CONFIG_EXAMPLE_REF_FROM_INTERNAL
/* Step 2: (Optional) Set the debounce configuration
* It's an optional configuration, if the wait time is set in debounce configuration,
@@ -105,17 +98,12 @@ void example_init_analog_comparator_intr(void)
/* 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
ESP_LOGI(TAG, "Analog comparator enabled");
}
void example_analog_comparator_intr_app(void)
{
/* Initialize GPIO to monitor the comparator interrupt */
/* Initialize GPIO to monitor the comparator cross event */
example_init_monitor_gpio();
/* Initialize Analog Comparator */
example_init_analog_comparator_intr();
@@ -23,7 +23,7 @@ void example_init_monitor_gpio(void)
void app_main(void)
{
#if CONFIG_EXAMPLE_USE_ETM
#if CONFIG_EXAMPLE_MONITOR_IO_FROM_ETM
example_analog_comparator_etm_app();
#else
example_analog_comparator_intr_app();
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -9,29 +9,29 @@
#include <stdint.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/ana_cmpr.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_MONITOR_GPIO_NUM (0) // The gpio to monitor the comparator cross event
#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))
#if CONFIG_IDF_TARGET_ESP32P4
#define EXAMPLE_MONITOR_GPIO_NUM (32) // The gpio to monitor the on cross callback
#else
#define EXAMPLE_MONITOR_GPIO_NUM (0) // The gpio to monitor the on cross callback
#endif
#define TAG "example"
void example_init_monitor_gpio(void);
#if CONFIG_EXAMPLE_USE_ETM
#if CONFIG_EXAMPLE_MONITOR_IO_FROM_ETM
/**
* @brief Set or clear the monitor GPIO via Event Task Matrix when cross interrupt triggers.
* @brief Set or clear the monitor GPIO via Event Task Matrix when cross event fires.
* @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
* 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
@@ -17,12 +17,8 @@ from pytest_embedded_idf.utils import idf_parametrize
@idf_parametrize('target', ['esp32h2', 'esp32p4', 'esp32c5', 'esp32c61'], indirect=['target'])
def test_ana_cmpr_example(dut: Dut) -> None:
sdkconfig = dut.app.sdkconfig
dut.expect(
r'ana_cmpr_example: Analog Comparator source gpio ([0-9]+), external reference gpio ([0-9]+)', timeout=10
)
if sdkconfig['EXAMPLE_INTERNAL_REF']:
dut.expect('ana_cmpr_example: Allocate Analog Comparator with internal reference', timeout=10)
dut.expect(r'ana_cmpr_example: Analog comparator enabled, reference voltage: [0-9]+% \* VDD', timeout=10)
elif sdkconfig['EXAMPLE_EXTERNAL_REF']:
dut.expect('ana_cmpr_example: Allocate Analog Comparator with external reference', timeout=10)
dut.expect('ana_cmpr_example: Analog comparator enabled, external reference selected', timeout=10)
if sdkconfig['EXAMPLE_REF_FROM_INTERNAL']:
dut.expect_exact('Allocate Analog Comparator with internal reference voltage')
elif sdkconfig['EXAMPLE_REF_FROM_EXTERNAL']:
dut.expect_exact('Allocate Analog Comparator with external reference from GPIO')
dut.expect_exact('Analog comparator enabled')
@@ -1,2 +1,2 @@
CONFIG_EXAMPLE_INTERNAL_REF=n
CONFIG_EXAMPLE_EXTERNAL_REF=y
CONFIG_EXAMPLE_REF_FROM_INTERNAL=n
CONFIG_EXAMPLE_REF_FROM_EXTERNAL=y
@@ -1,2 +1,2 @@
CONFIG_EXAMPLE_INTERNAL_REF=y
CONFIG_EXAMPLE_EXTERNAL_REF=n
CONFIG_EXAMPLE_REF_FROM_INTERNAL=y
CONFIG_EXAMPLE_REF_FROM_EXTERNAL=n