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
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_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_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_emptyandmcpwm_timer_config_t::update_period_on_syncare 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_valueto 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_timerperiod_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
cbsstructure 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
-
mcpwm_timer_event_cb_t on_full
-
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.
-
uint32_t update_period_on_empty
-
int group_id
-
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
-
mcpwm_sync_handle_t sync_src