# Analog Comparator

[中文]

## Overview

An analog comparator tells you whether a source signal is above or below a reference signal. The reference can come from either an internal generator or an external input.

This makes the analog comparator useful for tasks such as:

- Detecting whether a waveform crosses a fixed threshold

- Turning a sine wave into a digital square wave around a chosen reference level

- Comparing one analog signal against another analog signal

- Generating interrupts or ETM events when the comparison result changes

- Building simple hardware signal-processing pipelines without continuous CPU involvement

Note

The analog comparator peripheral is not a continuous-time comparator in the same sense as a discrete analog comparator IC or an op-amp based analog front end. It is driven by a source clock, so comparison results are sampled in hardware time. In practice, clock source, scan timing, debounce, and ETM configuration all affect what you observe on real signals.

## Quick Start

If you are new to this peripheral, start with the simplest workflow:

1. Create a comparator unit

2. Select the source signal and reference source

3. Configure the internal reference or external reference input

4. Optionally configure debounce

5. Register a callback or create ETM connections

6. Enable the comparator

The following example uses an internal reference and an interrupt callback to detect when a source signal crosses 50% VDD:

    ana_cmpr_handle_t cmpr = NULL;
    ana_cmpr_config_t config = {
        .unit = 0,                            // Pick a comparator unit that is available on your target
        .clk_src = ANA_CMPR_CLK_SRC_DEFAULT,  // Most applications can use the default clock source
        .ref_src = ANA_CMPR_REF_SRC_INTERNAL, // Use the internal reference for a simple fixed threshold
        .cross_type = ANA_CMPR_CROSS_ANY,     // Trigger on both positive and negative crossings
        .src_chan0_gpio = 0,                  // Replace with the analog comparator source GPIO wired on your board
    };
    ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));

    ana_cmpr_internal_ref_config_t ref_cfg = {
        .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, // Set the internal reference voltage to 50% of VDD, i.e., compare whether the source signal is above or below half of the supply voltage
    };
    ESP_ERROR_CHECK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));

    ana_cmpr_debounce_config_t dbc_cfg = {
        .wait_us = 10, // Set a debounce time of 10 microseconds to suppress duplicate interrupts from noisy signals around the threshold
    };
    ESP_ERROR_CHECK(ana_cmpr_set_debounce(cmpr, &dbc_cfg));

    ana_cmpr_event_callbacks_t cbs = {
        .on_cross = example_ana_cmpr_on_cross_callback, // Register a callback to be called when a crossing event occurs; this callback should be defined elsewhere in your code
    };
    ESP_ERROR_CHECK(ana_cmpr_register_event_callbacks(cmpr, &cbs, NULL));

    ESP_ERROR_CHECK(ana_cmpr_enable(cmpr));

This flow introduces the most important ideas:

- `ana_cmpr_new_unit()` creates a comparator instance and selects the source GPIO and reference source.

- `ana_cmpr_set_internal_reference()` chooses the threshold when using the internal reference.

- `ana_cmpr_set_debounce()` can suppress duplicate crossing interrupts caused by noisy or slow-moving signals.

- `ana_cmpr_register_event_callbacks()` lets your code react when the comparison result changes.

- `ana_cmpr_enable()` starts the hardware after configuration is complete.

The rest of this document expands this flow into typical usage scenarios.

### Lifecycle and Valid API States

The following diagram shows the analog comparator lifecycle and the states in which each API is intended to be used:

            flowchart TD
        NC([Not created]) -->|ana_cmpr_new_unit| INIT[Init / Disabled]
        INIT -->|ana_cmpr_enable| EN[Enabled]
        EN -->|ana_cmpr_disable| INIT
        INIT -->|ana_cmpr_del_unit| NC

        subgraph INIT_APIS [Init-state APIs]
            SCAN[ana_cmpr_set_scan_config]
            ADD[ana_cmpr_add_src_chan<br/>ana_cmpr_remove_src_chan]
            CB[ana_cmpr_register_event_callbacks]
        end

        subgraph BOTH_APIS [APIs usable in both states]
            IR[ana_cmpr_set_internal_reference]
            DBC[ana_cmpr_set_debounce]
        end

        subgraph EN_APIS [Enabled-only API]
            TRIG[ana_cmpr_trigger_scan]
        end

        INIT -. can call .-> SCAN
        INIT -. can call .-> ADD
        INIT -. can call .-> CB
        INIT -. can call .-> IR
        INIT -. can call .-> DBC
        EN -. can call .-> IR
        EN -. can call .-> DBC
        EN -. can call .-> TRIG

        classDef stateNeutral fill:#f8fafc,stroke:#64748b,stroke-width:1.5px,color:#111827;
        classDef stateInit fill:#eff6ff,stroke:#2563eb,stroke-width:1.5px,color:#111827;
        classDef stateEnabled fill:#fdf2f8,stroke:#db2777,stroke-width:1.5px,color:#111827;
        classDef initApi fill:#eff6ff,stroke:#60a5fa,color:#111827;
        classDef bothApi fill:#ecfdf5,stroke:#10b981,color:#111827;
        classDef enabledApi fill:#fdf2f8,stroke:#f472b6,color:#111827;

        class NC stateNeutral;
        class INIT stateInit;
        class EN stateEnabled;
        class SCAN,ADD,CB initApi;
        class IR,DBC bothApi;
        class TRIG enabledApi;

The main constraints to remember are:

- `ana_cmpr_register_event_callbacks()`, `ana_cmpr_add_src_chan()`, `ana_cmpr_remove_src_chan()`, and `ana_cmpr_set_scan_config()` are intended to be used while the comparator is still in init state.

- `ana_cmpr_trigger_scan()` only works after `ana_cmpr_enable()`.

- `ana_cmpr_del_unit()` requires the comparator to be disabled first.

## Scenario 1: Detect When a Signal Crosses a Fixed Threshold

Use this setup when you have one analog input and you only care whether it is above or below a threshold.

Typical examples:

- Detect whether a sensor output rises above a limit

- Convert a sine wave into a digital waveform around a fixed threshold

- Trigger software when a signal changes polarity around mid-supply

The easiest way to build this is to compare the source signal against the internal reference.

### Example: Internal Reference with Callback

    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)
    {
        if (edata->cross_type == ANA_CMPR_CROSS_POS) {
            gpio_set_level(EXAMPLE_MONITOR_GPIO_NUM, 1);
        } else if (edata->cross_type == ANA_CMPR_CROSS_NEG) {
            gpio_set_level(EXAMPLE_MONITOR_GPIO_NUM, 0);
        }
        return false;
    }

    ana_cmpr_handle_t cmpr = NULL;
    ana_cmpr_config_t config = {
        .unit = 0,                            // Use a valid unit index for the selected target
        .clk_src = ANA_CMPR_CLK_SRC_DEFAULT,  // Start with default unless you need specific timing
        .ref_src = ANA_CMPR_REF_SRC_INTERNAL, // Compare source against internal threshold
        .cross_type = ANA_CMPR_CROSS_ANY,     // Report both positive and negative crossings
        .src_chan0_gpio = 0,                  // Replace with the source channel GPIO connected on your board
    };
    ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));

    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_debounce_config_t dbc_cfg = {
        .wait_us = 10,
    };
    ESP_ERROR_CHECK(ana_cmpr_set_debounce(cmpr, &dbc_cfg));

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

    ESP_ERROR_CHECK(ana_cmpr_enable(cmpr));

### How to Read the Configuration

The `ana_cmpr_config_t` structure describes the basic shape of the comparator instance:

- `ana_cmpr_config_t::unit` selects which comparator unit to use.

- `ana_cmpr_config_t::clk_src` selects the comparator source clock. For most applications, `ANA_CMPR_CLK_SRC_DEFAULT` is the right starting point.

- `ana_cmpr_config_t::ref_src` selects whether the reference comes from the internal threshold generator or an external analog input.

- `ana_cmpr_config_t::cross_type` selects which crossings should trigger the interrupt callback: positive, negative, or both.

- `ana_cmpr_config_t::src_chan0_gpio` selects the source GPIO on targets whose analog comparator pads are configurable.

- `ana_cmpr_config_t::resample_limit` sets the unit-wide number of consecutive consistent samples required before a channel state update is accepted.

When using the internal reference, `ana_cmpr_set_internal_reference()` sets the threshold with `ana_cmpr_internal_ref_config_t::ref_volt`. The available values are fixed percentages of VDD. For example, `ANA_CMPR_REF_VOLT_50_PCT_VDD` means the comparator reports whether the source signal is above or below half of the supply voltage.

### Debounce and Signal Stability

Real analog signals are often noisy near the threshold. Without debounce, a signal that slowly moves across the threshold or jitters around it may trigger several crossing interrupts in a short time.

Use `ana_cmpr_set_debounce()` to suppress these duplicate crossings:

- `ana_cmpr_debounce_config_t::wait_us` is the time window during which new crossing interrupts are temporarily ignored after one crossing has already been reported.

As a rule of thumb:

- Increase `wait_us` if your signal is noisy and you see too many interrupts.

- Decrease `wait_us` if your signal changes quickly and you start missing real crossings.

### Callback Behavior

Register callbacks with `ana_cmpr_register_event_callbacks()` before enabling the unit.

The comparator currently provides one callback group member:

- `ana_cmpr_event_callbacks_t::on_cross`

The callback receives `ana_cmpr_cross_event_data_t`, which tells you:

- `ana_cmpr_cross_event_data_t::cross_type` - whether the source crossed upward or downward

- `ana_cmpr_cross_event_data_t::src_chan_id` - which source channel triggered the event on targets that support multiple source channels

On targets that do not support independent positive and negative interrupt reporting, `ana_cmpr_cross_event_data_t::cross_type` can always be reported as `ANA_CMPR_CROSS_ANY`.

The callback runs in interrupt context, so keep it short and non-blocking.

Note

If CONFIG_ANA_CMPR_ISR_CACHE_SAFE is enabled, place the callback and any accessed data in internal RAM.

## Scenario 2: Compare a Signal Against an External Reference

Use this setup when the reference level is not a fixed percentage of VDD.

Typical examples:

- Compare a sensor signal against a voltage divider output

- Compare a waveform against another waveform

- Generate a digital result from a source/reference pair that both come from analog front-end circuitry

In this case, the comparator source is still your input signal, but the reference comes from another analog input.

### Example: External Reference Input

    ana_cmpr_handle_t cmpr = NULL;
    ana_cmpr_config_t config = {
        .unit = 0,                             // Use a valid unit index for the selected target
        .clk_src = ANA_CMPR_CLK_SRC_DEFAULT,   // Default clock is usually enough
        .ref_src = ANA_CMPR_REF_SRC_EXTERNAL,  // Select external reference mode
        .cross_type = ANA_CMPR_CROSS_ANY,      // Report both crossing directions
        .src_chan0_gpio = 0,                   // Source signal GPIO from your board design
        .ext_ref_gpio = 1,                     // Reference signal GPIO from your board design
    };
    ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));

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

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

    ESP_ERROR_CHECK(ana_cmpr_enable(cmpr));

### What Changes Compared with Scenario 1

The main difference is `ana_cmpr_config_t::ref_src`:

- `ANA_CMPR_REF_SRC_INTERNAL` means the reference is generated inside the comparator block.

- `ANA_CMPR_REF_SRC_EXTERNAL` means the reference comes from a dedicated analog input.

When using an external reference:

- `ana_cmpr_config_t::ext_ref_gpio` becomes meaningful on targets with configurable analog comparator pads.

- `ana_cmpr_set_internal_reference()` is not used.

You can query the actual GPIOs in use with `ana_cmpr_get_channel_gpio()`:

    gpio_num_t src_gpio = -1;
    gpio_num_t ext_ref_gpio = -1;
    // Read back actual channel mapping after initialization.
    ESP_ERROR_CHECK(ana_cmpr_get_channel_gpio(cmpr, ANA_CMPR_SOURCE_CHAN, 0, &src_gpio));
    ESP_ERROR_CHECK(ana_cmpr_get_channel_gpio(cmpr, ANA_CMPR_EXT_REF_CHAN, 0, &ext_ref_gpio));

## Scenario 3: Build a Low-CPU Hardware Signal Path with ETM

Use this setup when you want the hardware to react to crossings directly, without routing every event through the CPU.

Typical examples:

- Turn a sampled analog input into a GPIO waveform with very low CPU load

- Use a timer to schedule comparator scans periodically

- Connect comparator crossings to other peripherals through ETM

### Example: GPTimer Periodic Scan with ETM

peripherals/analog_comparator/etm_periodic_scan example builds the following hardware chain:

- GPTimer alarm event -> GPTimer enable-alarm task

- GPTimer alarm event -> Analog comparator start task

- Analog comparator positive cross event -> GPIO set task

- Analog comparator negative cross event -> GPIO clear task

In other words, the timer schedules scans, the comparator samples the source signal, and the crossing result drives a monitor GPIO directly through ETM.

The key comparator-side configuration looks like this:

    ana_cmpr_handle_t cmpr = NULL;
    ana_cmpr_config_t config = {
        .unit = 0,                             // Use a valid unit index for your target
        .clk_src = ANA_CMPR_CLK_SRC_DEFAULT,   // Keep default unless ETM timing requires otherwise
        .ref_src = ANA_CMPR_REF_SRC_INTERNAL,  // Use internal reference for threshold
        .cross_type = ANA_CMPR_CROSS_ANY,      // Keep both edge directions for ETM output waveform
        .src_chan0_gpio = 0,                   // Set according to your board's source signal wiring
        .resample_limit = 3,                   // Improve noise immunity before reporting channel state
    };
    ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));

    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_scan_config_t scan_cfg = {
        .scan_mode = ANA_CMPR_SCAN_MODE_FULL,  // Scan all configured channels each cycle
        .poll_period_us = 2,                   // Tune this for update rate vs. timing margin
    };
    ESP_ERROR_CHECK(ana_cmpr_set_scan_config(cmpr, &scan_cfg));

    ana_cmpr_etm_task_config_t cmpr_task_cfg = {
        .task_type = ANA_CMPR_TASK_START,
    };
    ESP_ERROR_CHECK(ana_cmpr_new_etm_task(cmpr, &cmpr_task_cfg, &cmpr_start_task));

    ana_cmpr_etm_event_config_t pos_evt_cfg = {
        .event_type = ANA_CMPR_EVENT_POS_CROSS, // Rising crossing event
        .src_chan_id = 0,                       // Monitor source channel 0 in this example
    };
    ESP_ERROR_CHECK(ana_cmpr_new_etm_event(cmpr, &pos_evt_cfg, &cmpr_pos_evt));

    ana_cmpr_etm_event_config_t neg_evt_cfg = {
        .event_type = ANA_CMPR_EVENT_NEG_CROSS, // Falling crossing event
        .src_chan_id = 0,                       // Same source channel as positive crossing
    };
    ESP_ERROR_CHECK(ana_cmpr_new_etm_event(cmpr, &neg_evt_cfg, &cmpr_neg_evt));

### Understanding Scan Configuration

When the target supports source-channel scan, `ana_cmpr_set_scan_config()` controls how the comparator walks through source channels:

- `ana_cmpr_scan_config_t::scan_mode` selects the scanning behavior.

- `ana_cmpr_scan_config_t::poll_period_us` sets the wait time between channel comparisons.

These fields matter most when:

- you use multiple source channels

- the source signal is noisy

- you want periodic sampling instead of interrupting on every hardware edge

In practice:

- Shorter `poll_period_us` means faster scan response but tighter timing margins.

### ETM Event and Task Handles

The analog comparator provides ETM handles through two APIs:

- `ana_cmpr_new_etm_event()` creates an event handle from a comparator crossing.

- `ana_cmpr_new_etm_task()` creates a task handle that can be triggered by another ETM event.

In the current analog comparator driver:

- ETM event type is selected by `ana_cmpr_etm_event_config_t::event_type`

- The source channel is selected by `ana_cmpr_etm_event_config_t::src_chan_id`

- Optional event delay is configured by `ana_cmpr_etm_event_config_t::event_delay`

- Task type is selected by `ana_cmpr_etm_task_config_t::task_type`

For how to connect the comparator events and tasks to ETM channels, refer to ETM.

## Working with Multiple Source Channels

Some targets support more than one source channel per comparator unit. If your application needs to sample several analog inputs against the same reference, you can configure extra source channels while the comparator is in init state.

The relevant APIs are:

- `ana_cmpr_add_src_chan()`

- `ana_cmpr_remove_src_chan()`

- `ana_cmpr_set_src_chan_cross_type()`

Example:

    ana_cmpr_src_chan_config_t src_cfg = {
        .gpio_num = EXAMPLE_SRC_CHAN1_GPIO,
        .cross_type = ANA_CMPR_CROSS_ANY,
    };
    ESP_ERROR_CHECK(ana_cmpr_add_src_chan(cmpr, 1, &src_cfg));

When using multiple source channels:

- Add or remove channels only before `ana_cmpr_enable()`.

- If you remove every configured source channel, `ana_cmpr_enable()` fails with `ESP_ERR_INVALID_STATE`.

- `ana_cmpr_set_src_chan_cross_type()` is only runtime-configurable on ESP32-H2.

## Runtime Observation and Timing Helpers

The following APIs are general runtime helpers and are not tied to multi-source configuration:

- `ana_cmpr_trigger_scan()` forces one software-triggered scan sequence (on targets that support software-triggered scan).

- `ana_cmpr_get_output_level()` reads the latest sampled comparator output of a source channel (on targets that support output-level reporting).

- `ana_cmpr_get_clock_resolution_hz()` returns PAD_COMP_CLK resolution in Hz.

- `ana_cmpr_get_capture_timestamps()` reads current/previous crossing timestamps (on capture-capable targets).

Use `ana_cmpr_get_output_level()` when you need current digital comparison state from software. Use `ana_cmpr_get_clock_resolution_hz()` when converting PAD_COMP_CLK ticks (for example, capture timestamps) to time units. Use `ana_cmpr_trigger_scan()` when you want deterministic software-controlled refresh timing; it requires `ana_cmpr_enable()` and returns `ESP_ERR_INVALID_STATE` in init state.

To get meaningful capture timestamps, enable the capture timer when creating the unit:

    ana_cmpr_config_t config = {
        .unit = 0,                            // Use a valid unit index for your target
        .clk_src = ANA_CMPR_CLK_SRC_DEFAULT,  // PAD_COMP_CLK source
        .ref_src = ANA_CMPR_REF_SRC_INTERNAL, // Reference mode used by your capture scenario
        .cross_type = ANA_CMPR_CROSS_ANY,     // Keep both crossing directions by default
        .src_chan0_gpio = 0,                  // Must match your board's source signal wiring
        .en_capture_timer = true,             // Required for capture timestamp APIs
    };

Then convert ticks to time with:

    uint32_t resolution_hz = 0;
    uint32_t current_ticks = 0;
    ESP_ERROR_CHECK(ana_cmpr_get_clock_resolution_hz(cmpr, &resolution_hz));
    ESP_ERROR_CHECK(ana_cmpr_get_capture_timestamps(cmpr, 0, &current_ticks, NULL));
    uint32_t time_us = (uint32_t)(((uint64_t)current_ticks * 1000000U) / resolution_hz);

## Practical Configuration Notes

### Choosing the Clock Source

The comparator clock affects sampling behavior. In most applications, use `ANA_CMPR_CLK_SRC_DEFAULT` unless you have a specific clocking requirement.

Note that the analog comparator clock source can be shared with other GPIO-extension style peripherals on some targets. If different peripherals request incompatible clock sources, initialization can fail.

### Choosing the Internal Reference Level

The internal reference is defined as a percentage of VDD, not as an arbitrary voltage in volts.

This is convenient when:

- the input signal naturally swings with the supply range

- you want a simple mid-supply or supply-relative threshold

This is less suitable when:

- you need a precise threshold independent of VDD variation

- the threshold must change continuously instead of in coarse steps

### Tuning Debounce

Debounce is one of the first parameters to tune on real hardware.

- Too little debounce: duplicate interrupts or unstable event behavior near the threshold

- Too much debounce: missed crossings on fast-changing signals

There is no single good value for every application. Start small and adjust based on observed signal behavior.

### Tuning Scan Timing

On scan-capable targets, scan timing and resampling should be chosen together:

- Reduce `poll_period_us` when you need quicker updates

- Increase `ana_cmpr_config_t::resample_limit` when you need better noise rejection

- Avoid choosing a scan rate that is much slower than the effective input dynamics you want to detect

## Operational Notes

### Enable and Disable Lifecycle

The comparator follows a simple lifecycle:

1. Create and configure it

2. Enable it

3. Run your application

4. Disable it before deleting it

Use `ana_cmpr_enable()` and `ana_cmpr_disable()` as a pair.

While enabled, only a limited set of runtime control functions are intended to be adjusted. Configuration functions such as source channel management and scan configuration must be done before enabling the unit.

### Power Management

When CONFIG_PM_ENABLE is enabled, sleep and clock changes can affect the comparator. The driver uses a power management lock internally when needed, so enabling the comparator can prevent light sleep while the unit is active.

If power consumption matters, structure your application so the comparator is only enabled when needed.

### IRAM Safe

If you need comparator interrupts to keep working while the cache is disabled, enable CONFIG_ANA_CMPR_ISR_CACHE_SAFE.

If you also need the runtime control functions to remain callable in that situation, enable CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM.

The following control APIs can be placed in IRAM:

- `ana_cmpr_set_internal_reference()`

- `ana_cmpr_set_debounce()`

- `ana_cmpr_set_src_chan_cross_type()`

- `ana_cmpr_trigger_scan()`

### Thread Safety

The driver is designed to be thread-safe for concurrent API calls on the same `ana_cmpr_handle_t`, by combining:

- A per-handle FSM (INIT/ENABLE/WAIT) with atomic state transitions to serialize incompatible operations

- Short critical sections to keep shared software state and hardware registers updated atomically

- Slot lifecycle protection for create/delete windows

The main lifecycle contract still applies: call `ana_cmpr_disable()` before `ana_cmpr_del_unit()`, and make sure no active dependent objects (for example ETM handles) remain when deleting the unit.

### Kconfig Options

The most relevant Kconfig options are:

- CONFIG_ANA_CMPR_ISR_CACHE_SAFE

    Keeps the default ISR path available when cache is disabled. Enable this if comparator interrupts must work in cache-off windows.

- CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM

    Places ISR-callable runtime control APIs in IRAM, so they remain callable when cache is disabled.

- CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG

    Enables driver debug logs for troubleshooting and bring-up. This increases binary size and log verbosity.

## Examples

- peripherals/analog_comparator/etm_periodic_scan shows how to use GPTimer and ETM to trigger periodic comparator scans and drive a monitor GPIO from comparator crossing events.

## API Reference

### Driver APIs

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

  Note

  Caller must ensure no active users remain before deleting the unit handle, including any ETM event/task handles created from this unit (delete them first via `esp_etm_del_event()` and `esp_etm_del_task()`).

  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 set to `ANA_CMPR_REF_SRC_INTERNAL`.

  Note

  This function is allowed to run within ISR context including interrupt 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 internal reference configuration success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

    - ESP_ERR_NOT_ALLOWED Set the reference voltage for external reference channel is not allowed

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 interrupt 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 debounce configuration success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

esp_err_t ana_cmpr_get_capture_timestamps(ana_cmpr_handle_t cmpr, int src_chan_id, uint32_t *current, uint32_t *previous)

  Get capture timestamps of a source channel.

  Note

  Returned timestamp values are measured in PAD_COMP_CLK cycles

  Note

  Convert ticks to time by first querying comparator clock resolution with `ana_cmpr_get_clock_resolution_hz()`. For example, `time_us = ticks * 1000000 / resolution_hz`.

  Parameters:

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

    - src_chan_id -- [in] The source channel index

    - current -- [out] Timestamp of the latest cross event, in PAD_COMP_CLK cycles. Can be NULL if not needed.

    - previous -- [out] Timestamp of the previous cross event, in PAD_COMP_CLK cycles. Can be NULL if not needed.

  Returns:

    - ESP_OK Get capture timestamps success

    - ESP_ERR_INVALID_ARG Both output pointers are NULL, or invalid channel id

    - ESP_ERR_NOT_SUPPORTED Hardware doesn't support capture timer

esp_err_t ana_cmpr_get_clock_resolution_hz(ana_cmpr_handle_t cmpr, uint32_t *resolution_hz)

  Get clock resolution of the analog comparator unit.

  Note

  Returned value is in Hz and corresponds to the PAD_COMP_CLK domain. This clock is shared by features like debounce filtering and capture timestamps.

  Parameters:

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

    - resolution_hz -- [out] Comparator clock resolution in Hz

  Returns:

    - ESP_OK Get comparator clock resolution success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

esp_err_t ana_cmpr_add_src_chan(ana_cmpr_handle_t cmpr, int src_chan_id, const ana_cmpr_src_chan_config_t *src_cfg)

  Add or update a source channel.

  Note

  This function can only be called when the comparator unit is in init (disabled) state

  Parameters:

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

    - src_chan_id -- [in] The source channel index

    - src_cfg -- [in] Source channel configuration

  Returns:

    - ESP_OK Add/update source channel success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters or invalid channel/GPIO configuration

    - ESP_ERR_INVALID_STATE The analog comparator is not in init state

    - ESP_ERR_NOT_SUPPORTED Source channel index is not supported by the current target

esp_err_t ana_cmpr_remove_src_chan(ana_cmpr_handle_t cmpr, int src_chan_id)

  Remove a source channel from scan and interrupt routing.

  Note

  This function can only be called when the comparator unit is in init (disabled) state

  Note

  This API is idempotent: removing an already-removed channel still returns ESP_OK

  Parameters:

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

    - src_chan_id -- [in] The source channel index

  Returns:

    - ESP_OK Remove source channel success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters or invalid channel id

    - ESP_ERR_INVALID_STATE The analog comparator is not in init state

    - ESP_ERR_NOT_SUPPORTED Source channel index is not supported by the current target

esp_err_t ana_cmpr_set_src_chan_cross_type(ana_cmpr_handle_t cmpr, int src_chan_id, ana_cmpr_cross_type_t cross_type)

  Set cross type for the given source channel.

  Note

  On targets with edge-type interrupt support, interrupt source selection is fixed when adding source channels, so runtime cross-type switching is not supported.

  Parameters:

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

    - src_chan_id -- [in] The source channel index

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

  Returns:

    - ESP_OK Set cross type configuration success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters or invalid channel/cross type

    - ESP_ERR_INVALID_STATE The target source channel isn't configured

    - ESP_ERR_NOT_SUPPORTED Runtime cross-type switching isn't supported by the current target

esp_err_t ana_cmpr_set_scan_config(ana_cmpr_handle_t cmpr, const ana_cmpr_scan_config_t *scan_cfg)

  Set scan configuration.

  Note

  This function can only be called when the comparator unit is in init (disabled) state

  Parameters:

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

    - scan_cfg -- [in] Scan configuration

  Returns:

    - ESP_OK Set scan configuration success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

    - ESP_ERR_INVALID_STATE The analog comparator is not in init state

    - ESP_ERR_NOT_SUPPORTED Scan configuration is not supported by current target

esp_err_t ana_cmpr_trigger_scan(ana_cmpr_handle_t cmpr)

  Trigger one analog comparator scan sequence.

  Parameters:

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

  Returns:

    - ESP_OK Trigger scan success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

    - ESP_ERR_INVALID_STATE Invalid unit state for triggering scan

    - ESP_ERR_NOT_SUPPORTED The hardware doesn't support software triggered scan

esp_err_t ana_cmpr_get_output_level(ana_cmpr_handle_t cmpr, int src_chan_id, bool *out_level)

  Get the output level of a source channel.

  Note

  The output level indicates whether the source voltage is higher than the reference voltage

  Note

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

  Parameters:

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

    - src_chan_id -- [in] The source channel index

    - out_level -- [out] The output level of the source channel

      - true: source voltage > reference voltage

      - false: source voltage < reference voltage

  Returns:

    - ESP_OK Get output level success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters or invalid channel id

    - ESP_ERR_NOT_SUPPORTED Hardware can't report the output level of the source channel or the source channel index is not supported by the current target

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_channel_gpio(ana_cmpr_handle_t cmpr, ana_cmpr_channel_type_t chan_type, int chan_id, gpio_num_t *gpio_num)

  Get the GPIO number of a configured analog comparator channel.

  Parameters:

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

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

    - chan_id -- [in] The source channel index when `chan_type` is `ANA_CMPR_SOURCE_CHAN`. Must be 0 when `chan_type` is `ANA_CMPR_EXT_REF_CHAN`

    - 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 channel type/channel id

    - ESP_ERR_INVALID_STATE The target channel is not configured

    - ESP_ERR_NOT_SUPPORTED The source channel index is not supported by the current target

    - ESP_ERR_NOT_FOUND The requested channel doesn't have a GPIO mapping, e.g. the reference source is internal

static inline esp_err_t ana_cmpr_set_cross_type(ana_cmpr_handle_t cmpr, ana_cmpr_cross_type_t cross_type)

  Set the cross type for the source channel 0 that can trigger the event.

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

  Note

  This is a legacy API that only applies to source channel 0

  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 cross type configuration success

    - ESP_ERR_INVALID_ARG NULL pointer of the parameters

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

  Get the fixed GPIO number of the analog comparator unit.

  Deprecated:

    Please use `ana_cmpr_get_channel_gpio()` instead to query the GPIO of the configured comparator instance

  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

  int unit

    Analog comparator unit ID, index from 0

  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`

  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)

  ana_cmpr_cross_type_t cross_type

    The crossing type of source channel 0, that can trigger interrupt

  gpio_num_t src_chan0_gpio

    The GPIO number of source channel 0 signal

  gpio_num_t ext_ref_gpio

    The GPIO number of external reference signal, only valid when `ref_src` is set to `ANA_CMPR_REF_SRC_EXTERNAL`

  uint8_t resample_limit

    Unit-wide consecutive sample count required to update channel status

  bool en_capture_timer

    Enable channel capture timer at unit creation.

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%

  ana_cmpr_ref_hys_t ref_hys_level

    Internal reference hysteresis level

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_src_chan_config_t

  Analog comparator source channel configuration.

  Public Members

  gpio_num_t gpio_num

    Source input GPIO

  ana_cmpr_cross_type_t cross_type

    Crossing type that can trigger events for this source channel

struct ana_cmpr_scan_config_t

  Analog comparator scan configuration.

  Public Members

  ana_cmpr_scan_mode_t scan_mode

    Channel scan mode

  uint32_t poll_period_us

    Channel switching wait time in microseconds

### Driver Types

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

  int src_chan_id

    The source channel index that triggers the interrupt, valid when the target supports multiple source channels

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

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

Was this page helpful?

- Thank you! We received your feedback.
- If you have any comments, fill in Espressif Documentation Feedback Form.

- We value your feedback.
- Let us know how we can improve this page by filling in Espressif Documentation Feedback Form.