☰
STM32G474 HRTIM驱动移相全桥:从波形到闭环的完整指南
2026/10/5 11:29:47 网站建设 项目流程

前阵子帮朋友调一台2kW的移相全桥样机,控制器从TMS320F28379D换成了STM32G474,核心就是看中它内置的HRTIM高精度定时器。很多人一听“移相全桥”就觉得得用DSP或者FPGA,其实把HRTIM摸透了,一颗几十块钱的G474就能干完全部活:四路带死区的PWM、移相角连续调节、ADC同步采样、过流保护联动,全部单芯片搞定。

这篇文章就把我这次从零开始搭移相全桥控制程序的完整思路写出来。内容包含波形怎么设计、寄存器怎么配、移相怎么动态调、反馈环怎么闭环,以及我调机过程中踩过的几个真实坑。无论你是准备自己用G4做数字电源,还是单纯想搞懂HRTIM的移相机制,应该都能拿我这份记录直接当参考。

1. 为什么选STM32G474而不是DSP:先看清HRTIM的本质

1.1 移相全桥对控制器的四个硬性要求

移相全桥不是随便拿一个MCU就能玩的。它的控制要求非常具体,归纳起来其实只有四条:

第一,需要输出两组互补且相位可调的PWM信号。一组驱动左半桥Q1/Q3,一组驱动右半桥Q2/Q4,两组之间必须存在一个可以在0到接近180度范围内精确调整的相位差,这个相位差直接决定输出功率。

第二,每组互补信号之间需要插入可配置的死区时间。死区太小可能直通炸管,死区太大会造成副边占空比丢失,所以死区必须可细调、可独立配置上升沿和下降沿。

第三,移相角需要在控制周期内动态更新。也就是说一个周期结束后,下一个周期的PWM相位就要立刻变化,不能出现中间状态的畸形脉冲。

第四,PWM时序必须能和ADC采样、故障保护精确对齐。移相全桥的电流波形是脉动的,采样点如果落在开关振铃区,反馈值就会抖到怀疑人生,所以必须有硬件级的触发联动。

这四个要求,普通定时器TIM1/TIM8很难同时满足,特别是第二条和第四条,往往需要外部分立逻辑来处理。而STM32G474的HRTIM,天生就是照着这个需求设计的。

1.2 HRTIM与传统高级定时器TIM1的差异

STM32G474上这颗HRTIM,全称是High-Resolution Timer,跟F1/F4时代的高级定时器完全是两个物种。

先看时基。G474的主频可以跑到170MHz,HRTIM最高可以直接用这个170MHz作为计数时钟,一个计数周期约5.88ns。在200kHz开关频率下,一个完整的5us PWM周期,大约对应850个计数点,也就是说移相角的天然分辨率大约0.42度。这个精度已经高于绝大多数模拟方案的死区RC精度。开启HRTIM内部DLL校准后,还可以把边沿延时精度进一步压到约130ps级别,相位步进更小,这是普通TIM1永远做不到的。

再看结构。HRTIM并不是一个孤立的定时器,它内部有A、B、C、D、E共5个独立定时器。每个定时器都能输出两路PWM,加上可编程的死区发生器,一共能支持10路高精度输出。关键的是这5个定时器之间可以互相设置复位源、触发源、比较事件联动,也就是所谓的“定时器级联”。移相全桥恰好需要两对互补PWM,用TA产生一对,TB产生另一对,两者之间通过比较事件互相锁定周期起点,天然就是为这个拓扑准备的。

再加上HRTIM的事件触发矩阵可以映射到ADC的注入组、规则组以及刹车输入,采样和保护都不需要CPU额外干预,这就把数字电源最头疼的时序一致性问题从软件层面直接解决了。

1.3 与DSP方案相比的成本和门槛优势

以前做移相全桥,圈里默认方案就是C2000系列或者STM32F334这类带高级定时器的型号。C2000确实很强,软件生态也成熟,但一颗F28379D的价格和供货稳定性,在当下的项目环境里真的是个老大难问题。STM32G474的出现,等于给了第二条路:同样是170MHz的Cortex-M4,带FPU,带片内比较器、运算放大器、DAC、5Msps的ADC,再加上HRTIM这个杀手锏,一套下来一颗芯片全包,价格还比传统DSP方案低不少。

开发门槛方面,G474可以用STM32CubeMX生成工程,HRTIM的基础配置(时基、比较寄存器、输出引脚)可以图形化搞定。移相关系、死区时序这些核心逻辑则需要自己理解后动手配。说实话,HRTIM的寄存器文档又厚又绕,刚开始看很劝退,但把五个定时器的“主从复位”机制搞明白后,移相全桥的实现难度其实比在C2000里写EPWM还要直接。

2. 四路PWM的时序设计:移相全桥到底要什么波形

2.1 从全桥拓扑理解两对互补信号

移相全桥之所以叫“移相”,关键就在于两个桥臂的驱动波形不是固定反相的,而是有意识的“错开”一点角度。

拿一个全桥来拆解。左桥臂上管Q1和下管Q3是一对互补信号,用PWM_A驱动;右桥臂上管Q2和下管Q4是另一对互补信号,用PWM_B驱动。传统全桥里,PWM_A和PWM_B严格反相,也就是相位差固定180度,这样Q1和Q4同时导通半个周期,Q2和Q3同时导通另外半个周期,输出最大。

移相全桥的控制思路是:两个桥臂仍然保持接近反相的工作状态,但通过把PWM_B相对PWM_A正常反相点的位置向前或向后偏移一个角度,让对角线开关管的重叠导通时间缩短。重叠时间变短,变压器原边施加电压的有效时间就变短,输出能量随之降低。这个“错开的角度”就是我们常说的移相角,移相角越大,输出占空比越大还是越小取决于参考定义,在实际项目中我把它定义为“相对理想反相点的偏移量”,偏移越大,有效占空比越小。偏移0度时,相当于普通全桥满占空比运行;偏移接近半个周期时,有效占空比降到0附近。

所以,HRTIM的输出不需要像电机控制那样有三相空间矢量之类的花活,它只需要老老实实输出两路50%占空比的方波,并让两路方波之间的相对相位可以连续调整。听起来很简单,但波形质量必须稳定:相位不能抖,死区不能漏,更新不能乱。

2.2 死区时间的设定逻辑与占空比丢失

移相全桥每个桥臂的上下管切换都需要死区,这是为了给MOSFET的寄生电容充放电留出时间窗口。更准确地说,死区时间的设计和ZVS(零电压开关)能不能实现是强相关的。

死区时间给多少,先看开关管的关断延时和栅极驱动电路的传播延迟差别。常见MOSFET的关断延迟在几十ns到一百多ns不等,栅极驱动芯片的匹配误差一般在20ns以内。如果死区时间小于上下管的关断延时差,就会发生直通。所以我的经验是:在170MHz时基下,200kHz开关频率,死区先给17个计数,折合约100ns,这是基础值;然后上示波器看换流波形,如果看到桥臂中点电压在死区时间内已经完成翻转并出现长时间平台,可以试着往下压,如果关断波形还没稳定就出现另一边开通的趋势,就往上加。最终我这个项目的两对桥臂死区都定在130ns左右,满载和轻载都验证过没有直通风险。

死区也不是越大越好。死区期间变压器原边电流会从副边折算过来的电流主导,这段时间内原边电压为零,能量不传递,等效到副边就是占空比丢失。死区每增加1ns,副边有效占空比就少一点。在低压大电流输出场景,比如48V/40A的电源,副边哪怕丢失0.5%占空比,输出电流能力都会明显下降,所以死区必须在安全范围内压到尽量小,不能拍脑袋给一个“看起来保险”的大值。

2.3 同步整流信号从哪来

移相全桥的副边如果做同步整流,还需要两路和原边换流逻辑绑定的驱动信号。这部分我一开始想过用逻辑芯片和定时器拼,后来发现直接用HRTIM的TC定时器最干净。

TC可以和TA联动,通过配置复位源和比较值,让TC1/TC2输出的SR驱动信号在变压器原边换流前的合适时刻先关闭,在原边换流完成后再打开,从而避开死区窗口。TC的时基、周期与TA完全一致,移动相位只需要挪动TC的比较值,不需要重新算时间。用TC的好处是,SR信号和原边PWM天然同源,不存在独立定时器跑偏的问题。

不过如果项目初期只是想先把主功率拓扑调通,副边用快恢复二极管整流验证也是完全可行的。我的建议是先不挂SR,等原边移相逻辑稳定了再逐步加入同步整流,否则问题叠加在一起,出故障时很难定位。

3. HRTIM核心配置实操:TA和TB产生可调移相

3.1 初始化流程与DLL校准

先说初始化顺序,这个顺序踩过坑,写反了会有各种诡异现象。正确流程是先配置HRTIM的基本时基和比较寄存器,然后配置死区,再使能DLL校准,等校准完成后输出使能。

DLL校准这里要特别说一句。HRTIM的DLL用于把时钟边沿进一步细分,出发点是抵消温度漂移和工艺差异带来的相位漂移。如果不做校准,PWM照样能出,但边沿抖动会变大,移相精度打折扣。校准方法是使能DLL的校准使能位,然后等待硬件置位DLLRDY标志。这个校准过程在上电后通常需要一小段时间,我一般放在系统初始化里,等校准完成后再启动HRTIM波形输出。

初始化时基的代码如下,注意时基单位是HRTIM时钟计数:

/* HRTIM已配置为170MHz时钟源,1计数 = 5.88ns */ /* 200kHz开关频率,周期5us,对应850个计数 */ sTimerBaseConfig.Period = 850 - 1; HAL_HRTIM_TimerBaseConfig(&hhrtim1, HRTIM_TIMERID_TIMER_A, &sTimerBaseConfig); sTimerBaseConfig.Period = 850 - 1; HAL_HRTIM_TimerBaseConfig(&hhrtim1, HRTIM_TIMERID_TIMER_B, &sTimerBaseConfig);

这里有一个容易被忽略的点:HRTIM的周期寄存器通常要写入“周期计数减1”,类似PWM周期寄存器的ARR。我第一次就是在这里多写了一个计数,导致实际频率跑到了198.8kHz,调试了半天才反应过来。

3.2 关键寄存器:用TA的比较事件锁住TB周期起点

移相的核心机制是让TB的计数器周期起点不固定在自己周期的0点,而是被TA的某个比较事件“强行复位”。这样TB看着还是850个计数一个循环,但实际上它的起始相位完全由TA的CMP4xR寄存器的值决定。

具体配置分两步。第一步,设置TA的CMP1xR寄存器为半周期425个计数,用来产生TA输出通道的50%占空比。第二步,把TB的复位源字段TBRST配置成“TA的比较器4事件”,然后通过更新TB的CMP4xR寄存器来动态改变TB的起点。

假设CMP4xR初始设为425,也就是半个周期,那么TB从周期中点才开始计数。TB自己的CMP1xR也设为425,它输出50%占空比的高电平就会从425计数点一直持续到850。当你把这串波形和TA波形放到一起看,TA和TB正好反相,相当于移相角为0,全桥满占空比运行。此时把CMP4xR往0方向减小,TB整体前移,移相角增大,有效占空比下降;往425方向增大的行为是对称的,实际控制中我一般只使用0到425区间。

这个思路的代码框架:

/* TA驱动左桥臂:CMP1决定50%占空比 */ hhrtim1.Instance->sTimerxRegs[HRTIM_TIMER_INDEX_A].CMP1xR = 425 - 1; /* 右桥臂TB的复位源选择:TA的比较器4事件 */ hhrtim1.Instance->sCommonRegs->RSTR |= HRTIM_RSTR_TBRST(HRTIM_RSTR_TBRST_TA_CMP4); /* TB的CMP1决定自身的50%占空比 */ hhrtim1.Instance->sTimerxRegs[HRTIM_TIMER_INDEX_B].CMP1xR = 425 - 1; /* TB的CMP4就是移相角寄存器,初始为半周期=满占空比 */ hhrtim1.Instance->sTimerxRegs[HRTIM_TIMER_INDEX_B].CMP4xR = 425 - 1;

注意上面代码里RSTR寄存器的位段定义,不同HAL库版本宏有些差异,但原理一致。关键是要理解:TB的“周期起点”被TA_CMP4事件锁住后,TA_CMP4的值就等于TB相对TA的相位差。

最后用一句大白话总结这个机制:TA负责给自己限宽,同时用CMP4打一个可移动的“标记点”,TB看到这个标记点就重新开始数数,于是标记点在哪,TB的波形就跟到哪。

3.3 死区生成器的方向设置与时间换算

HRTIM的死区配置在定时器的死区生成器上,每个输出通道都有独立的上升沿死区延时和下降沿死区延时。对于同一对互补输出,正确设置方式是对上下管的导通沿同时插入延时。

很多第一次用HRTIM的人会在这一块犯迷糊,搞不清DTR和DTD到底对应哪个沿。我的记忆方法是:任何输出通道,它的原始波形上升沿到来时,实际输出要延迟DTR个时钟;原始波形下降沿到来时,实际输出要延迟DTD个时钟。对于一对互补的PWM,上管的下降沿和下管的上升沿是同一个逻辑切换点被劈成两个方向的,所以你只需要统一把所有输出通道的DTR和DTD都设成相同的值,插入的开关间隔自然就是对称的。

sDeadTimeConfig.DeadTimeRising = 22; /* 130ns / 5.88ns ≈ 22计数 */ sDeadTimeConfig.DeadTimeFalling = 22; HAL_HRTIM_DeadTimeConfig(&hhrtim1, HRTIM_TIMERID_TIMER_A, &sDeadTimeConfig); HAL_HRTIM_DeadTimeConfig(&hhrtim1, HRTIM_TIMERID_TIMER_B, &sDeadTimeConfig);

死区时间往寄存器里填的时候用除法计算,这一点一定不要心算省掉。130ns除以5.88ns是22.1,取整22,实际死区约129ns,误差可以接受。如果将来开关频率更高,比如250kHz或300kHz,时基不够的话可以打开HRTIM的分频,但代价是相位分辨率下降,属于权衡。

3.4 动态更新移相角:预装载与同步

移相全桥是闭环控制,所以CMP4xR不是设一次就不管了,而是每个控制周期都要更新。如果更新时机不对,比如在TB计数过程中临时改了复位点,那么当周期走到一半时,复位事件突然到来,TB会立刻归零重新计数,输出波形就会多出一个不该有的窄脉冲。

解决办法是利用HRTIM比较寄存器的预装载功能。打开CMP4xR的预装载,写入的值先锁存到影子寄存器,然后在更新事件(通常是周期溢出)到来时才统一生效。这样就能保证波形永远是完整周期级别的变化,不会在周期中间发生突变。

使用库函数的方式:

/* 使能TB的CMP4预装载 */ HAL_HRTIM_WaveformCompareConfig(&hhrtim1, HRTIM_TIMERID_TIMER_B, HRTIM_COMPAREUNIT_4, &sTimerCompareConfig); /* 其中sTimerCompareConfig.CompareValue每次动态写入 */

在中断里更新移相角时,写入CMP4xR后不需要额外操作,硬件会在下一个更新事件自动锁存。前提是你必须确保CMP4xR预装载已经打开,否则写进去立刻生效,问题就是这个“立刻”不可控。

另外,CMP4xR的写入最好放在周期中断或ADC转换结束中断里,而不是在控制算法的任意节点直接赋值。这样写表面上看没毛病,实际会把更新时刻的抖动带进控制系统,造成周期时间不确定,反馈环路表现极差。

4. ADC触发与闭环控制:高精度PWM不能配慢反馈

4.1 用HRTIM事件确定ADC采样窗口

移相全桥的原边电流波形每个开关周期都有一段震荡和换流过程,如果ADC在任意时刻采样,得到的数据基本没法用。要拿到稳定的反馈量,必须把采样窗口精准放在电流平台最平整的地方。

HRTIM的优势在于它可以把定时器的比较事件直接映射成ADC触发信号。我用的方案是让TA的CMP1事件(也就是左桥臂占空比翻转点附近)触发ADC1注入组采样。这个点通常在变压器原边电流进入平台期的中间位置,避开了两个桥臂的死区换流窗口,采样出来的电流和电压波动都很小。

还有更进阶的做法:用HRTIM的延时事件做二次触发,让ADC采样比主事件延迟几十ns到几百ns,从而微调采样点。实测下来这个特性非常有用,尤其是在原边电流波形有轻微振铃时,挪动几十个ns就能显著改善采样稳定性。

ADC触发配置在CubeMX里就能看到HRTIM1的ADC trigger选项,选择Timer A Compare 1作为触发源,触发注入组,采样序列里放入输出电压和电流反馈两个通道。这个配置跑起来后,你会在每个PWM周期都获得一组反馈值,频率和开关频率一致,非常适合做200kHz的数字控制环。

4.2 数字PID与移相角限幅、软启动

有了每个周期同步的ADC数据,控制部分就变成标准的数字电压环。我用的增量式PID,在200kHz的PWM中断里运行,输出量直接作为CMP4xR的修正值。

这里有一个特别重要的工程细节:移相角寄存器的更新要和PID输出限幅绑在一起,同时还需要给移相角本身设上下限。上限是半周期计数附近,也就是满占空比状态,不能让它突破到超过半周期,否则移相逻辑会进入对称区,占空比反而掉头;下限设在接近0的位置,防止空载时有效占空比过小,变压器进入不稳定断续状态。

软启动也不能省。全桥电路直接满占空比启动,冲击电流和变压器饱和风险都很大。我的做法是上电后让移相角从最大值(接近0占空比)缓慢减小,以固定步进朝目标移相角逼近,同时实时监测原边电流,如果电流超过设定阈值就暂停步进,等待电流回落。每100us更新一次移相角,整个软启动过程控制在10ms到20ms左右。

4.3 片内比较器与刹车保护联动

G474最大的一个福利是内部集成了数个模拟比较器,这些比较器的输出可以直接送到HRTIM的刹车输入,不需要经过CPU判断。我配置了一路COMP1检测原边电流过流,正端接电流采样信号,负端由DAC提供一个阈值电压,当电流超出阈值,COMP1翻转,HRTIM立即封锁全部输出。

这个保护路径的延时只有几十ns,比在ADC中断里判断再关PWM快几个数量级,是真正能救管子的保护。配置时要注意把刹车模式设为锁存型,也就是一旦触发,输出电平一直保持封锁,直到软件确认故障并重新初始化。如果设成自动恢复,故障源没有清除时PWM会反复重启,故障电流一次比一次大,极其危险。

另外,HRTIM还支持PWM输出与刹车事件之间的硬件联动,可以在封锁PWM的同时触发ADC中断记录故障时刻的状态量,方便定位问题根源。这部分我后来在整机测试中排查浪涌原因时帮了大忙。

5. 实测数据与调试中踩过的坑

5.1 200kHz/2kW样机的关键实测数据

样机参数:输入380V直流电,输出48V/40A,开关频率200kHz,变压器变比按副边输出余量选,原边移相角由闭环自动调节。整机控制只用一片STM32G474,没有附加任何外部PWM发生电路。

满载效率在95%以上,峰值效率出现在半载附近,约96%。动态负载从10%跳变到90%,输出电压恢复时间在150us左右,移相角响应没有明显过冲。示波器观察原边桥臂中点电压波形,死区时间内电压翻转干净,ZVS状态在满载到50%负载范围内基本保持。移相角度稳定性方面,在室温下用统计模式观察相位抖动,长期观察没有跑出一个时基计数(约0.42度)的范围,开启DLL后抖动进一步收窄。

这些数据说明,G474的方案在大功率移相全桥上是完全立得住的,不只是能出波形的级别,而是可以做到和DSP方案同样优秀甚至更细的移相精度。

5.2 坑1:相位寄存器中间状态导致的脉冲毛刺

调试过程中最诡异的一个问题是:闭环一开启,原边电流波形偶尔出现一个很窄的尖峰,像是隔几个周期随机冒出来的。用示波器连续触发的时候,能看到HRTIM的某一路输出偶尔多出一个异常脉冲,宽度只有一两个时基计数。

排查过程来回折腾了很久,最后定位到是CMP4xR的更新没有做预装载同步。当时我直接在一个ADC中断里往里写新移相角,结果硬件有时候在TB计数到中间时收到新值,复位事件当场生效,TB立刻归零,输出自然就多跳了一下。

这个问题的修复其实很简单,就是前面提到的打开CMP4xR预装载,并且只允许在周期更新事件后写入移相角。修完后再看波形,异常窄脉冲彻底消失。这个坑提醒我,HRTIM的寄存器能力很强大,但使用前必须先弄清楚哪些寄存器是立即生效、哪些是预装载生效,不要想当然。

5.3 坑2:死区方向设置反转引发的直通

死区方向设置反掉的经历,比脉冲毛刺更让人冒冷汗。那次是改了一版PCB,换了一款栅极驱动芯片,驱动芯片的正逻辑输入变成了负逻辑,我简单调整了PWM输出极性,忘了重新看死区插入方向。

结果一上电,桥臂中点波形直接出现明显的上管和下管同时导通的凹陷,伴随着热成像里的桥臂升温异常,好在电流限制保护介入及时,没有真正烧掉管子。后来抓波形,发现死区插入到了错误的边沿,原本应该“先关断上管、再延时开通下管”的逻辑,变成了“上管关断同时下管也准备开通”,失去了死区保护的意义。

排查方式是直接用示波器A/B通道分别看上下管栅极波形,放大到ns级观察两个下降沿和上升沿之间的间隔。死区设置正常时,上下管驱动之间应该有一个明确的“同时为低”区间,如果看到某个时刻两条波形电平都是高的,说明插入方向反了。修复就是要确保上管下降沿到下管上升沿之间的延迟大于0,并且下管下降沿到上管上升沿之间同样如此。

5.4 坑3:ADC采样窗口被开关振铃淹没

闭环调好后,发现数字PID在稳定电流输出时波动特别大,表现为输出电压纹波正常,但ADC读取值来回跳,导致环路很不稳定。

用示波器对比电流波形和ADC实际采样时序时才发现,HRTIM触发的ADC采样点正好落在桥臂换流振铃的尾巴上,振铃虽然没有击穿器件,但幅值仍然能对采样电容产生干扰。解决办法就是前面提到的HRTIM事件延时调整,把采样点往后挪了大约150ns,彻底避开了振铃区间,ADC数据马上变得平稳,PID输出也不再抖动。

如果你的调试现场也出现类似问题,建议先把反馈环断开,单纯看ADC采样值是否稳定,再把采样点往平台区中间方向慢慢挪。这个处理顺序能帮你快速区分是模拟采样问题还是数字控制问题。

最后再分享一个调试小技巧:HRTIM的每个定时器都有独立的比较事件标志位,调试时可以把这些事件引到空闲引脚上,用示波器直接观测移相角更新的实际时刻。这样你就不是全靠猜,而是能亲眼看着TA_CMP4事件和TB复位事件之间的时间差,和你代码里设置的数字是否一致。我后来做任何HRTIM相关的项目,都会先干这一步,能省掉至少半天的排查时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询