# MCPWM Comparator: Turn a Ratio into an Edge

A comparator emits an event when the timer count reaches `cmp_ticks`. A generator converts that event into a GPIO transition. In the usual up-counting PWM arrangement, the comparator value is the high-time in ticks.

In practice, a comparator is how you turn "I want the edge earlier, later, narrower, or wider" into hardware timing. Runtime duty control is usually nothing more than changing the comparator threshold.

## Set a 30% duty cycle

Create a comparator from an existing operator, then set its threshold. With the 50-tick timer from the timer page, a value of 15 represents 30% duty. The waveform below shows the compare event at tick 15 — the generator can use this to end the high pulse.

Timer counts up; the comparator fires at tick 15. The generator turns this into a falling edge.

    mcpwm_cmpr_handle_t comparator = NULL;
    mcpwm_comparator_config_t comparator_config = {
        .flags.update_cmp_on_tez = true, // Change duty only at cycle boundary
    };
    ESP_ERROR_CHECK(mcpwm_new_comparator(oper, &comparator_config, &comparator));
    ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparator, 15));

The comparator configuration has only one field besides the flags:

- `intr_priority` — the interrupt priority used by the `on_reach` callback. Not setting it (`0`) lets the driver choose a low priority; raise it when the callback must preempt other ISRs.

- `flags` — the update points explained below. The example enables `update_cmp_on_tez`, which is the usual choice for changing duty at the cycle boundary.

For a runtime duty request in percent, calculate `period_ticks * percent / 100`. Keep the result within the timer period.

This is why duty updates normally change the comparator rather than the generator actions: actions describe the waveform rule, while the comparator is the runtime edge position.

## Why buffer the update?

Updating a comparator immediately can move an edge in the middle of the active cycle. `update_cmp_on_tez` buffers it until the counter reaches zero, `update_cmp_on_tep` until it reaches the peak, and `update_cmp_on_sync` until a sync event. In up-counting or down-counting mode the peak coincides with the cycle boundary, so `tez` and `tep` select almost the same update point; only in up-down mode does the peak sit at the midpoint of the cycle, making `tez` and `tep` two distinct update points. The buffered choice is usually the right one for motors and power conversion.

## Two comparators for pulse placement

A single comparator gives one edge per cycle. With two comparators in the same operator, you can place a pulse anywhere inside the period — one comparator opens the pulse and the other closes it. This is useful for sampling windows, trigger signals, or asymmetric dead-time compensation.

That pattern appears often in motor control, for example when an ADC sample window should sit away from switching noise, or when an external device needs a timing pulse that is not tied to the PWM boundary.

    mcpwm_cmpr_handle_t cmp_a, cmp_b;
    mcpwm_new_comparator(oper, &comparator_config, &cmp_a);
    mcpwm_new_comparator(oper, &comparator_config, &cmp_b);
    mcpwm_comparator_set_compare_value(cmp_a, 10);
    mcpwm_comparator_set_compare_value(cmp_b, 30);

## Use compare events as a timing marker

The `on_reach` callback fires when the compare value is reached. This is useful when software must observe a precise point in the PWM cycle. Register it before starting time-critical work. The callback runs in ISR context, so keep it short.

    static bool IRAM_ATTR on_compare(mcpwm_cmpr_handle_t cmpr,
                                     const mcpwm_compare_event_data_t *edata,
                                     void *user_ctx)
    {
        // Signal a task or trigger only ISR-safe work.
        return false;
    }

    mcpwm_comparator_event_callbacks_t callbacks = { .on_reach = on_compare };
    ESP_ERROR_CHECK(mcpwm_comparator_register_event_callbacks(comparator,
                                                              &callbacks, NULL));

## Comparator kinds

The operator comparator, created with `mcpwm_new_comparator()`, drives the generators so it can shape the PWM output.

The event comparator, created with `mcpwm_new_event_comparator()`. Its compare event only reaches other peripherals through ETM; it never drives a generator and does not affect the PWM output.

Note

The name is the trap: the operator comparator can also produce ETM events, so the event comparator is not the only way to link MCPWM to ETM. The event comparator exists to supplement the operator comparator, not to replace it. An event comparator consumes none of the operator-comparator slots and never moves a PWM edge, which makes it the flexible choice when you need an extra compare point purely as a timing marker — for example, to find a sampling window for an ADC trigger that must not disturb the PWM waveform.

Both types accept the same compare value and ETM event setup:

    mcpwm_event_comparator_config_t evt_cmp_cfg = {};
    mcpwm_cmpr_handle_t evt_cmpr = NULL;
    ESP_ERROR_CHECK(mcpwm_new_event_comparator(oper, &evt_cmp_cfg, &evt_cmpr));
    ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(evt_cmpr, 25));

    esp_etm_event_handle_t evt = NULL;
    ESP_ERROR_CHECK(mcpwm_comparator_new_etm_event(evt_cmpr,
        &(mcpwm_cmpr_etm_event_config_t){ .event_type = MCPWM_CMPR_ETM_EVENT_EQUAL },
        &evt));

## API Reference

### MCPWM Comparator Driver Functions

#### Header File

- components/esp_driver_mcpwm/include/driver/mcpwm_cmpr.h

- This header file can be included with:

  >     #include "driver/mcpwm_cmpr.h"

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

  >     REQUIRES esp_driver_mcpwm

  > or

  >     PRIV_REQUIRES esp_driver_mcpwm

#### Functions

esp_err_t mcpwm_new_comparator(mcpwm_oper_handle_t oper, const mcpwm_comparator_config_t *config, mcpwm_cmpr_handle_t *ret_cmpr)

  Create MCPWM comparator.

  Parameters:

    - oper -- [in] MCPWM operator, allocated by `mcpwm_new_operator()`, the new comparator will be allocated from this operator

    - config -- [in] MCPWM comparator configuration

    - ret_cmpr -- [out] Returned MCPWM comparator

  Returns:

    - ESP_OK: Create MCPWM comparator successfully

    - ESP_ERR_INVALID_ARG: Create MCPWM comparator failed because of invalid argument

    - ESP_ERR_NO_MEM: Create MCPWM comparator failed because out of memory

    - ESP_ERR_NOT_FOUND: Create MCPWM comparator failed because can't find free resource

    - ESP_FAIL: Create MCPWM comparator failed because of other error

esp_err_t mcpwm_del_comparator(mcpwm_cmpr_handle_t cmpr)

  Delete MCPWM comparator.

  Parameters:

    cmpr -- [in] MCPWM comparator handle, allocated by `mcpwm_new_comparator()`

  Returns:

    - ESP_OK: Delete MCPWM comparator successfully

    - ESP_ERR_INVALID_ARG: Delete MCPWM comparator failed because of invalid argument

    - ESP_FAIL: Delete MCPWM comparator failed because of other error

esp_err_t mcpwm_new_event_comparator(mcpwm_oper_handle_t oper, const mcpwm_event_comparator_config_t *config, mcpwm_cmpr_handle_t *ret_cmpr)

  Create MCPWM event comparator.

  Parameters:

    - oper -- [in] MCPWM operator, allocated by `mcpwm_new_operator()`, the new event comparator will be allocated from this operator

    - config -- [in] MCPWM comparator configuration

    - ret_cmpr -- [out] Returned MCPWM event comparator

  Returns:

    - ESP_OK: Create MCPWM event comparator successfully

    - ESP_ERR_INVALID_ARG: Create MCPWM event comparator failed because of invalid argument

    - ESP_ERR_NO_MEM: Create MCPWM event comparator failed because out of memory

    - ESP_ERR_NOT_FOUND: Create MCPWM event comparator failed because can't find free resource

    - ESP_FAIL: Create MCPWM event comparator failed because of other error

esp_err_t mcpwm_comparator_register_event_callbacks(mcpwm_cmpr_handle_t cmpr, const mcpwm_comparator_event_callbacks_t *cbs, void *user_data)

  Set event callbacks for MCPWM comparator.

  Note

  User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.

  Parameters:

    - cmpr -- [in] MCPWM comparator handle, allocated by `mcpwm_new_comparator()`

    - cbs -- [in] Group of callback functions

    - user_data -- [in] User data, which will be passed to callback functions directly

  Returns:

    - ESP_OK: Set event callbacks successfully

    - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument

    - ESP_FAIL: Set event callbacks failed because of other error

esp_err_t mcpwm_comparator_set_compare_value(mcpwm_cmpr_handle_t cmpr, uint32_t cmp_ticks)

  Set MCPWM comparator's compare value.

  Parameters:

    - cmpr -- [in] MCPWM comparator handle, allocated by `mcpwm_new_comparator()`

    - cmp_ticks -- [in] The new compare value

  Returns:

    - ESP_OK: Set MCPWM compare value successfully

    - ESP_ERR_INVALID_ARG: Set MCPWM compare value failed because of invalid argument (e.g. the cmp_ticks is out of range)

    - ESP_ERR_INVALID_STATE: Set MCPWM compare value failed because the operator doesn't have a timer connected

    - ESP_FAIL: Set MCPWM compare value failed because of other error

#### Structures

struct mcpwm_comparator_config_t

  MCPWM comparator configuration.

  Public Members

  int intr_priority

    MCPWM comparator interrupt priority, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3)

  struct mcpwm_comparator_config_t::extra_mcpwm_comparator_flags flags

    Extra configuration flags for comparator

  struct extra_mcpwm_comparator_flags

    Extra configuration flags for comparator.

    Public Members

    uint32_t update_cmp_on_tez

      Whether to update compare value when timer count equals to zero (tez)

    uint32_t update_cmp_on_tep

      Whether to update compare value when timer count equals to peak (tep)

    uint32_t update_cmp_on_sync

      Whether to update compare value on sync event

struct mcpwm_event_comparator_config_t

  MCPWM event comparator configuration.

struct mcpwm_comparator_event_callbacks_t

  Group of supported MCPWM compare event callbacks.

  Note

  The callbacks are all running under ISR environment

  Public Members

  mcpwm_compare_event_cb_t on_reach

    ISR callback function which would be invoked when counter reaches compare value

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.