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

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