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

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

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

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

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

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:

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.

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

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/driver/analog_comparator/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 driver component. To declare that your component depends on driver, add the following to your CMakeLists.txt:

    REQUIRES driver
    

    or

    PRIV_REQUIRES driver
    

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 comparision 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/driver/analog_comparator/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 driver component. To declare that your component depends on driver, add the following to your CMakeLists.txt:

    REQUIRES driver
    

    or

    PRIV_REQUIRES driver
    

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.