MCPWM Operator: Assemble an Output Stage
An operator is the container between a timer and its generators. It owns the comparators, generator actions, brake handling, dead-time routing, and carrier modulation. One timer can drive multiple operators in the same group, while an operator connects to exactly one timer.
If the timer is the clock source, the operator is the output-stage container. It lets several outputs share one time base while keeping protection, dead time, and carrier features grouped with the power stage they belong to.
Connect the building blocks
Create the operator in the same group as the timer, then connect them with mcpwm_operator_connect_timer(). The connection must exist before the generator can use timer events.
mcpwm_oper_handle_t oper = NULL;
mcpwm_operator_config_t oper_config = {
.group_id = 0,
.flags.update_gen_action_on_tez = true,
.flags.update_dead_time_on_tez = true,
};
ESP_ERROR_CHECK(mcpwm_new_operator(&oper_config, &oper));
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(oper, timer));
The operator configuration is small, but a few fields do not appear in the example:
group_id— the MCPWM group the operator is allocated from. It must match the timer's group, because an operator can only connect to a timer inside the same group.intr_priority— the interrupt priority used by the brake event callbacks. Not setting it (0) lets the driver choose a low priority; raise it when brake notifications must preempt other ISRs.
The flags choose when new generator actions and dead-time settings take effect. They are all off by default, so changes apply immediately — possibly in the middle of a PWM cycle:
update_gen_action_on_tez,update_gen_action_on_tep, andupdate_gen_action_on_sync— buffer generator action changes until the counter reaches zero, the peak, or a sync event.update_dead_time_on_tez,update_dead_time_on_tep, andupdate_dead_time_on_sync— buffer dead-time changes the same way; see dead time for the update-point rules.
For a running power stage, use the zero (tez), peak (tep), or sync update point to avoid partial cycles.
One timer, multiple operators
The same timer can drive several operators, each producing a different waveform. This is useful for multi-phase inverters or multiple motors running at the same frequency but with independent duty cycles.
The reverse is also important: one operator connects to exactly one timer, so all comparators and generators inside that operator inherently share the same time base. That is why in-phase, complementary, and paired outputs are easy to build there.
mcpwm_oper_handle_t oper_b = NULL;
mcpwm_operator_config_t oper_config_b = {
.group_id = 0,
.flags.update_gen_action_on_tez = true,
};
ESP_ERROR_CHECK(mcpwm_new_operator(&oper_config_b, &oper_b));
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(oper_b, timer));
// Create separate comparators and generators under oper_b.
Brake and safe output state
The operator turns a fault into a brake action. Arrange brake actions before starting PWM: this makes the reaction entirely hardware driven and avoids software latency in the fault path.
Recovery policy
CBC (cycle by cycle): brakes while the fault is active and recovers at the configured timer zero or peak. This suits a transient current limit.
OST (one shot): stays braked after the fault disappears. Software must explicitly recover it. Use it for an interlock or serious over-current condition.
For CBC, set cbc_recover_on_tez or cbc_recover_on_tep to choose the boundary at which a cleared fault releases the outputs. A boundary avoids restoring a switch in the middle of a PWM cycle.
Warning
Do not enable both cbc_recover_on_tez and cbc_recover_on_tep at the same time; choose the boundary that matches the waveform and gate-driver timing.
Fault connection
Connect the fault to the operator, then specify the state of every generator during that brake mode. This example drives the raw generator low in both timer directions for OST braking:
ESP_ERROR_CHECK(mcpwm_operator_set_brake_on_fault(oper,
&(mcpwm_brake_config_t) {
.fault = fault,
.brake_mode = MCPWM_OPER_BRAKE_MODE_OST,
}));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_brake_event(
generator, MCPWM_GEN_BRAKE_EVENT_ACTION(
MCPWM_TIMER_DIRECTION_UP, MCPWM_OPER_BRAKE_MODE_OST,
MCPWM_GEN_ACTION_LOW)));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_brake_event(
generator, MCPWM_GEN_BRAKE_EVENT_ACTION(
MCPWM_TIMER_DIRECTION_DOWN, MCPWM_OPER_BRAKE_MODE_OST,
MCPWM_GEN_ACTION_LOW)));
For a bridge, configure both generators with the same brake action. Confirm the electrical safe state at the gate driver; a logical low can be inverted by dead time, GPIO matrix, or external circuitry.
The distinction from a generator fault action is important: generator fault actions are best for a local immediate edge response, while operator brake defines the safe state, latch behavior, and recovery policy for the entire output stage. The primary protection path should usually use operator brake.
OST fault recovery
CBC recovers on its configured boundary after the fault goes inactive. For OST, remove and validate the root cause first, then call:
ESP_ERROR_CHECK(mcpwm_operator_recover_from_fault(oper, fault));
The call fails while the source is still active.
CBC brakes only while the fault is active and recovers at the next cycle boundary; OST stays latched until software recovery.
Brake event callbacks
The operator can report brake events through the on_brake_cbc and on_brake_ost callbacks. They run in ISR context; use them for notification, not blocking recovery.
mcpwm_operator_event_callbacks_t cbs = {
.on_brake_cbc = my_brake_cbc_cb,
.on_brake_ost = my_brake_ost_cb,
};
ESP_ERROR_CHECK(mcpwm_operator_register_event_callbacks(oper, &cbs, NULL));
Carrier modulation
Carrier modulation superimposes a high-frequency carrier on an operator's PWM output. It is commonly used with transformer-isolated gate-drive schemes: even a base PWM held at 100% duty then contains transitions that can cross the isolation barrier. Configure the base PWM first; carrier settings affect the operator's all generators.
Carrier configuration
mcpwm_carrier_config_t carrier = {
.clk_src = MCPWM_CARRIER_CLK_SRC_DEFAULT,
.frequency_hz = 100000,
.duty_cycle = 0.5f,
.first_pulse_duration_us = 20,
};
ESP_ERROR_CHECK(mcpwm_operator_apply_carrier(oper, &carrier));
A 100 kHz carrier gates a 50% duty base PWM. The first pulse is stretched to 20 us (two carrier periods), and no chopping occurs while the base PWM is low.
Carrier parameters
clk_srcselects the carrier clock source. It defaults to an internal PLL clock (e.g. PLL_F160M); some chips also expose RC_FAST or XTAL as alternatives. Different sources offer different resolution and power consumption. The default is fine for most applications; pick a different source only to avoid noise from a particular clock, when PLL precision is insufficient, or when power consumption matters.frequency_hzis the carrier frequency; select a value compatible with the isolation transformer, gate driver, switching loss budget, and target clock resolution.duty_cycleaccepts the hardware steps 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, or 0.875, rather than an arbitrary ratio.first_pulse_duration_uscontrols the first pulse after modulation begins. It must be nonzero and at least one carrier period. A longer first pulse can help establish current in an inductive isolation path, but must stay within the gate-drive system's limits.Use
invert_before_modulatewhen the raw PWM needs a polarity change andinvert_after_modulatewhen the modulated output needs one.
Pass NULL as the configuration to mcpwm_operator_apply_carrier() when carrier modulation is not needed.
API Reference
MCPWM Operator Driver Functions
Header File
This header file can be included with:
#include "driver/mcpwm_oper.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_operator(const mcpwm_operator_config_t *config, mcpwm_oper_handle_t *ret_oper)
Create MCPWM operator.
- Parameters:
config -- [in] MCPWM operator configuration
ret_oper -- [out] Returned MCPWM operator handle
- Returns:
ESP_OK: Create MCPWM operator successfully
ESP_ERR_INVALID_ARG: Create MCPWM operator failed because of invalid argument
ESP_ERR_NO_MEM: Create MCPWM operator failed because out of memory
ESP_ERR_NOT_FOUND: Create MCPWM operator failed because can't find free resource
ESP_FAIL: Create MCPWM operator failed because of other error
-
esp_err_t mcpwm_del_operator(mcpwm_oper_handle_t oper)
Delete MCPWM operator.
- Parameters:
oper -- [in] MCPWM operator, allocated by
mcpwm_new_operator()- Returns:
ESP_OK: Delete MCPWM operator successfully
ESP_ERR_INVALID_ARG: Delete MCPWM operator failed because of invalid argument
ESP_FAIL: Delete MCPWM operator failed because of other error
-
esp_err_t mcpwm_operator_connect_timer(mcpwm_oper_handle_t oper, mcpwm_timer_handle_t timer)
Connect MCPWM operator and timer, so that the operator can be driven by the timer.
- Parameters:
oper -- [in] MCPWM operator handle, allocated by
mcpwm_new_operator()timer -- [in] MCPWM timer handle, allocated by
mcpwm_new_timer()
- Returns:
ESP_OK: Connect MCPWM operator and timer successfully
ESP_ERR_INVALID_ARG: Connect MCPWM operator and timer failed because of invalid argument
ESP_FAIL: Connect MCPWM operator and timer failed because of other error
-
esp_err_t mcpwm_operator_set_brake_on_fault(mcpwm_oper_handle_t oper, const mcpwm_brake_config_t *config)
Set brake method for MCPWM operator.
- Parameters:
oper -- [in] MCPWM operator, allocated by
mcpwm_new_operator()config -- [in] MCPWM brake configuration
- Returns:
ESP_OK: Set trip for operator successfully
ESP_ERR_INVALID_ARG: Set trip for operator failed because of invalid argument
ESP_FAIL: Set trip for operator failed because of other error
-
esp_err_t mcpwm_operator_recover_from_fault(mcpwm_oper_handle_t oper, mcpwm_fault_handle_t fault)
Try to make the operator recover from fault.
Note
To recover from fault or escape from trip, you make sure the fault signal has disappeared already. Otherwise the recovery can't succeed.
- Parameters:
oper -- [in] MCPWM operator, allocated by
mcpwm_new_operator()fault -- [in] MCPWM fault handle
- Returns:
ESP_OK: Recover from fault successfully
ESP_ERR_INVALID_ARG: Recover from fault failed because of invalid argument
ESP_ERR_INVALID_STATE: Recover from fault failed because the fault source is still active
ESP_FAIL: Recover from fault failed because of other error
-
esp_err_t mcpwm_operator_register_event_callbacks(mcpwm_oper_handle_t oper, const mcpwm_operator_event_callbacks_t *cbs, void *user_data)
Set event callbacks for MCPWM operator.
Note
User can deregister a previously registered callback by calling this function and setting the callback member in the
cbsstructure to NULL.- Parameters:
oper -- [in] MCPWM operator handle, allocated by
mcpwm_new_operator()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_operator_apply_carrier(mcpwm_oper_handle_t oper, const mcpwm_carrier_config_t *config)
Apply carrier feature for MCPWM operator.
- Parameters:
oper -- [in] MCPWM operator, allocated by
mcpwm_new_operator()config -- [in] MCPWM carrier specific configuration
- Returns:
ESP_OK: Set carrier for operator successfully
ESP_ERR_INVALID_ARG: Set carrier for operator failed because of invalid argument
ESP_FAIL: Set carrier for operator failed because of other error
Structures
-
struct mcpwm_operator_config_t
MCPWM operator configuration.
Public Members
-
int group_id
Specify from which group to allocate the MCPWM operator
-
int intr_priority
MCPWM operator interrupt priority, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3)
-
struct mcpwm_operator_config_t::extra_mcpwm_operator_flags flags
Extra configuration flags for operator
-
struct extra_mcpwm_operator_flags
Extra configuration flags for operator.
Public Members
-
uint32_t update_gen_action_on_tez
Whether to update generator action when timer counts to zero
-
uint32_t update_gen_action_on_tep
Whether to update generator action when timer counts to peak
-
uint32_t update_gen_action_on_sync
Whether to update generator action on sync event
-
uint32_t update_dead_time_on_tez
Whether to update dead time when timer counts to zero
-
uint32_t update_dead_time_on_tep
Whether to update dead time when timer counts to peak
-
uint32_t update_dead_time_on_sync
Whether to update dead time on sync event
-
uint32_t update_gen_action_on_tez
-
int group_id
-
struct mcpwm_brake_config_t
MCPWM brake configuration structure.
Public Members
-
mcpwm_fault_handle_t fault
Which fault causes the operator to brake
-
mcpwm_operator_brake_mode_t brake_mode
Brake mode
-
uint32_t cbc_recover_on_tez
Recovery CBC brake state on tez event
-
uint32_t cbc_recover_on_tep
Recovery CBC brake state on tep event
-
struct mcpwm_brake_config_t flags
Extra flags for brake configuration
-
mcpwm_fault_handle_t fault
-
struct mcpwm_operator_event_callbacks_t
Group of supported MCPWM operator event callbacks.
Note
The callbacks are all running under ISR environment
Public Members
-
mcpwm_brake_event_cb_t on_brake_cbc
callback function when mcpwm operator brakes in CBC
-
mcpwm_brake_event_cb_t on_brake_ost
callback function when mcpwm operator brakes in OST
-
mcpwm_brake_event_cb_t on_brake_cbc
-
struct mcpwm_carrier_config_t
MCPWM carrier configuration structure.
Public Members
-
mcpwm_carrier_clock_source_t clk_src
MCPWM carrier clock source
-
uint32_t frequency_hz
Carrier frequency in Hz
-
uint32_t first_pulse_duration_us
The duration of the first PWM pulse, in us
-
float duty_cycle
Carrier duty cycle
-
uint32_t invert_before_modulate
Invert the raw signal
-
uint32_t invert_after_modulate
Invert the modulated signal
-
struct mcpwm_carrier_config_t flags
Extra flags for carrier configuration
-
mcpwm_carrier_clock_source_t clk_src