# Analog Comparator

## Introduction

Analog Comparator is a peripheral that can be used to compare a source signal with the internal reference voltage or an external reference signal.

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 ESP32-H2 has 1 unit(s), the channels in the unit(s) are:

UNIT0

- Source Channel: GPIO11

- External Reference Channel: GPIO10

- Internal Reference Channel: Range 0% ~ 70% of the VDD, the step is 10% of the VDD

## Functional Overview

The following sections of this document cover the typical steps to install and operate an Analog Comparator unit:

- Resource Allocation - covers which parameters should be set up to get a unit handle and how to recycle the resources when it finishes working.

- Further Configurations - covers the other configurations that might need to specific and what they are used for.

- Enable and Disable Unit - covers how to enable and disable the unit.

- Power Management - describes how different source clock selections can affect power consumption.

- IRAM Safe - lists which functions are supposed to work even when the cache is disabled.

- Thread Safety - lists which APIs are guaranteed to be thread safe by the driver.

- Kconfig Options - lists the supported Kconfig options that can be used to make a different effect on driver behavior.

### Resource Allocation

An Analog Comparator unit channel is represented by `ana_cmpr_handle_t`. Each unit can support either an internal or an external reference.

To allocate the resource of the Analog Comparator unit, `ana_cmpr_new_unit()` need to be called to get the handle of the unit. Configurations `ana_cmpr_config_t` need to be specified while allocating the unit:

- `ana_cmpr_config_t::unit` selects the Analog Comparator unit.

- `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 `soc_periph_ana_cmpr_clk_src_t::ANA_CMPR_CLK_SRC_DEFAULT` as the clock source.

- `ana_cmpr_config_t::ref_src` selects the reference source from internal voltage or external signal.

- `ana_cmpr_config_t::cross_type` selects which kind of cross type can trigger the interrupt.

The function `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 `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 `ana_cmpr_unit_disable()` in advance, or make sure it has not enabled yet by `ana_cmpr_unit_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));

### Further Configurations

- `ana_cmpr_set_intl_reference()` - Specify the internal reference voltage when `ana_cmpr_ref_source_t::ANA_CMPR_REF_SRC_INTERNAL` is selected as reference source.

It requires `ana_cmpr_internal_ref_config_t::ref_volt` to specify the voltage. The voltage related to the VDD power supply, which can only support a certain fixed percentage of VDD. Currently on ESP32-H2, the internal reference voltage can be range to 0 ~ 70% VDD with a step 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()` - Set the debounce configuration.

It requires `ana_cmpr_debounce_config_t::wait_us` to set the interrupt waiting time. The interrupt is disabled temporarily for `ana_cmpr_debounce_config_t::wait_us` micro seconds, so that the frequent triggering can be avoid while the source signal crossing the reference signal. That is, the waiting time is supposed to be inverse ratio to the relative frequency between the source and reference. If the waiting time is set too short, it can not bypass the jitter totally, but if too long, the next crossing interrupt might be missed.

    #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()` - Set the source signal cross type.

The initial cross type is set int `ana_cmpr_new_unit()`, this function can update the cross type, even in ISR context.

    #include "driver/ana_cmpr.h"

    ESP_ERROR_CHECK(ana_cmpr_set_cross_type(cmpr, ANA_CMPR_CROSS_POS));

- `ana_cmpr_register_event_callbacks()` - Register the callbacks.

Currently it supports `ana_cmpr_event_callbacks_t::on_cross`, it will be called when the crossing event (specified by `ana_cmpr_config_t::cross_type`) occurs.

    #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));

Note

When CONFIG_ANA_CMPR_ISR_IRAM_SAFE is enabled, you should guarantee the callback context and involved data to be in internal RAM by add the attribute `IRAM_ATTR`. (See more in IRAM Safe)

### Enable and Disable Unit

- `ana_cmpr_enable()` - Enable the Analog Comparator unit.

- `ana_cmpr_disable()` - Disable the Analog Comparator unit.

After the Analog Comparator unit is enabled and the crossing event interrupt is enabled, a power management lock will be acquired if the power management is enabled (see Power Management). Under the enable state, only `ana_cmpr_set_intl_reference()` and `ana_cmpr_set_debounce()` can be called, other functions can only be called after the unit is disabled.

Calling `ana_cmpr_disable()` does the opposite.

### Power Management

When power management is enabled (i.e., CONFIG_PM_ENABLE is on), the system will adjust the APB frequency before going into light sleep, thus potentially changing the resolution of the Analog Comparator.

However, the driver can prevent the system from changing APB frequency by acquiring a power management lock of type `ESP_PM_NO_LIGHT_SLEEP`. Whenever the driver creates a Analog Comparator unit instance that has selected the clock source like `ANA_CMPR_CLK_SRC_DEFAULT` or `ANA_CMPR_CLK_SRC_XTAL` as its clock source, the driver guarantees that the power management lock is acquired when enable the channel by `ana_cmpr_enable()`. Likewise, the driver releases the lock when `ana_cmpr_disable()` is called for that channel.

### IRAM Safe

By default, the Analog Comparator interrupt will be deferred when the Cache is disabled for reasons like programming/erasing Flash. Thus the alarm interrupt will not get executed in time, which is not expected in a real-time application.

There is a Kconfig option CONFIG_ANA_CMPR_ISR_IRAM_SAFE that:

1. Enables the interrupt being serviced even when cache is disabled

2. Places all functions that used by the ISR into IRAM [1]

3. Places driver object into DRAM (in case it is allocated on PSRAM)

This allows the interrupt to run while the cache is disabled but comes at the cost of increased IRAM consumption.

There is a Kconfig option CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM that can put commonly used IO control functions into IRAM as well. So that these functions can also be executable when the cache is disabled. These IO control functions are listed as follows:

- `ana_cmpr_set_internal_reference()`

- `ana_cmpr_set_debounce()`

- `ana_cmpr_set_cross_type()`

### Thread Safety

The factory function `ana_cmpr_new_unit()` is guaranteed to be thread safe by the driver, which means, user can call it from different RTOS tasks without protection by extra locks. The following functions are allowed to run under ISR context, the driver uses a critical section to prevent them being called concurrently in both task and ISR.

- `ana_cmpr_set_internal_reference()`

- `ana_cmpr_set_debounce()`

- `ana_cmpr_set_cross_type()`

Other functions that take the `ana_cmpr_handle_t` as the first positional parameter, are not treated as thread safe. Which means the user should avoid calling them from multiple tasks.

### Kconfig Options

- CONFIG_ANA_CMPR_ISR_IRAM_SAFE controls whether the default ISR handler can work when cache is disabled, see IRAM Safe for more information.

- CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM controls where to place the Analog Comparator control functions (IRAM or Flash), see IRAM Safe for more information.

- CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG is used to enabled the debug log output. Enabling this option increases the firmware binary size.

## Application Example

- peripherals/analog_comparator shows the basic usage of the analog comparator, and other potential usages like hysteresis comparator and SPWM generator.

## API Reference

### 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.

  Parameters:

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

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

  Returns:

    - 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.

  Parameters:

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

  Returns:

    - 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.

  Note

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

  Note

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

  Note

  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

  Parameters:

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

    - ref_cfg -- [in] Internal reference configuration

  Returns:

    - 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.

  Note

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

  Note

  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

  Parameters:

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

    - dbc_cfg -- [in] Debounce configuration

  Returns:

    - 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.

  Note

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

  Note

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

  Note

  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

  Parameters:

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

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

  Returns:

    - 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.

  Note

  This function can only be called before enabling the unit

  Parameters:

    - 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

  Returns:

    - 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.

  Parameters:

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

  Returns:

    - 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.

  Parameters:

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

  Returns:

    - 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.

  Parameters:

    - 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

  Returns:

    - 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 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

  uint32_t io_loop_back

    Enable this field when the other signals that output on the comparison pins are supposed to be fed back. Normally used for debug/test scenario

  struct ana_cmpr_config_t::[anonymous] 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 of re-enabling the interrupt after the last triggering, it is used to avoid the spurious triggering while the source signal crossing the reference signal. The value should regarding how fast the source signal changes, e.g., a rapid signal requires a small wait time, otherwise the next crosses may be missed. (Unit: micro second)

struct ana_cmpr_event_callbacks_t

  Group of Analog Comparator callbacks.

  Note

  The callbacks are all running under ISR environment

  Note

  When CONFIG_ANA_CMPR_ISR_IRAM_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 internal reference source, related to VDD

  enumerator ANA_CMPR_REF_SRC_EXTERNAL

    Analog Comparator external reference source, from `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

enum ana_cmpr_cross_type_t

  Analog comparator interrupt type.

  Values:

  enumerator ANA_CMPR_CROSS_DISABLE

    Disable the cross event interrupt

  enumerator ANA_CMPR_CROSS_POS

    Positive cross can trigger event interrupt

  enumerator ANA_CMPR_CROSS_NEG

    Negative cross can trigger event interrupt

  enumerator ANA_CMPR_CROSS_ANY

    Any cross can trigger event interrupt

enum ana_cmpr_ref_voltage_t

  Analog comparator internal reference voltage.

  Values:

  enumerator ANA_CMPR_REF_VOLT_0_PCT_VDD

    Internal reference voltage equals to 0% VDD

  enumerator ANA_CMPR_REF_VOLT_10_PCT_VDD

    Internal reference voltage equals to 10% VDD

  enumerator ANA_CMPR_REF_VOLT_20_PCT_VDD

    Internal reference voltage equals to 20% VDD

  enumerator ANA_CMPR_REF_VOLT_30_PCT_VDD

    Internal reference voltage equals to 30% VDD

  enumerator ANA_CMPR_REF_VOLT_40_PCT_VDD

    Internal reference voltage equals to 40% VDD

  enumerator ANA_CMPR_REF_VOLT_50_PCT_VDD

    Internal reference voltage equals to 50% VDD

  enumerator ANA_CMPR_REF_VOLT_60_PCT_VDD

    Internal reference voltage equals to 60% VDD

  enumerator ANA_CMPR_REF_VOLT_70_PCT_VDD

    Internal reference voltage equals to 70% VDD

[1]

`ana_cmpr_event_callbacks_t::on_cross` callback and the functions invoked by itself should also be placed in IRAM, you need to take care of them by themselves.

Provide feedback about this document