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. 知识结构总览

下面这张图把高级定时器配置的核心流程串起来了,你可以对照着看:

GD32高级定时器PWM配置流程 1. 时基配置 2. 比较输出配置 3. 死区时间配置 4. 刹车功能配置 5. 使能定时器 6. 输出PWM波形 关键参数 PWM频率:10~20kHz 死区时间:1~3μs 刹车源:硬件过流信号 调试建议 先空载测波形 确认死区后再接电机

这张图把配置流程分成了6步,每一步都有对应的寄存器操作。你按这个顺序来,基本不会漏配置。

6. 常见问题与调试经验

最后,我总结几个实际项目中容易踩的坑:

  • PWM输出没波形:检查outputstate和outputnstate有没有使能。我刚开始经常忘了配这个,折腾半天才发现。
  • 死区时间不对:确认时钟频率。GD72的定时器时钟可能是72MHz也可能是108MHz,死区时间计算公式里的Tck要对应上。
  • 刹车后PWM不恢复:检查breakautomatic有没有使能。如果没使能,刹车信号消失后需要软件手动清除刹车标志位。
  • 电机抖动或噪音大:死区时间可能偏大,或者PWM频率不合适。我一般先调死区,再调频率。

个人习惯:每次改完定时器配置,我都会用逻辑分析仪抓一下三对互补PWM的波形,确认相位关系正确、死区时间符合预期。这一步虽然花时间,但能避免很多低级错误。

好了,这一章的内容就到这里。高级定时器的配置是FOC控制的基础,配好了后面SVPWM的调试才能顺利进行。记住:PWM波形是电机控制的“语言”,波形不对,算法再牛也白搭。