电机控制脉宽调制器 (MCPWM)
从这里开始
MCPWM 将计数器转换为时序精确的输出边沿。当 LEDC 的简单 PWM 已无法满足需求时,可使用 MCPWM:电机桥需要互补输出和死区,逆变器需要同步相位,传感器则需要精确测量脉宽。
最小可用的 MCPWM 设计由四个对象构成:定时器 提供时间基准,操作器 管理波形资源,比较器 决定边沿位置,生成器 驱动 GPIO。其他模块均在此基础上扩展。
构建一路 PWM 输出
初次生成 PWM 输出时,请按下图从左至右创建对象。主线上各阶段按角色配色:时间基准(蓝色)、操作器核心(紫色)、波形配置(青色)、启用与输出(绿色)。琥珀色节点为基础输出正常后按需添加的扩展,红色节点为安全制动。只有在所有输出动作均已配置完成后,才启动定时器。
flowchart LR
T1["1. 创建定时器<br/>mcpwm_new_timer"]:::time
O1["2. 创建操作器<br/>mcpwm_new_operator"]:::core
LINK["3. 连接时间基准<br/>mcpwm_operator_connect_timer"]:::core
C1["4. 创建比较器<br/>mcpwm_new_comparator"]:::wave
G1["5. 创建生成器<br/>mcpwm_new_generator"]:::wave
A1["6. 描述边沿<br/>mcpwm_generator_set_action_on_*_event"]:::wave
RUN["7. 启用并启动<br/>mcpwm_timer_enable<br/>mcpwm_timer_start_stop"]:::run
PIN["GPIO 输出 PWM"]:::output
T1 --> O1 --> LINK --> C1 --> G1 --> A1 --> RUN --> PIN
DT["死区<br/>mcpwm_generator_set_dead_time"]:::optional
BR["故障与制动<br/>mcpwm_new_*_fault<br/>mcpwm_operator_set_brake_on_fault"]:::safety
SY["相位同步<br/>mcpwm_new_*_sync_src<br/>mcpwm_timer_set_phase_on_sync"]:::optional
CA["载波调制<br/>mcpwm_operator_apply_carrier"]:::optional
A1 -. 扩展 .-> DT
O1 -. 保护 .-> BR
T1 -. 对齐 .-> SY
O1 -. 调制 .-> CA
classDef time fill:#dbeafe,stroke:#2563eb,color:#172554
classDef core fill:#ede9fe,stroke:#7c3aed,color:#2e1065
classDef wave fill:#cffafe,stroke:#0891b2,color:#164e63
classDef run fill:#dcfce7,stroke:#16a34a,color:#14532d
classDef output fill:#bbf7d0,stroke:#15803d,color:#14532d
classDef optional fill:#fef3c7,stroke:#d97706,color:#78350f
classDef safety fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
下面这段代码创建一路 20 kHz、30% 占空比的 PWM 输出,可作为阅读后续各页前的整体参考。它展示了对象的创建顺序,也说明了运行时最常改动的其实是比较器,而不是重新配置整条链路。
mcpwm_timer_handle_t timer = NULL;
mcpwm_oper_handle_t oper = NULL;
mcpwm_cmpr_handle_t comparator = NULL;
mcpwm_gen_handle_t generator = NULL;
// 1 MHz → 1 tick = 1 µs
// 50 ticks → 50 µs 周期 → 20 kHz
ESP_ERROR_CHECK(mcpwm_new_timer(
&(mcpwm_timer_config_t) {
.group_id = 0,
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
.resolution_hz = 1000000,
.period_ticks = 50,
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
},
&timer));
ESP_ERROR_CHECK(mcpwm_new_operator(
&(mcpwm_operator_config_t) {
.group_id = 0,
},
&oper));
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(oper, timer));
ESP_ERROR_CHECK(mcpwm_new_comparator(
oper,
&(mcpwm_comparator_config_t) {
.flags.update_cmp_on_tez = true,
},
&comparator));
// 15 / 50 = 30% 占空比
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparator, 15));
ESP_ERROR_CHECK(mcpwm_new_generator(
oper,
&(mcpwm_generator_config_t) {
.gen_gpio_num = 18,
},
&generator));
// 定时器归零 → 输出 HIGH;比较器匹配 → 输出 LOW
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(
generator,
MCPWM_GEN_TIMER_EVENT_ACTION(
MCPWM_TIMER_DIRECTION_UP,
MCPWM_TIMER_EVENT_EMPTY,
MCPWM_GEN_ACTION_HIGH)));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(
generator,
MCPWM_GEN_COMPARE_EVENT_ACTION(
MCPWM_TIMER_DIRECTION_UP,
comparator,
MCPWM_GEN_ACTION_LOW)));
ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
// 运行时修改比较值即可调整占空比,无需重建生成器动作。
// 25 / 50 = 50% 占空比
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparator, 25));
定时器的 resolution_hz 和 period_ticks 确定时序刻度;比较器的 compare_value 在该刻度中选择边沿位置;生成器动作 API 决定在定时器边界或比较器越过阈值时输出何种电平。这种分工也便于调参:改变定时器可调整频率,改变比较器可调整占空比或边沿位置,改变生成器动作可调整极性或波形形状。
波形配置完成后,调用 mcpwm_timer_enable() 和 mcpwm_timer_start_stop()。运行时应通过 mcpwm_comparator_set_compare_value() 更新比较器,而不是重新配置生成器动作。仅在应用需要时添加对应扩展:半桥使用死区,安全路径使用故障与制动,相位对齐使用同步,隔离式驱动使用载波。
功能地图
目标 |
先看哪些页 |
关键 API |
典型应用 |
|---|---|---|---|
输出单路 PWM |
|
舵机、调光、基础功率控制 |
|
输出互补半桥 PWM |
半桥、逆变桥臂 |
||
多路同频对齐或移相 |
多相电机、并联变换器 |
||
测量输入脉宽或周期 |
HC-SR04、转速计、RC 输入 |
||
外设间硬件联动 |
|
ADC 触发、跨外设定时链路 |
本指南中每个页面介绍一个 MCPWM 模块:
资源与生命周期
所有对象都属于一个 MCPWM 组。连接的定时器与操作器必须位于同一组;GPIO 故障源和 GPIO 同步源也只能在本组中使用。硬件资源有限,创建时可能返回 ESP_ERR_NOT_FOUND。
每个对象都由 mcpwm_new_*() 工厂函数创建并返回一个不透明句柄,由对应的 mcpwm_del_*() 函数释放,例如 mcpwm_new_timer() 与 mcpwm_del_timer()。先创建父对象,再创建子对象;释放时按相反顺序执行:先删除生成器/比较器,再删除操作器,最后删除定时器。删除定时器前必须禁用它;删除捕获定时器前必须删除其通道。
组时钟分频器由定时器共享,部分芯片的捕获定时器也共享它。按目标分辨率单调顺序(从高到低或从低到高)创建对象,可避免分频冲突。详见 高级主题。
术语速查
TEZ: Timer equals zero,定时器计数等于零时触发的事件。
TEP: Timer equals peak,定时器计数达到峰值时触发的事件。
定时器(Timer): MCPWM 的时间基准,决定频率和 Tick 刻度。
操作器(Operator): 连接定时器与输出逻辑的容器,管理比较器、生成器、制动、死区和载波。
比较器(Comparator): 当计数达到阈值时发出事件,常用于决定边沿位置和占空比。
生成器(Generator): 根据定时器/比较器/故障/同步事件输出 GPIO 电平。
死区(Dead Time): 在半桥上下管切换之间插入的非重叠时间,避免直通。
故障(Fault): 进入保护路径的异常源,可来自 GPIO 或软件。
制动(Brake): 故障触发后的输出安全策略。
CBC: Cycle By Cycle,故障有效时制动,清除后在周期边界自动恢复。
OST: One Shot,一次制动后保持锁存,需软件显式恢复。
同步(Sync): 在同步边沿把定时器加载到指定计数值和方向,以实现对齐或移相。
捕获(Capture): 对输入边沿打时间戳,用于测脉宽、周期或转速。
应用示例
peripherals/mcpwm/mcpwm_servo_control:RC 舵机的单路 PWM。
peripherals/mcpwm/mcpwm_bdc_speed_control:有刷直流电机及速度反馈。
peripherals/mcpwm/mcpwm_bldc_hall_control:使用霍尔传感器反馈进行 BLDC 换相。
peripherals/mcpwm/mcpwm_capture_hc_sr04:使用 HC-SR04 测量脉宽。
peripherals/mcpwm/mcpwm_sync:GPIO、定时器和软件同步。
peripherals/mcpwm/mcpwm_foc_svpwm_open_loop:开环 FOC 的三对互补 PWM。
API 参考
通用类型
Header File
This header file can be included with:
#include "driver/mcpwm_types.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
Structures
-
struct mcpwm_timer_event_data_t
MCPWM timer event data.
Public Members
-
uint32_t count_value
MCPWM timer count value
-
mcpwm_timer_direction_t direction
MCPWM timer count direction
-
uint32_t count_value
-
struct mcpwm_brake_event_data_t
MCPWM brake event data.
-
struct mcpwm_fault_event_data_t
MCPWM fault event data.
-
struct mcpwm_compare_event_data_t
MCPWM compare event data.
Public Members
-
uint32_t compare_ticks
Compare value
-
mcpwm_timer_direction_t direction
Count direction
-
uint32_t compare_ticks
-
struct mcpwm_capture_event_data_t
MCPWM capture event data.
Type Definitions
-
typedef struct mcpwm_timer_t *mcpwm_timer_handle_t
Type of MCPWM timer handle.
-
typedef struct mcpwm_oper_t *mcpwm_oper_handle_t
Type of MCPWM operator handle.
-
typedef struct mcpwm_cmpr_t *mcpwm_cmpr_handle_t
Type of MCPWM comparator handle.
-
typedef struct mcpwm_gen_t *mcpwm_gen_handle_t
Type of MCPWM generator handle.
-
typedef struct mcpwm_fault_t *mcpwm_fault_handle_t
Type of MCPWM fault handle.
-
typedef struct mcpwm_sync_t *mcpwm_sync_handle_t
Type of MCPWM sync handle.
-
typedef struct mcpwm_cap_timer_t *mcpwm_cap_timer_handle_t
Type of MCPWM capture timer handle.
-
typedef struct mcpwm_cap_channel_t *mcpwm_cap_channel_handle_t
Type of MCPWM capture channel handle.
-
typedef bool (*mcpwm_timer_event_cb_t)(mcpwm_timer_handle_t timer, const mcpwm_timer_event_data_t *edata, void *user_ctx)
MCPWM timer event callback function.
- Param timer:
[in] MCPWM timer handle
- Param edata:
[in] MCPWM timer event data, fed by driver
- Param user_ctx:
[in] User data, set in
mcpwm_timer_register_event_callbacks()- Return:
Whether a high priority task has been waken up by this function
-
typedef bool (*mcpwm_brake_event_cb_t)(mcpwm_oper_handle_t oper, const mcpwm_brake_event_data_t *edata, void *user_ctx)
MCPWM operator brake event callback function.
- Param oper:
[in] MCPWM operator handle
- Param edata:
[in] MCPWM brake event data, fed by driver
- Param user_ctx:
[in] User data, set in
mcpwm_operator_register_event_callbacks()- Return:
Whether a high priority task has been waken up by this function
-
typedef bool (*mcpwm_fault_event_cb_t)(mcpwm_fault_handle_t fault, const mcpwm_fault_event_data_t *edata, void *user_ctx)
MCPWM fault event callback function.
- Param fault:
MCPWM fault handle
- Param edata:
MCPWM fault event data, fed by driver
- Param user_ctx:
User data, set in
mcpwm_fault_register_event_callbacks()- Return:
whether a task switch is needed after the callback returns
-
typedef bool (*mcpwm_compare_event_cb_t)(mcpwm_cmpr_handle_t comparator, const mcpwm_compare_event_data_t *edata, void *user_ctx)
MCPWM comparator event callback function.
- Param comparator:
MCPWM comparator handle
- Param edata:
MCPWM comparator event data, fed by driver
- Param user_ctx:
User data, set in
mcpwm_comparator_register_event_callbacks()- Return:
Whether a high priority task has been waken up by this function
-
typedef bool (*mcpwm_capture_event_cb_t)(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_data_t *edata, void *user_ctx)
MCPWM capture event callback function.
- Param cap_channel:
MCPWM capture channel handle
- Param edata:
MCPWM capture event data, fed by driver
- Param user_ctx:
User data, set in
mcpwm_capture_channel_register_event_callbacks()- Return:
Whether a high priority task has been waken up by this function
Header File
This header file can be included with:
#include "hal/mcpwm_types.h"
This header file is a part of the API provided by the
esp_hal_mcpwmcomponent. To declare that your component depends onesp_hal_mcpwm, add the following to your CMakeLists.txt:REQUIRES esp_hal_mcpwm
or
PRIV_REQUIRES esp_hal_mcpwm
Type Definitions
-
typedef soc_periph_mcpwm_timer_clk_src_t mcpwm_timer_clock_source_t
MCPWM timer clock source.
-
typedef soc_periph_mcpwm_capture_clk_src_t mcpwm_capture_clock_source_t
MCPWM capture clock source.
-
typedef soc_periph_mcpwm_carrier_clk_src_t mcpwm_carrier_clock_source_t
MCPWM carrier clock source.
Enumerations
-
enum mcpwm_timer_direction_t
MCPWM timer count direction.
Values:
-
enumerator MCPWM_TIMER_DIRECTION_UP
Counting direction: Increase
-
enumerator MCPWM_TIMER_DIRECTION_DOWN
Counting direction: Decrease
-
enumerator MCPWM_TIMER_DIRECTION_UP
-
enum mcpwm_timer_event_t
MCPWM timer events.
Values:
-
enumerator MCPWM_TIMER_EVENT_EMPTY
MCPWM timer counts to zero (i.e. counter is empty)
-
enumerator MCPWM_TIMER_EVENT_FULL
MCPWM timer counts to peak (i.e. counter is full)
-
enumerator MCPWM_TIMER_EVENT_INVALID
MCPWM timer invalid event
-
enumerator MCPWM_TIMER_EVENT_EMPTY
-
enum mcpwm_timer_count_mode_t
MCPWM timer count modes.
Values:
-
enumerator MCPWM_TIMER_COUNT_MODE_PAUSE
MCPWM timer paused
-
enumerator MCPWM_TIMER_COUNT_MODE_UP
MCPWM timer counting up
-
enumerator MCPWM_TIMER_COUNT_MODE_DOWN
MCPWM timer counting down
-
enumerator MCPWM_TIMER_COUNT_MODE_UP_DOWN
MCPWM timer counting up and down
-
enumerator MCPWM_TIMER_COUNT_MODE_PAUSE
-
enum mcpwm_timer_start_stop_cmd_t
MCPWM timer commands, specify the way to start or stop the timer.
Values:
-
enumerator MCPWM_TIMER_STOP_EMPTY
MCPWM timer stops when next count reaches zero
-
enumerator MCPWM_TIMER_STOP_FULL
MCPWM timer stops when next count reaches peak
-
enumerator MCPWM_TIMER_START_NO_STOP
MCPWM timer starts counting, and don't stop until received stop command
-
enumerator MCPWM_TIMER_START_STOP_EMPTY
MCPWM timer starts counting and stops when next count reaches zero
-
enumerator MCPWM_TIMER_START_STOP_FULL
MCPWM timer starts counting and stops when next count reaches peak
-
enumerator MCPWM_TIMER_STOP_EMPTY
-
enum mcpwm_generator_action_t
MCPWM generator actions.
Values:
-
enumerator MCPWM_GEN_ACTION_KEEP
Generator action: Keep the same level
-
enumerator MCPWM_GEN_ACTION_LOW
Generator action: Force to low level
-
enumerator MCPWM_GEN_ACTION_HIGH
Generator action: Force to high level
-
enumerator MCPWM_GEN_ACTION_TOGGLE
Generator action: Toggle level
-
enumerator MCPWM_GEN_ACTION_KEEP
-
enum mcpwm_operator_brake_mode_t
MCPWM operator brake mode.
Values:
-
enumerator MCPWM_OPER_BRAKE_MODE_CBC
Brake mode: CBC (cycle by cycle)
-
enumerator MCPWM_OPER_BRAKE_MODE_OST
Brake mode: OST (one shot)
-
enumerator MCPWM_OPER_BRAKE_MODE_INVALID
MCPWM operator invalid brake mode
-
enumerator MCPWM_OPER_BRAKE_MODE_CBC
-
enum mcpwm_capture_edge_t
MCPWM capture edge.
Values:
-
enumerator MCPWM_CAP_EDGE_POS
Capture on the positive edge
-
enumerator MCPWM_CAP_EDGE_NEG
Capture on the negative edge
-
enumerator MCPWM_CAP_EDGE_POS