GD32定时器高级应用:PWM生成与死区插入,HRTIM高精度定时器配置

各位同学,咱们今天聊点硬核的。FOC控制的核心,说白了就是靠PWM波去驱动MOS管,让电机转起来。但PWM不是随便给个占空比就完事了,这里面的门道,尤其是死区插入和HRTIM的玩法,我当年可是踩过不少坑。

我个人习惯,拿到一个新项目,先看定时器资源。GD32的定时器家族很庞大,从基本定时器到高级定时器,再到HRTIM,各有各的活。咱们做FOC,高级定时器是主力,HRTIM是杀手锏。

PWM生成:不只是占空比

先说说最基础的PWM生成。GD32的高级定时器(比如TIMER0、TIMER7)支持中心对齐模式和边沿对齐模式。做FOC,我强烈建议用中心对齐模式。

为什么是中心对齐?

因为中心对齐模式下,PWM的更新发生在计数器的顶点和底点,这正好和ADC采样的时刻对齐。你想想看,电流采样最理想的时刻就是PWM中间点,这时候开关噪声最小。

配置代码其实不复杂,我贴一段我常用的初始化片段:

// 定时器配置:中心对齐模式,PWM模式1
timer_oc_parameter_struct oc_config;
timer_parameter_struct timer_init_struct;

rcu_periph_clock_enable(RCU_TIMER0);

timer_deinit(TIMER0);
timer_struct_para_init(&timer_init_struct);
timer_init_struct.prescaler = 0;  // 不分频
timer_init_struct.period = 1000;  // 载波频率决定
timer_init_struct.clockdivision = TIMER_CKDIV_DIV1;
timer_init_struct.alignedmode = TIMER_COUNTER_CENTER_ALIGNED;  // 中心对齐
timer_init(TIMER0, &timer_init_struct);

// 配置通道1输出
timer_channel_output_struct_para_init(&oc_config);
oc_config.ocpolarity = TIMER_OC_POLARITY_HIGH;
oc_config.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_channel_output_config(TIMER0, TIMER_CH_0, &oc_config);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 500);  // 50%占空比

timer_enable(TIMER0);

嗯,这里要注意一点:period的值直接决定了PWM频率。FOC常用的载波频率在10kHz~20kHz之间,算一下主频就能得到period值。我遇到过有人直接把period设成最大值,结果电机嗡嗡响,查了半天才发现是频率太低。

死区插入:MOS管的保命符

说到死区,这可是个要命的话题。我记得刚做电机驱动那会儿,有一次没加死区,上电一瞬间,MOS管直接冒烟了。从那以后,我对死区配置格外小心。

死区的作用很简单:防止上下桥臂同时导通。因为MOS管关断需要时间,如果上管还没完全关断,下管就开了,那就是直通短路。

GD32的高级定时器内置了死区发生器,配置起来很方便:

// 死区配置:插入到互补PWM之间
timer_break_parameter_struct break_config;
timer_break_struct_para_init(&break_config);
break_config.deadtime = 200;  // 死区时间,单位取决于时钟分频
break_config.outputstate = TIMER_CCX_ENABLE;
break_config.outputnstate = TIMER_CCXN_ENABLE;
break_config.breakpolarity = TIMER_BREAK_POLARITY_LOW;
break_config.breakstate = TIMER_BREAK_ENABLE;
timer_break_config(TIMER0, &break_config);

死区时间怎么选?

一般根据MOS管的关断延迟来定。我常用的经验值:

  • 低速MOS管(如IRFP460):300~500ns
  • 中速MOS管(如NCE3080):150~300ns
  • 高速GaN器件:50~100ns

别贪心,死区设太大,波形失真;设太小,炸管风险。我一般留20%的余量。

死区插入后的波形,上下管的PWM之间会有一段空白期,这就是死区。你可以用示波器看,如果发现上下管波形有重叠,赶紧断电检查。

HRTIM高精度定时器:FOC的终极武器

如果你觉得普通定时器的PWM精度不够,那HRTIM就是为你准备的。GD32的HRTIM(高分辨率定时器)能做到皮秒级的PWM分辨率,对于高速电机控制或者低电感电机来说,简直是神器。

HRTIM和普通定时器最大的区别在于:

特性 普通高级定时器 HRTIM
PWM分辨率 1个时钟周期(~10ns @108MHz) ~217ps(使用DLL倍频)
通道数 4个 6个(可组合成3对互补)
死区调节 整数步进 高精度步进
触发同步 基本同步 多定时器交叉触发

HRTIM的配置比普通定时器复杂一些,但核心思路是一样的。我贴一个HRTIM的初始化框架:

// HRTIM初始化(简化版)
hrtim_parameter_struct hrtim_init;
hrtim_timing_parameter_struct timing;

rcu_periph_clock_enable(RCU_HRTIM);

hrtim_deinit();
hrtim_struct_para_init(&hrtim_init);
hrtim_init.prescaler = HRTIM_PRESCALER_DIV1;
hrtim_init.cntmode = HRTIM_CNT_MODE_CONTINUOUS;
hrtim_init.period = 5000;  // 高分辨率模式下,周期值更大
hrtim_init.halfmode = HRTIM_HALF_MODE_DISABLE;
hrtim_init(&hrtim_init);

// 配置定时器A(用于U相)
hrtim_timing_config(HRTIM_TIMER_ID_A, &timing);
hrtim_compare_config(HRTIM_TIMER_ID_A, HRTIM_COMPARE_ID_1, 2500);  // 50%占空比

// 使能输出
hrtim_output_enable(HRTIM_TIMER_ID_A, HRTIM_OUTPUT_ID_1);
hrtim_output_enable(HRTIM_TIMER_ID_A, HRTIM_OUTPUT_ID_2);  // 互补输出

hrtim_enable();

HRTIM的坑:

我曾经在一个项目里,HRTIM配置好后,PWM死活不出波形。查了半天,发现是HRTIM的时钟源没选对。HRTIM有独立的PLL,需要先使能并锁定,才能正常工作。另外,HRTIM的输出引脚是固定的,不能随便映射,这点和普通定时器不一样。

知识体系总览

下面这张图,是我自己总结的GD32定时器在FOC中的应用框架,你一看就明白:

GD32定时器在FOC控制中的应用框架 FOC控制需求 高级定时器 HRTIM 基本定时器 PWM生成 中心对齐 / 边沿对齐 死区插入 互补PWM保护 触发同步 ADC触发 / 定时器级联 SVPWM调制 三相占空比计算 电流采样触发 PWM中点对齐 故障保护 刹车输入 / 过流保护 HRTIM适用于高精度场景,普通高级定时器满足大部分FOC需求

实际项目中的配置建议

根据我多年的经验,不同场景下定时器的选择策略是这样的:

  1. 普通FOC(10kHz~20kHz载波):用高级定时器就够了,TIMER0或TIMER7,配置简单,资源充足。
  2. 高速电机(>100krpm):必须上HRTIM,普通定时器的分辨率不够,会导致电流纹波大,电机噪音明显。
  3. 低电感电机(如无人机电机):HRTIM的高精度死区调节是刚需,普通定时器的死区步进太大,容易造成死区时间不匹配。

我的调试小技巧:

调试PWM时,先用低频(比如1kHz)和大死区(比如1us)验证波形,确认无误后再逐步提高频率和减小死区。这样即使配置有误,也不会炸管。

好了,这一章的内容就这些。定时器是FOC的基石,PWM生成和死区插入是基本功,HRTIM是进阶玩法。把这些搞明白,后面的电流环和速度环调优才能事半功倍。