# 模拟比较器

[English]

## 简介

模拟比较器是一种用于比较信号源与内部参考电压或外部参考信号的外设。

当用于比较模拟信号时，集成模拟比较器可以低成本替代运算放大器。不同于运算放大器的连续比较，ESP 模拟比较器由时钟源驱动，其采样频率取决于时钟的频率。

ESP32-C5 上的模拟比较器有 1 个单元，单元中的通道如下：

UNIT0

- 源通道：GPIO9

- 外部参考通道：GPIO8

- 内部参考通道：电压范围是 VDD 的 0% ~ 70%，步长为 VDD 的 10%

## 功能概述

本文中的以下章节涵盖了安装及操作模拟比较器单元的基本步骤：

- 资源分配 - 涵盖了应设置哪些参数以获取单元句柄，以及完成工作后如何回收资源。

- 进一步配置 - 涵盖了可能需要指定的其他配置及其用途。

- 启用和禁用单元 - 涵盖了如何启用和禁用单元。

- 电源管理 - 描述了不同时钟源对功耗的影响。

- IRAM 安全 - 列出了在 cache 被禁用时也能起效的函数。

- 线程安全 - 列出了驱动程序中线程安全的 API。

- Kconfig 选项 - 列出了支持的 Kconfig 选项，这些选项可以对驱动程序产生不同影响。

- ETM 事件 - 介绍了如何创建一个模拟比较器跨越事件。

### 资源分配

模拟比较器单元由 `ana_cmpr_handle_t` 表示，每个单元都可支持内部或外部的参考信号。

通过调用 `ana_cmpr_new_unit()` 来获取单元句柄以分配资源。在分配单元时需要指定 `ana_cmpr_config_t` 配置：

- `ana_cmpr_config_t::unit` 选择模拟比较器单元。

- `ana_cmpr_config_t::clk_src` 选择模拟比较器的时钟源，这将影响采样频率。请注意，模拟比较器的时钟源来自 IO MUX，与 Sigma-Delta 调制器 (SDM) 和毛刺过滤器 (Glitch Filter) 等 GPIO 扩展外设共享时钟源。如果为多个 GPIO 扩展外设指定不同的时钟源，则配置将失败。这些外设的默认时钟源是相同的，通常选择 `soc_periph_ana_cmpr_clk_src_t::ANA_CMPR_CLK_SRC_DEFAULT` 即可。

- `ana_cmpr_config_t::ref_src` 选择内部参考电压或外部参考信号为参考信号源。

- `ana_cmpr_config_t::cross_type` 选择哪种类型的跨零信号可以触发中断。

函数 `ana_cmpr_new_unit()` 可能因内存不足、参数无效等各种错误而失败。如果不再需要先前创建的模拟比较器单元，可通过调用 `ana_cmpr_del_unit()` 来回收资源，从而释放底层硬件通道的资源供其他用途。在删除模拟比较器单元句柄之前，首先应通过 `ana_cmpr_disable()` 禁用句柄，或者确保尚未通过 `ana_cmpr_enable()` 启用该单元。

    #include "driver/ana_cmpr.h"

    ana_cmpr_handle_t cmpr = NULL;
    ana_cmpr_config_t config = {
        .unit = 0,
        .clk_src = ANA_CMPR_CLK_SRC_DEFAULT,
        .ref_src = ANA_CMPR_REF_SRC_INTERNAL,
        .cross_type = ANA_CMPR_CROSS_ANY,
    };
    ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));
    // ...
    ESP_ERROR_CHECK(ana_cmpr_del_unit(cmpr));

### 进一步配置

- `ana_cmpr_set_internal_reference()` - 选择 `ana_cmpr_ref_source_t::ANA_CMPR_REF_SRC_INTERNAL` 作为参考源时，该函数可以指定内部参考电压。

需要由 `ana_cmpr_internal_ref_config_t::ref_volt` 来指定电压。该电压受 VDD 电源电压限制，只能支持固定百分比的 VDD。目前在 ESP32-C5 上，内部参考电压范围是 VDD 的 0% ~ 70%，步长为 VDD 的 10%。

    #include "driver/ana_cmpr.h"

    ana_cmpr_internal_ref_config_t ref_cfg = {
        .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD,
    };
    ESP_ERROR_CHECK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));

- `ana_cmpr_set_debounce()` - 设置去抖配置。

通过 `ana_cmpr_debounce_config_t::wait_us` 可设置中断等待时间。跨零中断触发后，中断将暂时禁用 `ana_cmpr_debounce_config_t::wait_us` 微秒，这样可以避免信号源跨越参考信号时频繁触发中断。因此，等待时间应与信号源和参考信号之间的相对频率成反比。如果中断等待时间设置得太短，则无法完全避免抖动，但如果设置得太长，则可能会错过下一个跨越中断。

    #include "driver/ana_cmpr.h"

    ana_cmpr_debounce_config_t dbc_cfg = {
        .wait_us = 1,
    };
    ESP_ERROR_CHECK(ana_cmpr_set_debounce(cmpr, &dbc_cfg));

- `ana_cmpr_set_cross_type()` - 设置信号源跨越类型。

初始跨越类型在 `ana_cmpr_new_unit()` 中设置。即便在中断服务程序 (ISR) 的上下文中，此函数也可以更新跨越类型。

    #include "driver/ana_cmpr.h"

    ESP_ERROR_CHECK(ana_cmpr_set_cross_type(cmpr, ANA_CMPR_CROSS_POS));

- `ana_cmpr_register_event_callbacks()` - 注册回调函数。

目前支持 `ana_cmpr_event_callbacks_t::on_cross`。当发生跨越事件（由 `ana_cmpr_config_t::cross_type` 指定）时，将调用该回调函数。

    #include "driver/ana_cmpr.h"

    static bool IRAM_ATTR example_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr,
                                                         const ana_cmpr_cross_event_data_t *edata,
                                                         void *user_ctx)
    {
        // ...
        return false;
    }
    ana_cmpr_event_callbacks_t cbs = {
        .on_cross = example_ana_cmpr_on_cross_callback,
    };
    ESP_ERROR_CHECK(ana_cmpr_register_event_callbacks(cmpr, &cbs, NULL));

备注

当启用 CONFIG_ANA_CMPR_ISR_CACHE_SAFE 时，应添加属性 `IRAM_ATTR`，确保回调上下文和涉及的数据位于内部 RAM 中（详情请参阅 IRAM 安全）。

### 启用和禁用单元

- `ana_cmpr_enable()` - 启用模拟比较器单元。

- `ana_cmpr_disable()` - 禁用模拟比较器单元。

启用模拟比较器单元与跨越事件中断后，若同时启用了电源管理（详见 电源管理），则将获得电源管理锁。在 启用 状态下，只能调用 `ana_cmpr_set_internal_reference()` 和 `ana_cmpr_set_debounce()`，其他函数可在禁用单元后调用。

调用 `ana_cmpr_disable()` 则会执行与上述过程相反的操作。

### 电源管理

当启用电源管理时（即开启 CONFIG_PM_ENABLE），系统会在进入 Light-sleep 模式前调整 APB 频率，因此模拟比较器的分辨率也可能随之更改。

通过获取类型为 `ESP_PM_NO_LIGHT_SLEEP` 的电源管理锁，驱动程序可以防止系统更改 APB 频率。只要驱动程序创建的模拟比较器单元实例选择 `ANA_CMPR_CLK_SRC_DEFAULT` 或 `ANA_CMPR_CLK_SRC_XTAL` 作为其时钟源，驱动程序会确保通过 `ana_cmpr_enable()` 启用通道，并获取电源管理锁。同理，当为该通道调用 `ana_cmpr_disable()` 时，驱动程序会释放锁。

### IRAM 安全

默认情况下，当 cache 因写入或擦除 flash 等原因而被禁用时，模拟比较器的中断服务将会延迟，造成警报中断无法及时执行。在实时应用程序中通常需要避免这一情况发生。

Kconfig 选项 CONFIG_ANA_CMPR_ISR_CACHE_SAFE 支持：

1. 即使 cache 被禁用也能启用中断服务。

2. 将 ISR 使用的所有函数放入 IRAM。 [1]

3. 将驱动程序对象放入 DRAM（以防它被分配到 PSRAM上）。

启用上述 Kconfig 选项以保证在禁用 cache 时可以正常使用函数，但这会增加 IRAM 消耗。

另一个 Kconfig 选项 CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM 也支持将常用的 IO 控制函数放入 IRAM 中，以保证在禁用 cache 时可以正常使用函数。IO 控制函数如下所示：

- `ana_cmpr_set_internal_reference()`

- `ana_cmpr_set_debounce()`

- `ana_cmpr_set_cross_type()`

### 线程安全

驱动程序会确保工厂函数 `ana_cmpr_new_unit()` 的线程安全。使用时，可以直接从不同的 RTOS 任务中调用此类函数，无需额外锁保护。

驱动程序设置了临界区，以防函数同时在任务和 ISR 中被调用。因此，以下函数支持在 ISR 上下文运行：

- `ana_cmpr_set_internal_reference()`

- `ana_cmpr_set_debounce()`

- `ana_cmpr_set_cross_type()`

其他以 `ana_cmpr_handle_t` 为第一个位置参数的函数均非线程安全，因此应避免从多个任务中调用这类函数。

### Kconfig 选项

- CONFIG_ANA_CMPR_ISR_CACHE_SAFE 控制默认的 ISR 句柄在 cache 被禁用时是否可以正常工作，详见 IRAM 安全。

- CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM 控制模拟比较器控制函数的存放位置（IRAM 或 flash），详见 IRAM 安全。

- CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG 用于启用调试日志输出。启用此选项将增加固件的二进制文件大小。

### ETM 事件

创建一个模拟比较器跨越事件，需要额外包含头文件 `driver/ana_cmpr_etm.h`，并调用函数 `ana_cmpr_new_etm_event()` 来分配事件。有关如何将事件连接到任务，请参考 ETM。

## 应用示例

- peripherals/analog_comparator 展示了模拟比较器的基本用法以及其他用途（如迟滞比较器和 SPWM 发生器）。

## API 参考

### Header File

- components/esp_driver_ana_cmpr/include/driver/ana_cmpr.h

- This header file can be included with:

  >     #include "driver/ana_cmpr.h"

- This header file is a part of the API provided by the `esp_driver_ana_cmpr` component. To declare that your component depends on `esp_driver_ana_cmpr`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_driver_ana_cmpr

  > or

  >     PRIV_REQUIRES esp_driver_ana_cmpr

### Functions

esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t *ret_cmpr)

  Allocating a new analog comparator unit handle.

  参数:

    - config -- [in] The config of the analog comparator unit

    - ret_cmpr -- [out] The returned analog comparator unit handle

  返回:

    - ESP_OK Allocate analog comparator unit handle success

    - ESP_ERR_NO_MEM No memory for the analog comparator structure

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters or wrong unit number

    - ESP_ERR_INVALID_STATE The unit has been allocated or the clock source has been occupied

esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr)

  Delete the analog comparator unit handle.

  参数:

    cmpr -- [in] The handle of analog comparator unit

  返回:

    - ESP_OK Delete analog comparator unit handle success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters or wrong unit number

    - ESP_ERR_INVALID_STATE The analog comparator is not disabled yet

esp_err_t ana_cmpr_set_internal_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_internal_ref_config_t *ref_cfg)

  Set internal reference configuration.

  备注

  This function only need to be called when `ana_cmpr_config_t::ref_src` is set to `ANA_CMPR_REF_SRC_INTERNAL`.

  备注

  This function is allowed to run within ISR context including interrupt callbacks

  备注

  This function will be placed into IRAM if `CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` is on, so that it's allowed to be executed when Cache is disabled

  参数:

    - cmpr -- [in] The handle of analog comparator unit

    - ref_cfg -- [in] Internal reference configuration

  返回:

    - ESP_OK Set denounce configuration success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

    - ESP_ERR_INVALID_STATE The reference source is not `ANA_CMPR_REF_SRC_INTERNAL`

esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_config_t *dbc_cfg)

  Set debounce configuration to the analog comparator.

  备注

  This function is allowed to run within ISR context including interrupt callbacks

  备注

  This function will be placed into IRAM if `CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` is on, so that it's allowed to be executed when Cache is disabled

  参数:

    - cmpr -- [in] The handle of analog comparator unit

    - dbc_cfg -- [in] Debounce configuration

  返回:

    - ESP_OK Set denounce configuration success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

esp_err_t ana_cmpr_set_cross_type(ana_cmpr_handle_t cmpr, ana_cmpr_cross_type_t cross_type)

  Set the source signal cross type.

  备注

  The initial cross type is configured in `ana_cmpr_new_unit`, this function can update the cross type

  备注

  This function is allowed to run within ISR context including interrupt callbacks

  备注

  This function must be called before `ana_cmpr_register_event_callbacks`

  参数:

    - cmpr -- [in] The handle of analog comparator unit

    - cross_type -- [in] The source signal cross type that can trigger the interrupt

  返回:

    - ESP_OK Set denounce configuration success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cmpr_event_callbacks_t *cbs, void *user_data)

  Register analog comparator interrupt event callbacks.

  备注

  This function can only be called before enabling the unit

  参数:

    - cmpr -- [in] The handle of analog comparator unit

    - cbs -- [in] Group of callback functions

    - user_data -- [in] The user data that will be passed to callback functions directly

  返回:

    - ESP_OK Register callbacks success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

    - ESP_ERR_INVALID_STATE The analog comparator has been enabled

esp_err_t ana_cmpr_enable(ana_cmpr_handle_t cmpr)

  Enable the analog comparator unit.

  参数:

    cmpr -- [in] The handle of analog comparator unit

  返回:

    - ESP_OK Enable analog comparator unit success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

    - ESP_ERR_INVALID_STATE The analog comparator has been enabled

esp_err_t ana_cmpr_disable(ana_cmpr_handle_t cmpr)

  Disable the analog comparator unit.

  参数:

    cmpr -- [in] The handle of analog comparator unit

  返回:

    - ESP_OK Disable analog comparator unit success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

    - ESP_ERR_INVALID_STATE The analog comparator has disabled already

esp_err_t ana_cmpr_get_gpio(ana_cmpr_unit_t unit, ana_cmpr_channel_type_t chan_type, int *gpio_num)

  Get the specific GPIO number of the analog comparator unit.

  参数:

    - unit -- [in] The handle of analog comparator unit

    - chan_type -- [in] The channel type of analog comparator, like source channel or reference channel

    - gpio_num -- [out] The output GPIO number of this channel

  返回:

    - ESP_OK Get GPIO success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters or wrong unit number or wrong channel type

### Structures

struct ana_cmpr_config_t

  Analog comparator unit configuration.

  Public Members

  ana_cmpr_unit_t unit

    Analog comparator unit

  ana_cmpr_clk_src_t clk_src

    The clock source of the analog comparator, which decide the resolution of the comparator

  ana_cmpr_ref_source_t ref_src

    Reference signal source of the comparator, select using ANA_CMPR_REF_SRC_INTERNAL or ANA_CMPR_REF_SRC_EXTERNAL. For internal reference, the reference voltage should be set to `internal_ref_volt`, for external reference, the reference signal should be connect to `ANA_CMPRx_EXT_REF_GPIO`

  ana_cmpr_cross_type_t cross_type

    The crossing types that can trigger interrupt

  int intr_priority

    The interrupt priority, range 1~3. If set to 0, the driver will automatically select a relative low priority (1,2,3)

  uint32_t io_loop_back

    Deprecated. For debug/test, a signal output from other peripheral can work as comparator input.

  struct ana_cmpr_config_t flags

    Analog comparator driver flags

struct ana_cmpr_internal_ref_config_t

  Analog comparator internal reference configuration.

  Public Members

  ana_cmpr_ref_voltage_t ref_volt

    The internal reference voltage. It can be specified to a certain fixed percentage of the VDD power supply, currently supports 0%~70% VDD with a step 10%

struct ana_cmpr_debounce_config_t

  Analog comparator debounce filter configuration.

  Public Members

  uint32_t wait_us

    The wait time to prevent frequent interrupts caused by signal noise or bouncing. During the specified wait_us period, no new interrupts will be triggered. Set the value according to the signal characteristics. A rapid signal requires a small wait time, otherwise the next cross event may be missed.

struct ana_cmpr_event_callbacks_t

  Group of Analog Comparator callbacks.

  备注

  The callbacks are all running under ISR environment

  备注

  When CONFIG_ANA_CMPR_ISR_CACHE_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. The variables used in the function should be in the SRAM as well.

  Public Members

  ana_cmpr_cross_cb_t on_cross

    The callback function on cross interrupt

### Header File

- components/esp_driver_ana_cmpr/include/driver/ana_cmpr_types.h

- This header file can be included with:

  >     #include "driver/ana_cmpr_types.h"

- This header file is a part of the API provided by the `esp_driver_ana_cmpr` component. To declare that your component depends on `esp_driver_ana_cmpr`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_driver_ana_cmpr

  > or

  >     PRIV_REQUIRES esp_driver_ana_cmpr

### Structures

struct ana_cmpr_cross_event_data_t

  Analog comparator cross event data.

  Public Members

  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 Always be ANA_CMPR_CROSS_ANY if target does not support independent interrupt (like ESP32H2)

### Macros

ANA_CMPR_UNIT_0

  Deprecated:

    Analog comparator unit 0

### Type Definitions

typedef int ana_cmpr_unit_t

  Analog comparator unit.

typedef struct ana_cmpr_t *ana_cmpr_handle_t

  Analog comparator unit handle.

typedef soc_periph_ana_cmpr_clk_src_t ana_cmpr_clk_src_t

  Analog comparator clock source.

typedef bool (*ana_cmpr_cross_cb_t)(ana_cmpr_handle_t cmpr, const ana_cmpr_cross_event_data_t *edata, void *user_ctx)

  Prototype of Analog comparator event callback.

  Param cmpr:

    [in] Analog Comparator handle, created from `ana_cmpr_new_unit()`

  Param edata:

    [in] Point to Analog Comparator event data. The lifecycle of this pointer memory is inside this function, user should copy it into static memory if used outside this function. (Currently not use)

  Param user_ctx:

    [in] User registered context, passed from `ana_cmpr_register_event_callbacks()`

  Return:

    Whether a high priority task has been waken up by this callback function

### Enumerations

enum ana_cmpr_ref_source_t

  Analog comparator reference source.

  Values:

  enumerator ANA_CMPR_REF_SRC_INTERNAL

    Analog Comparator reference voltage comes from internal, divided from VDD

  enumerator ANA_CMPR_REF_SRC_EXTERNAL

    Analog Comparator reference voltage comes from external pin, e.g. `ANA_CMPR0_EXT_REF_GPIO`

enum ana_cmpr_channel_type_t

  Analog comparator channel type.

  Values:

  enumerator ANA_CMPR_SOURCE_CHAN

    Analog Comparator source channel, which is used to input the signal that to be compared

  enumerator ANA_CMPR_EXT_REF_CHAN

    Analog Comparator external reference channel, which is used as the reference signal

[1]

`ana_cmpr_event_callbacks_t::on_cross` 回调函数，以及由其调用的其他函数也应放置在 IRAM 中，请妥善处理。

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。