MCPWM 同步:对齐 PWM 相位

为什么需要同步

每个 MCPWM 定时器是独立的硬件计数器。当你调用 mcpwm_timer_start() 启动两个定时器时,CPU 会依次发出两条写指令——第二个定时器比第一个晚几十个 CPU 周期才启动。即使两者的周期配置完全相同,它们的计数器在周期中的位置也是不同的,PWM 输出的相位关系无法预测。

同步通过在同步边沿到达时给**正在运行**的定时器加载指定的计数值和方向来解决这个问题。定时器必须已经在运行;同步不会启动或停止定时器。它是在运行时修正相位的一种机制。

如果同步边沿在每个周期都到达(例如来自 TEZ 处的定时器同步源),那么修正每周期重复一次,相位关系可以无限期保持。这就是典型的用法:一个定时器作为参考,其他定时器在每个周期都重新对齐到它。

MCPWM 提供三种同步源。所有源都产生 mcpwm_sync_handle_t 类型的句柄,且任何源都可以供给同组内的任意定时器。

GPIO 同步源

GPIO 同步源对外部引脚上的边沿做出反应——当外部控制器、传感器或编码器提供周期性参考信号时非常有用。

mcpwm_sync_handle_t sync = NULL;
ESP_ERROR_CHECK(mcpwm_new_gpio_sync_src(
    &(mcpwm_gpio_sync_src_config_t) {
        .group_id = 0,
        .gpio_num = 5,
        .flags.active_neg = false,
    }, &sync));

GPIO 同步源配置很简单:

  • group_id — 同步源所属的 MCPWM 组。必须与所有接收该同步的定时器所在组一致。

  • gpio_num — 承载同步信号的 GPIO。

  • active_neg — 默认上升沿为有效边沿;设置后改为下降沿有效。

软件同步源

软件同步源由应用代码按需产生同步边沿。它没有配置字段;创建后即可在需要时激活。

mcpwm_sync_handle_t soft_sync = NULL;
ESP_ERROR_CHECK(mcpwm_new_soft_sync_src(NULL, &soft_sync));

// 后续当应用决定同步时:
ESP_ERROR_CHECK(mcpwm_soft_sync_activate(soft_sync));

备注

必须先通过 mcpwm_timer_set_phase_on_sync()mcpwm_capture_timer_set_phase_on_sync() 将软件同步源绑定到定时器,再调用激活。驱动在创建时不会分配定时器;在绑定前调用 mcpwm_soft_sync_activate() 属于未定义行为。

这在定时器已经在运行、应用需要触发一次性的相位修正时有用——例如故障恢复后,或开始新的控制周期之前。由于软件同步是一次性的,如果后续没有更多同步边沿到来,相位关系会随时间漂移。如需持续锁相,应使用周期性源(GPIO 或定时器同步源)。

定时器同步源

定时器同步源在定时器到达指定事件时产生同步边沿——例如每次定时器计到零(TEZ)。这可以让一个定时器作为其他定时器的周期性参考,每周期都保持相位锁定。

mcpwm_sync_handle_t timer_sync = NULL;
ESP_ERROR_CHECK(mcpwm_new_timer_sync_src(
    timer_a,
    &(mcpwm_timer_sync_src_config_t) {
        .timer_event = MCPWM_TIMER_EVENT_EMPTY,
    },
    &timer_sync));

  • timer_event — 触发同步输出的定时器事件。常用 MCPWM_TIMER_EVENT_EMPTY (零)表示每个周期开始,或 MCPWM_TIMER_EVENT_PEAK 表示峰值位置。在向上计数模式中峰值就是周期边界;在向上-向下计数模式中峰值是周期的中点。

  • propagate_input_sync — 设置后,该定时器会将其接收到的输入同步转发到其输出,无需额外 GPIO 接线即可实现定时器同步链。此模式下硬件选择输入同步作为输出源,因此 timer_event 字段会被忽略。

每个定时器最多只能创建一个同步源。多个定时器可以接收同一个同步源。

由于定时器同步源每周期都会触发,接收定时器在每个周期都会得到修正。这是维持多路 PWM 通道间稳定相位关系最常用的方式。

设置接收相位

无论选择哪种同步源,接收定时器都使用相同的 API。调用 mcpwm_timer_set_phase_on_sync() 配置同步边沿到达时的行为。定时器必须已经在运行,同步才会生效。

ESP_ERROR_CHECK(mcpwm_timer_set_phase_on_sync(timer,
    &(mcpwm_timer_sync_phase_config_t) {
        .sync_src = sync,
        .count_value = 25,
        .direction = MCPWM_TIMER_DIRECTION_UP,
    }));

  • sync_src — 源对象。设为 NULL 可取消同步。

  • count_value — 同步事件到达时加载的计数值。应保持在定时器周期范围内。

  • direction — 加载后的计数方向。

两路 90 度移相

现在你已经了解了三种同步源以及如何设置接收相位,下面是一个完整示例。它使用定时器同步源:timer_a 每次到达零时发出同步,timer_b 收到后加载 count_value = 25,产生 90 度相位滞后。由于同步每周期重复一次,两路输出的相位关系可以无限期保持。

mcpwm_timer_handle_t timer_a = NULL;
mcpwm_timer_handle_t timer_b = NULL;
mcpwm_sync_handle_t timer_a_sync = NULL;

// timer_a 和 timer_b 均已创建,period_ticks = 100

ESP_ERROR_CHECK(mcpwm_new_timer_sync_src(
    timer_a,
    &(mcpwm_timer_sync_src_config_t) {
        .timer_event = MCPWM_TIMER_EVENT_EMPTY,
    },
    &timer_a_sync));

ESP_ERROR_CHECK(mcpwm_timer_set_phase_on_sync(timer_b,
    &(mcpwm_timer_sync_phase_config_t) {
        .sync_src = timer_a_sync,
        .count_value = 25,
        .direction = MCPWM_TIMER_DIRECTION_UP,
    }));

// timer_a 在 TEZ 输出同步;timer_b 收到后从 Tick 25 开始继续计数。

理解领先与滞后

下面的示意中,PWM_A 先开始一个周期,PWM_B 在其后四分之一周期出现,因此 PWM_B 滞后 PWM_A 90 度;反过来说,PWM_A 领先 PWM_B 90 度。

PWM 相移 90 度滞后

PWM_A 与 PWM_B 之间的 90 度相移:PWM_B 在 PWM_A 之后 25 个 tick 处开始上升。

其他注意事项

捕获定时器也可通过 mcpwm_capture_timer_set_phase_on_sync() 使用同一同步源,捕获始终向上计数。接收端和源必须保留在同一组中。删除源之前,应先取消同步或删除所有使用它的对象。

API 参考

MCPWM 同步驱动函数

Header File

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

  • This header file can be included with:

    #include "driver/mcpwm_sync.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_sync_src(mcpwm_timer_handle_t timer, const mcpwm_timer_sync_src_config_t *config, mcpwm_sync_handle_t *ret_sync)

Create MCPWM timer sync source.

参数:
  • timer -- [in] MCPWM timer handle, allocated by mcpwm_new_timer()

  • config -- [in] MCPWM timer sync source configuration

  • ret_sync -- [out] Returned MCPWM sync handle

返回:

  • ESP_OK: Create MCPWM timer sync source successfully

  • ESP_ERR_INVALID_ARG: Create MCPWM timer sync source failed because of invalid argument

  • ESP_ERR_NO_MEM: Create MCPWM timer sync source failed because out of memory

  • ESP_ERR_INVALID_STATE: Create MCPWM timer sync source failed because the timer has created a sync source before

  • ESP_FAIL: Create MCPWM timer sync source failed because of other error

esp_err_t mcpwm_new_gpio_sync_src(const mcpwm_gpio_sync_src_config_t *config, mcpwm_sync_handle_t *ret_sync)

Create MCPWM GPIO sync source.

参数:
  • config -- [in] MCPWM GPIO sync source configuration

  • ret_sync -- [out] Returned MCPWM GPIO sync handle

返回:

  • ESP_OK: Create MCPWM GPIO sync source successfully

  • ESP_ERR_INVALID_ARG: Create MCPWM GPIO sync source failed because of invalid argument

  • ESP_ERR_NO_MEM: Create MCPWM GPIO sync source failed because out of memory

  • ESP_ERR_NOT_FOUND: Create MCPWM GPIO sync source failed because can't find free resource

  • ESP_FAIL: Create MCPWM GPIO sync source failed because of other error

esp_err_t mcpwm_new_soft_sync_src(const mcpwm_soft_sync_config_t *config, mcpwm_sync_handle_t *ret_sync)

Create MCPWM software sync source.

参数:
  • config -- [in] MCPWM software sync source configuration

  • ret_sync -- [out] Returned software sync handle

返回:

  • ESP_OK: Create MCPWM software sync successfully

  • ESP_ERR_INVALID_ARG: Create MCPWM software sync failed because of invalid argument

  • ESP_ERR_NO_MEM: Create MCPWM software sync failed because out of memory

  • ESP_FAIL: Create MCPWM software sync failed because of other error

esp_err_t mcpwm_del_sync_src(mcpwm_sync_handle_t sync)

Delete MCPWM sync source.

参数:

sync -- [in] MCPWM sync handle, allocated by mcpwm_new_timer_sync_src() or mcpwm_new_gpio_sync_src() or mcpwm_new_soft_sync_src()

返回:

  • ESP_OK: Delete MCPWM sync source successfully

  • ESP_ERR_INVALID_ARG: Delete MCPWM sync source failed because of invalid argument

  • ESP_FAIL: Delete MCPWM sync source failed because of other error

esp_err_t mcpwm_soft_sync_activate(mcpwm_sync_handle_t sync)

Activate the software sync, trigger the sync event for once.

参数:

sync -- [in] MCPWM soft sync handle, allocated by mcpwm_new_soft_sync_src()

返回:

  • ESP_OK: Trigger MCPWM software sync event successfully

  • ESP_ERR_INVALID_ARG: Trigger MCPWM software sync event failed because of invalid argument

  • ESP_FAIL: Trigger MCPWM software sync event failed because of other error

Structures

struct mcpwm_timer_sync_src_config_t

MCPWM timer sync source configuration.

Public Members

mcpwm_timer_event_t timer_event

Timer event, upon which MCPWM timer will generate the sync signal

struct mcpwm_timer_sync_src_config_t::extra_mcpwm_timer_sync_src_flags flags

Extra configuration flags for timer sync source

struct extra_mcpwm_timer_sync_src_flags

Extra configuration flags for timer sync source.

Public Members

uint32_t propagate_input_sync

The input sync signal would be routed to its sync output

struct mcpwm_gpio_sync_src_config_t

MCPWM GPIO sync source configuration.

Public Members

int group_id

MCPWM group ID

int gpio_num

GPIO used by sync source

struct mcpwm_gpio_sync_src_config_t::extra_mcpwm_gpio_sync_src_flags flags

Extra configuration flags for GPIO sync source

struct extra_mcpwm_gpio_sync_src_flags

Extra configuration flags for GPIO sync source.

Public Members

uint32_t active_neg

Whether the sync signal is active on negedge, by default, the sync signal's posedge is treated as active

struct mcpwm_soft_sync_config_t

MCPWM software sync configuration structure.


此文档对您有帮助吗?