GD32定时器与PWM输出:高级定时器配置、互补PWM输出、死区时间设置、刹车功能
做FOC控制,说白了就是跟PWM打交道。你想想看,SVPWM算法算出来的那六个扇区、三个占空比,最终都得靠定时器输出成实实在在的方波,才能驱动MOS管。GD32的高级定时器(TMRx)在这方面功能很强,但配置起来也有不少坑。我刚开始做电机驱动那会儿,就在死区时间和刹车功能上栽过跟头,板子冒烟的事也不是没遇到过。
这一章,咱们就把GD32高级定时器里跟FOC最相关的几个模块掰开揉碎讲清楚:互补PWM怎么配、死区时间怎么算、刹车功能怎么用。这些都是实战中绕不开的硬骨头。
1. 高级定时器(TMRx)的核心架构
GD32的TMR0、TMR7这类高级定时器,跟普通定时器最大的区别就是多了“互补输出”和“刹车”这两个模块。我习惯把高级定时器看成三个部分:
- 时基单元:决定PWM的频率。说白了就是计数器、预分频器、自动重装载寄存器那套东西。
- 比较输出单元:决定PWM的占空比。FOC算法算出来的占空比就写在这里。
- 输出控制与保护单元:决定PWM怎么输出、什么时候关断。死区插入、刹车响应都在这一块。
嗯,这里要注意:FOC控制至少需要三对互补PWM(六路),分别控制U、V、W三相。GD32的高级定时器通常有3个或4个比较通道,每个通道都能输出一对互补信号,刚好够用。
核心要点:FOC的PWM频率通常设在10kHz~20kHz之间。频率太低,电流纹波大;频率太高,开关损耗大。我个人习惯先定16kHz,听不到噪音,效率也还行。
2. 互补PWM输出配置
互补PWM,就是同一通道输出两路极性相反的方波,一路控制上桥臂,一路控制下桥臂。GD32的配置流程其实不复杂,但寄存器名字容易搞混。
我直接给出一段我项目里用过的初始化代码,注释写得很清楚:
// 以TMR0为例,配置CH0为互补PWM输出
void timer_pwm_complementary_init(void)
{
// 1. 使能定时器时钟
rcu_periph_clock_enable(RCU_TIMER0);
// 2. 配置时基:16kHz PWM频率,72MHz时钟
timer_parameter_struct timer_initpara;
timer_struct_para_init(&timer_initpara);
timer_initpara.prescaler = 0; // 预分频:72MHz
timer_initpara.period = 4500 - 1; // 自动重装载:16kHz
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER0, &timer_initpara);
// 3. 配置比较输出模式:PWM模式1
timer_oc_parameter_struct timer_ocinitpara;
timer_channel_output_struct_para_init(&timer_ocinitpara);
timer_ocinitpara.outputstate = TIMER_CCX_ENABLE; // 使能CH0输出
timer_ocinitpara.outputnstate = TIMER_CCXN_ENABLE; // 使能CH0N互补输出
timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH; // 正输出高有效
timer_ocinitpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH; // 互补输出高有效
timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW; // 空闲时正输出低电平
timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW; // 空闲时互补输出低电平
timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocinitpara);
// 4. 使能自动重装载预装载
timer_auto_reload_shadow_enable(TIMER0);
// 5. 使能定时器
timer_enable(TIMER0);
}
这段代码里有个细节我吃过亏:ocidlestate和ocnidlestate一定要配成一致。我曾经把正输出配成低电平、互补输出配成高电平,结果一上电MOS管就直通短路,板子直接冒烟。嗯,从那以后我再也不敢乱配空闲状态了。
实战技巧:配置互补输出时,建议先用示波器看波形,确认两路信号之间有明显的死区,再接到驱动板上。我每次调试新板子,都会先空载测波形,确认无误后再接电机。
3. 死区时间设置
死区时间,就是上桥臂关断到下桥臂导通之间的延迟。为什么要加这个?因为MOS管关断需要时间,如果上桥臂还没完全关断、下桥臂就导通了,那上下桥臂就会直通,电流瞬间飙升,管子必烧。
GD32的死区时间由TIMERx_CAR寄存器控制,分为DTG[7:0]这8个位。配置方式有点绕,我直接给公式:
| DTG[7:0]范围 | 死区时间计算公式 | 示例(72MHz时钟) |
|---|---|---|
| 0x00 ~ 0x7F | DT × Tck | DT=100 → 100 × 13.89ns = 1.389μs |
| 0x80 ~ 0xBF | (64 + DT[5:0]) × 2 × Tck | DT=0xA0 → (64+32) × 27.78ns = 2.667μs |
| 0xC0 ~ 0xDF | (32 + DT[4:0]) × 8 × Tck | DT=0xD0 → (32+16) × 111.11ns = 5.333μs |
| 0xE0 ~ 0xFF | (32 + DT[4:0]) × 16 × Tck | DT=0xF0 → (32+16) × 222.22ns = 10.667μs |
死区时间怎么选?我一般遵循这个原则:
- MOS管规格:看数据手册里的关断延迟时间(td(off))和下降时间(tf),死区时间至少要大于这两者之和。
- 驱动电路:如果用了隔离驱动或栅极电阻较大,开关速度会变慢,死区要适当加大。
- PWM频率:频率越高,死区时间占比越大,对波形质量影响越明显。
避坑指南:死区时间不是越大越好。死区太大,电流波形会失真,电机噪音变大,效率下降。我曾经在一个项目里把死区设到3μs,结果电机低速运行时抖动得厉害,后来改成1μs就正常了。建议从1μs开始试,逐步减小,直到电流波形出现畸变再回调一点。
配置死区时间的代码很简单:
// 设置死区时间为1.389μs(72MHz时钟,DT=100)
timer_channel_dead_time_config(TIMER0, TIMER_CH_0, 100);
4. 刹车功能(Break Function)
刹车功能,是高级定时器里最重要的安全机制。当检测到故障信号(比如过流、过压)时,刹车功能可以立即强制关闭所有PWM输出,把MOS管全部关断,保护电路不被烧毁。
GD32的刹车功能有几个关键配置点:
- 刹车源:可以是外部引脚(BRK_IN),也可以是软件触发。
- 刹车极性:高电平有效还是低电平有效。
- 刹车输出状态:刹车后PWM输出是高电平、低电平还是高阻态。
- 自动恢复:刹车信号消失后,PWM是否自动恢复输出。
我一般这样配置刹车功能:
// 配置刹车功能
void timer_break_config(void)
{
timer_break_parameter_struct timer_breakpara;
timer_break_struct_para_init(&timer_breakpara);
timer_breakpara.breakstate = TIMER_BREAK_ENABLE; // 使能刹车
timer_breakpara.breakpolarity = TIMER_BREAK_POLARITY_HIGH; // 高电平触发刹车
timer_breakpara.breakfilter = TIMER_BREAK_FILTER_DIV1_8; // 输入滤波
timer_breakpara.outputstate = TIMER_OUTPUT_STATE_DISABLE; // 刹车后输出关闭
timer_breakpara.outputnstate = TIMER_OUTPUTN_STATE_DISABLE;
timer_breakpara.breakautomatic = TIMER_BREAK_AUTOMATIC_ENABLE; // 自动恢复
timer_breakpara.protectmode = TIMER_PROTECT_MODE_1; // 保护模式1
timer_break_config(TIMER0, &timer_breakpara);
}
这里有个关键参数protectmode,它决定了刹车后哪些寄存器被保护:
| 保护模式 | 说明 | 适用场景 |
|---|---|---|
| 模式0 | 不保护任何寄存器 | 调试阶段 |
| 模式1 | 保护比较值和死区寄存器 | 生产环境(推荐) |
| 模式2 | 保护比较值、死区和刹车寄存器 | 高安全要求 |
实战建议:刹车功能一定要接硬件过流保护信号。我见过有人只靠软件检测过流,结果CPU死机时PWM照常输出,电机直接烧了。硬件刹车是最后一道防线,不能省。
5. 知识结构总览
下面这张图把高级定时器配置的核心流程串起来了,你可以对照着看:
这张图把配置流程分成了6步,每一步都有对应的寄存器操作。你按这个顺序来,基本不会漏配置。
6. 常见问题与调试经验
最后,我总结几个实际项目中容易踩的坑:
- PWM输出没波形:检查
outputstate和outputnstate有没有使能。我刚开始经常忘了配这个,折腾半天才发现。 - 死区时间不对:确认时钟频率。GD72的定时器时钟可能是72MHz也可能是108MHz,死区时间计算公式里的Tck要对应上。
- 刹车后PWM不恢复:检查
breakautomatic有没有使能。如果没使能,刹车信号消失后需要软件手动清除刹车标志位。 - 电机抖动或噪音大:死区时间可能偏大,或者PWM频率不合适。我一般先调死区,再调频率。
个人习惯:每次改完定时器配置,我都会用逻辑分析仪抓一下三对互补PWM的波形,确认相位关系正确、死区时间符合预期。这一步虽然花时间,但能避免很多低级错误。
好了,这一章的内容就到这里。高级定时器的配置是FOC控制的基础,配好了后面SVPWM的调试才能顺利进行。记住:PWM波形是电机控制的“语言”,波形不对,算法再牛也白搭。