# MCPWM 定时器：设定频率

定时器为与其操作器相连的每一路 PWM 提供时间基准。它以 `resolution_hz` 的频率计数，并在达到 `period_ticks` 时回绕。先选择分辨率——它决定了边沿放置的最小步长——再选择目标频率对应的周期。

无论是舵机、调速还是逆变器，定时器都回答两个最基本的问题："一个 Tick 有多细？" 和 "一个 PWM 周期有多长？"。后续比较器和生成器都只是在这个时间基准上放置边沿。

## 构建 20 kHz 时间基准

对于向上计数模式， `period_ticks = resolution_hz / frequency_hz` 。以下配置的 Tick 为 1 MHz（每 Tick 1 微秒），周期为 50 Tick，频率即为 20 kHz。下图展示了计数器从 0 上升到 50 然后复位的过程 —— `TEZ` （定时器归零事件）和 `TEP` （定时器峰值事件）是生成器使用的两个边界。

向上计数：计数器形成锯齿波，从 0 上升到 50，TEZ 在归零时触发，TEP 在峰值时触发。

    mcpwm_timer_handle_t timer = NULL;
    mcpwm_timer_config_t timer_config = {
        .group_id = 0,
        .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
        .resolution_hz = 1000000,
        .period_ticks = 50,
        .count_mode = MCPWM_TIMER_COUNT_MODE_UP,
    };
    ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config, &timer));

示例代码只覆盖了最核心的配置，但 `mcpwm_timer_config_t` 中还有一些未出现的字段，在特定场景下同样重要：

- `group_id` — 定时器从哪个 MCPWM 组分配。不同芯片会提供不同数量的组，每个组包含一组共享时钟分频器的定时器、操作器、比较器和生成器。 `0` 表示第一个组，大多数设计用它就够了。

- `clk_src` — 定时器的时钟源。`MCPWM_TIMER_CLK_SRC_DEFAULT` 选择 PLL 时钟，适合绝大多数应用。部分芯片还提供其他时钟源，可在 PLL 被关闭（例如浅睡眠）时显式指定，让定时器继续计数。

- `resolution_hz` — 计数器的 Tick 频率。一个 Tick 持续 `1 / resolution_hz` 秒，1 MHz 即每 Tick 1 微秒。它决定了比较器能放置的边沿最细粒度。

- `period_ticks` — 一个完整 PWM 周期包含的 Tick 数。频率为 `resolution_hz / period_ticks`。

- `count_mode` — 计数器是只向上计数（边沿对齐 PWM），还是先上后下（中心对齐 PWM）。两种计数形态见 计数模式与波形；硬件还支持向下计数。

- `intr_priority` — 定时器回调使用的中断优先级。不设置（`0`）时由驱动选择较低优先级；当回调需要抢占其他中断时（例如对时序敏感的电机控制），可适当提高。

示例没有设置 `flags`，因此这些开关都处于关闭状态——这也是安全的默认值。其中两个值得了解：

- `update_period_on_empty` 和 `update_period_on_sync` — 默认关闭，因此 `mcpwm_timer_set_period()` 会立即生效。打开后可把频率切换推迟到安全边界，见 频率更新。

- `allow_pd` — 允许在睡眠时关闭 MCPWM 电源域。驱动会在睡眠前后备份并恢复定时器寄存器，从而省电，代价是额外占用 RAM。

在完成操作器、比较器和生成器的配置后，再启用并启动定时器：

    ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
    ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));

`mcpwm_timer_enable()` 启用定时器运行所需的系统服务：使能定时器中断，并在启用电源管理时持有该组电源管理锁，避免时钟变频干扰 PWM 时序。`mcpwm_timer_start_stop()` 则负责启动和停止计数。删除定时器前，先调用 `mcpwm_timer_disable()` 恢复原状，再调用 `mcpwm_del_timer()`。

`mcpwm_timer_start_stop()` 的第三个参数选择停止行为：

- `MCPWM_TIMER_START_NO_STOP` — 持续运行，直到显式停止。

- `MCPWM_TIMER_START_STOP_EMPTY` — 下次计数到零（TEZ）时自动停止。适用于单次或需要完整周期后再停止的同步启动。

- `MCPWM_TIMER_START_STOP_FULL` — 下次计数到峰值（TEP）时自动停止。适用于单个完整周期后停止。

## 计数模式与波形

向上计数 模式下，计数器从 0 计数到 `period_ticks` 然后复位。波形为锯齿波，PWM 边沿对齐在周期的一侧——这称为 边沿对齐 PWM。

向上-向下计数 模式下，计数器先向上到 `period_ticks / 2`，再向下回 0。波形为三角波，PWM 边沿围绕周期中心对称 —— 中心对齐 PWM。中心对齐 PWM 因谐波失真更小，常用于电机控制。

向上-向下计数：计数器形成三角波，上升到 25（50 的一半），再下降回 0。

两种模式的频率均为 `resolution_hz / period_ticks`。选择足够高的分辨率以满足所需的占空比精度，再选择周期以达到目标频率。

重要

`period_ticks` 表示完整 PWM 周期的总 Tick 数，而不是所有模式下都表示计数器峰值。

- 在 `MCPWM_TIMER_COUNT_MODE_UP` 中，计数器范围是 `0 -> period_ticks`。

- 在 `MCPWM_TIMER_COUNT_MODE_UP_DOWN` 中，硬件峰值是 `period_ticks / 2`，完整周期是 `0 -> peak -> 0`。

例如 `resolution_hz` = 1 MHz、`period_ticks` = 50 时：向上计数模式为 `0 -> 50`，向上-向下模式为 `0 -> 25 -> 0`。两者完整周期都是 50 微秒，因此频率都为 20 kHz，只是边沿分布不同。

## 频率更新

默认情况下，`mcpwm_timer_set_period()` 立即生效，可能截断当前周期并产生不完整的脉冲。设置 `update_period_on_empty` 可在计数归零时更新，设置 `update_period_on_sync` 则在同步事件时更新。若需保持占空比不变，应同时按比例更新比较值：

    // 周期由 50 改为 100，同时保持 40% 占空比
    ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparator, 40));
    ESP_ERROR_CHECK(mcpwm_timer_set_period(timer, 100));

对大多数实时调参场景，优先修改比较器以改变占空比，只有在确实需要改 PWM 频率时才修改定时器周期。电机和电源应用通常还应配合 `update_period_on_empty` 或同步更新，避免在周期中间切换参数。

## 定时器事件回调

定时器可在达到峰值（`on_full`）、归零（`on_empty`）或停止（`on_stop`）时通知应用。必须在启用定时器前注册回调。回调在 ISR 上下文执行，不能阻塞、分配内存或调用普通 FreeRTOS API，应使用 `...FromISR` 变体。

备注

定时器和捕获定时器可能与同组其他对象共享分频器。若同一组里需要多种分辨率，请按请求分辨率单调顺序创建对象，避免分频冲突。详细规则见 高级主题。

    static bool IRAM_ATTR on_timer_empty(mcpwm_timer_handle_t timer,
                                         const mcpwm_timer_event_data_t *edata,
                                         void *user_ctx)
    {
        BaseType_t high_task_woken = pdFALSE;
        vTaskNotifyGiveFromISR((TaskHandle_t)user_ctx, &high_task_woken);
        return high_task_woken == pdTRUE;
    }

    mcpwm_timer_event_callbacks_t cbs = { .on_empty = on_timer_empty };
    ESP_ERROR_CHECK(mcpwm_timer_register_event_callbacks(timer, &cbs,
                                                          xTaskGetCurrentTaskHandle()));

如何在同步边沿将定时器加载到指定相位，见 同步。

## API 参考

### MCPWM 定时器驱动函数

#### Header File

- components/esp_driver_mcpwm/include/driver/mcpwm_timer.h

- This header file can be included with:

  >     #include "driver/mcpwm_timer.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_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle_t *ret_timer)

  Create MCPWM timer.

  参数:

    - config -- [in] MCPWM timer configuration

    - ret_timer -- [out] Returned MCPWM timer handle

  返回:

    - ESP_OK: Create MCPWM timer successfully

    - ESP_ERR_INVALID_ARG: Create MCPWM timer failed because of invalid argument

    - ESP_ERR_NO_MEM: Create MCPWM timer failed because out of memory

    - ESP_ERR_NOT_FOUND: Create MCPWM timer failed because all hardware timers are used up and no more free one

    - ESP_FAIL: Create MCPWM timer failed because of other error

esp_err_t mcpwm_del_timer(mcpwm_timer_handle_t timer)

  Delete MCPWM timer.

  参数:

    timer -- [in] MCPWM timer handle, allocated by `mcpwm_new_timer()`

  返回:

    - ESP_OK: Delete MCPWM timer successfully

    - ESP_ERR_INVALID_ARG: Delete MCPWM timer failed because of invalid argument

    - ESP_ERR_INVALID_STATE: Delete MCPWM timer failed because timer is not in init state

    - ESP_FAIL: Delete MCPWM timer failed because of other error

esp_err_t mcpwm_timer_set_period(mcpwm_timer_handle_t timer, uint32_t period_ticks)

  Set a new period for MCPWM timer.

  备注

  If `mcpwm_timer_config_t::update_period_on_empty` and `mcpwm_timer_config_t::update_period_on_sync` are not set, the new period will take effect immediately. Otherwise, the new period will take effect when timer counts to zero or on sync event.

  备注

  You may need to use `mcpwm_comparator_set_compare_value` to set a new compare value for MCPWM comparator in order to keep the same PWM duty cycle.

  参数:

    - timer -- [in] MCPWM timer handle, allocated by `mcpwm_new_timer`

    - period_ticks -- [in] New period in count ticks

  返回:

    - ESP_OK: Set new period for MCPWM timer successfully

    - ESP_ERR_INVALID_ARG: Set new period for MCPWM timer failed because of invalid argument

    - ESP_FAIL: Set new period for MCPWM timer failed because of other error

esp_err_t mcpwm_timer_enable(mcpwm_timer_handle_t timer)

  Enable MCPWM timer.

  参数:

    timer -- [in] MCPWM timer handle, allocated by `mcpwm_new_timer()`

  返回:

    - ESP_OK: Enable MCPWM timer successfully

    - ESP_ERR_INVALID_ARG: Enable MCPWM timer failed because of invalid argument

    - ESP_ERR_INVALID_STATE: Enable MCPWM timer failed because timer is enabled already

    - ESP_FAIL: Enable MCPWM timer failed because of other error

esp_err_t mcpwm_timer_disable(mcpwm_timer_handle_t timer)

  Disable MCPWM timer.

  参数:

    timer -- [in] MCPWM timer handle, allocated by `mcpwm_new_timer()`

  返回:

    - ESP_OK: Disable MCPWM timer successfully

    - ESP_ERR_INVALID_ARG: Disable MCPWM timer failed because of invalid argument

    - ESP_ERR_INVALID_STATE: Disable MCPWM timer failed because timer is disabled already

    - ESP_FAIL: Disable MCPWM timer failed because of other error

esp_err_t mcpwm_timer_start_stop(mcpwm_timer_handle_t timer, mcpwm_timer_start_stop_cmd_t command)

  Send specific start/stop commands to MCPWM timer.

  参数:

    - timer -- [in] MCPWM timer handle, allocated by `mcpwm_new_timer()`

    - command -- [in] Supported command list for MCPWM timer

  返回:

    - ESP_OK: Start or stop MCPWM timer successfully

    - ESP_ERR_INVALID_ARG: Start or stop MCPWM timer failed because of invalid argument

    - ESP_ERR_INVALID_STATE: Start or stop MCPWM timer failed because timer is not enabled

    - ESP_FAIL: Start or stop MCPWM timer failed because of other error

esp_err_t mcpwm_timer_register_event_callbacks(mcpwm_timer_handle_t timer, const mcpwm_timer_event_callbacks_t *cbs, void *user_data)

  Set event callbacks for MCPWM timer.

  备注

  The first call to this function needs to be before the call to `mcpwm_timer_enable`

  备注

  User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.

  参数:

    - timer -- [in] MCPWM timer handle, allocated by `mcpwm_new_timer()`

    - cbs -- [in] Group of callback functions

    - user_data -- [in] User data, which will be passed to callback functions directly

  返回:

    - ESP_OK: Set event callbacks successfully

    - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument

    - ESP_ERR_INVALID_STATE: Set event callbacks failed because timer is not in init state

    - ESP_FAIL: Set event callbacks failed because of other error

esp_err_t mcpwm_timer_set_phase_on_sync(mcpwm_timer_handle_t timer, const mcpwm_timer_sync_phase_config_t *config)

  Set sync phase for MCPWM timer.

  参数:

    - timer -- [in] MCPWM timer handle, allocated by `mcpwm_new_timer()`

    - config -- [in] MCPWM timer sync phase configuration

  返回:

    - ESP_OK: Set sync phase for MCPWM timer successfully

    - ESP_ERR_INVALID_ARG: Set sync phase for MCPWM timer failed because of invalid argument

    - ESP_FAIL: Set sync phase for MCPWM timer failed because of other error

#### Structures

struct mcpwm_timer_event_callbacks_t

  Group of supported MCPWM timer event callbacks.

  备注

  The callbacks are all running under ISR environment

  Public Members

  mcpwm_timer_event_cb_t on_full

    callback function when MCPWM timer counts to peak value

  mcpwm_timer_event_cb_t on_empty

    callback function when MCPWM timer counts to zero

  mcpwm_timer_event_cb_t on_stop

    callback function when MCPWM timer stops

struct mcpwm_timer_config_t

  MCPWM timer configuration.

  Public Members

  int group_id

    Specify from which group to allocate the MCPWM timer

  mcpwm_timer_clock_source_t clk_src

    MCPWM timer clock source

  uint32_t resolution_hz

    Counter resolution in Hz The step size of each count tick equals to (1 / resolution_hz) seconds

  mcpwm_timer_count_mode_t count_mode

    Count mode

  uint32_t period_ticks

    Number of count ticks within a period. For up-down mode, the timer peak value is half of the period_ticks

  int intr_priority

    MCPWM timer interrupt priority, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3)

  struct mcpwm_timer_config_t::extra_mcpwm_timer_flags flags

    Extra configuration flags for timer

  struct extra_mcpwm_timer_flags

    Extra configuration flags for MCPWM timer.

    Public Members

    uint32_t update_period_on_empty

      Whether to update period when timer counts to zero

    uint32_t update_period_on_sync

      Whether to update period on sync event

    uint32_t allow_pd

      Set to allow power down. When this flag set, the driver will backup/restore the MCPWM registers before/after entering/exist sleep mode. By this approach, the system can power off MCPWM's power domain. This can save power, but at the expense of more RAM being consumed.

struct mcpwm_timer_sync_phase_config_t

  MCPWM Timer sync phase configuration.

  Public Members

  mcpwm_sync_handle_t sync_src

    The sync event source. Set to NULL will disable the timer being synced by others

  uint32_t count_value

    The count value that should lock to upon sync event

  mcpwm_timer_direction_t direction

    The count direction that should lock to upon sync event

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。