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

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_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?

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