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, and update_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, and update_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.

A fault asserts while PWM runs. CBC holds the output at the brake level while the fault is active and resumes at the next cycle boundary; OST stays latched until software recovery.

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));
Carrier modulation of a 50% duty base PWM

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_src selects 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_hz is the carrier frequency; select a value compatible with the isolation transformer, gate driver, switching loss budget, and target clock resolution.

  • duty_cycle accepts 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_us controls 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_modulate when the raw PWM needs a polarity change and invert_after_modulate when 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

  • components/esp_driver_mcpwm/include/driver/mcpwm_oper.h

  • 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_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_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 cbs structure 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

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

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

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


Was this page helpful?