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 theon_reachcallback. 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 enablesupdate_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
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_mcpwmcomponent. To declare that your component depends onesp_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 operatorconfig -- [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
cbsstructure 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.
-
int intr_priority
-
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
-
mcpwm_compare_event_cb_t on_reach