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.

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?