做中大功率DC-DC变换,绕不开移相全桥;用STM32G474做移相全桥控制,绕不开HRTIM。这两个词放在一起,基本就是一台数字电源控制器的核心骨架:HRTIM负责产生高分辨率PWM,移相全桥负责把能量从原边高效搬到副边。这篇文章我从实际项目的角度,把STM32G474的HRTIM配置移相全桥的完整思路写清楚,包括拓扑原理、各定时器单元怎么分工、移相角怎么在寄存器上实现、闭环和调试时最容易踩的坑,给正在做通信电源、车载充电、电池充电机,或者刚开始入门数字电源的嵌入式工程师一个可以直接参考的控制方案。
1. 移相全桥和HRTIM:为什么非要这对组合
1.1 移相全桥到底在做什么
先简单过一遍拓扑,免得后面讲控制的时候还要回头查概念。移相全桥的功率级由原边四个开关管、一个高频变压器、原边谐振电感和副边整流电路构成。四个开关管按桥式连接,每个桥臂上下两只管子互补导通,两个桥臂之间通过“移相”来传递能量。
正常工作时,变压器原边得到的是一个交流方波。两组对角开关管交替导通,例如Q1和Q4先同时导通,然后切换为Q2和Q3同时导通。关键点在于,每个开关管的占空比基本固定在接近50%,并不像普通全桥那样通过调制脉宽来控制输出,而是通过调节两个桥臂之间的相位差,也就是“移相角”来控制变压器原边方波的有效宽度。移相角越大,原边加在变压器上的等效脉冲宽度越窄,副边输出电压越低。移相角为零时,输出最大,等效占空比接近1。
移相全桥最大的价值在于软开关。超前桥臂的开关管在切换时,可以利用变压器原边电流给开关管寄生电容充放电,使开关管两端电压先降到零再开通,也就是ZVS零电压开通。滞后桥臂的ZVS条件稍差,因为换流时原边电流可能已经衰减,需要依靠谐振电感储存足够的能量来完成换流。所以谐振电感的设计、死区时间的设置,以及移相角小角度工况下的控制策略,直接决定整个电源的效率。
从控制器的角度看,我需要做的就是稳定产生四路PWM,让两个桥臂的相位差可实时调节,同时保证窄脉冲条件下波形质量不劣化。这个需求听起来简单,但用普通定时器做起来并不舒服。
1.2 普通PWM定时器为什么不够用
STM32G4系列也有TIM1这类高级定时器,同样支持互补输出和死区插入。如果只是点亮LED或者驱动一个简单buck,TIM1绰绰有余。但放到移相全桥上,问题就来了。
第一个问题是分辨率和抖动。移相全桥工作频率通常在100kHz上下,一个开关周期只有10微秒。主频170MHz下,计数器一个tick是5.88ns,换算成相位大约是0.21度。如果这个分辨率用在电流内环或者高精度电压环上,勉强够用,但普通定时器的比较事件触发从定时器复位、多定时器级联,在硬件上并没有专门为移相应用做过优化,实际PWM边沿抖动很容易超过几个tick。边沿抖动叠加到输出电压上,会体现为额外的纹波和噪声。
第二个问题是多路联动的复杂度。移相全桥需要两个桥臂的PWM保持严格同步关系,超前桥臂的周期要稳定,滞后桥臂相对超前桥臂要有一个精确可控的延迟。用普通定时器做这个延迟,要么让滞后桥臂定时器工作在从模式等待外部触发,要么配置繁琐的触发链路,稍不注意就会出现相位突变和毛刺。调试起来非常痛苦。
第三个问题是保护响应速度。过流保护要求PWM在几百纳秒内关断,普通定时器的刹车输入虽然能用,但要同时处理多路输出、死区状态和故障锁定,配置起来比较绕。HRTIM专门为这类场景设计,故障输入、输出强制状态、故障锁定、清除机制都是现成的。
1.3 STM32G474 HRTIM的高分辨率从哪来
HRTIM设计的目标场景就是数字电源,所以它内置了多路定时器单元、丰富的交叉联动、死区生成、故障输入和ADC同步触发。STM32G474的HRTIM最高可输出10路PWM? 实际上一个HRTIM模块包含多个Timer单元,每个单元有A/B两路输出,整体足够覆盖三相逆变器、两路交错PFC、全桥LLC、移相全桥这类拓扑。
所谓最高分辨率184ps,并不是说主计数器时钟被倍频到5GHz以上。HRTIM的粗调边沿仍然由170MHz主计数器产生,也就是5.88ns步进;但在边沿输出路径上,集成了一条经过校准的延迟线,可以把一个计数器时钟周期再细分成若干小段,从而对PWM输出边沿进行精细调整。这个延迟线经过校准后,就可以在比较值对应的整数tick基础上,再叠加一个亚纳秒级别的延迟值,最终实现约184ps的等效PWM分辨率。
用更直白的话说:150kHz频率下,普通定时器只有约1700个tick可调,而HRTIM有将近25万个等效相位点。移相全桥未必每次都用到这么极端的分辨率,但高分辨率意味着更精确的死区时间、更稳定的相位步进、更低的输出电压纹波。尤其在需要兼顾轻载和重载效率,死区时间要反复微调的时候,1tick对应5.88ns的粗调会让你很难受,而HRTIM可以做到精细得多的调整。
2. 整体方案设计:定时器单元怎么分配
2.1 系统架构与器件选型脉络
先把我实际做的这个系统骨架摆出来,方便对照。控制核心选择STM32G474RET6,主频170MHz,内置HRTIM、多个高速比较器COMP、DAC、ADC,基本把模拟外设和数字外设都集齐了。功率部分是一个典型的移相全桥DC-DC,输入400V左右,输出48V/30A,开关频率100kHz,变压器原边串接一个谐振电感,副边采用全桥整流加LC滤波。
在这个系统里,电压采样通过电阻分压送到ADC,电流采样通过电流互感器加运放放大后送到ADC以及比较器COMP。COMP的参考电压由内部DAC提供,当原边电流超过设定阈值时,COMP输出立即触发HRTIM的Fault输入,硬件级关断PWM。这个保护链路不需要软件参与,是数字电源最重要的安全保障。
控制环路上,外环采样输出电压,经过PI调节得到移相角指令,内环视情况采样原边电流或输出电感电流。电压环带宽大约几kHz,控制周期设置在20微秒到50微秒之间。移相角指令最终映射成HRTIM主定时器的比较值,从而改变滞后桥臂相对超前桥臂的相位。
2.2 三个定时器单元的分工逻辑
HRTIM里有TIMA到TIMF多个定时器单元,移相全桥其实只需要两个单元输出PWM,但我习惯用三个:TIMA做周期基准,TIMC做超前桥臂,TIMD做滞后桥臂。
TIMA不直接驱动功率管,只作为全系统的时基主定时器。它在连续升降计数模式下工作,产生一个100kHz的三角载波。TIMA的比较寄存器CMP2的值用来控制滞后桥臂的复位触发时刻,也就是移相角。
TIMC负责超前桥臂的上下管,A和B两路输出互补,占空比接近50%,中间插入死区。这个桥臂的计数和TIMA保持同步复位,所以它是整个系统的相位参考。TIMD负责滞后桥臂的上下管,配置方式和TIMC完全相同,区别在于它的计数器复位源不是TIMA的周期事件,而是TIMA的CMP2比较事件。这样,TIMA的CMP2值决定TIMD每次从零开始计数的时刻,相当于把滞后桥臂整体向后平移了一个相位。调整移相角时只需要修改TIMA的CMP2寄存器,简单直接。
还有多余的定时器单元也不浪费,比如TIME可以用于生成同步整流管的驱动信号,TIMF用于产生辅助电源或风扇的PWM,或者作为故障触发额外备份。不做过多冗余设计,但HRTIM多通道天然支持这类扩展。
2.3 关键参数计算:开关频率、死区、移相量化
系统主频170MHz,开关频率100kHz。我选用连续升降计数模式,也就是up-down模式,这样PWM输出是中心对齐的,对ZVS软开关友好一点。在这种模式下,定时器从0升到周期值PER,再从PER降到0,完整走完一个三角形载波才是一个开关周期。
周期寄存器的计算是:
PER = fHRTIM / (2 × fsw) = 170MHz / (2 × 100kHz) = 850所以PERIODR设为850。计数器从0到850再到0,一共1700个tick,正好对应10微秒的开关周期。一个tick长度是5.88ns。
死区时间的确定取决于功率管和驱动电路的实际参数。我用的MOSFET栅极电荷适中,驱动关断延迟加上米勒平台时间大约150ns,再留一定余量,死区设在300ns。换算成tick数量:
死区tick = 300ns / 5.88ns ≈ 51这个值直接写入HRTIM的死区寄存器。注意这只是粗调值,如果后续要优化轻载效率,还可以用延迟线对死区进行亚纳秒级别的微调,我后面会再提。
移相角的量化需要先看主定时器的工作方式。由于TIMA是up-down模式,一个比较事件在每个三角载波周期里会出现两次,一次在上升段,一次在下降段。配置HRTIM比较事件触发方向时,要确保只用上升沿方向比较事件去复位TIMD,否则滞后桥臂一个周期会被复位两次,波形直接乱掉。只取上升段事件的话,移相角范围0到180度,正好对应CMP2从0到850。CMP2每增加1,移相角变化:
Δφ = 360° / 1700 ≈ 0.212°对应到有效占空比,相当于一个tick宽度5.88ns与10微秒周期之比,约为0.06%的占空比步进,做稳压控制已经足够。如果要求更细,可以用HRTIM的延迟单元去微调CMP事件到复位信号之间的延迟,等效于把相位步进再细分到约0.0066度级别。这个功能在需要极高相位精度的场景很管用,但我实际项目里很少用到极限值。
3. 关键配置实操:把HRTIM的PWM跑起来
3.1 用CubeMX搭出主体框架
我平时习惯用STM32CubeMX先生成工程框架,再把关键寄存器改成自己需要的配置。这样既能保证时钟树和引脚映射正确,又不会因为HAL封装的层级太厚而迷失。
时钟树配置里,SYSCLK选170MHz,APB1和APB2也要确认到170MHz。HRTIM挂在APB2上,必须保证APB2定时器时钟没有分频,否则HRTIM计数频率就不是170MHz,直接导致所有频率和死区参数整体偏移。
CubeMX里HRTIM的配置入口在Timers分类下。先添加HRTIM1,然后在Timer A、Timer C、Timer D三个子页面分别配置。
TIMA配置要点:计数模式选Continuous up-down,周期850,不启用输出。TIMC和TIMD配置要点:都设置为由外部事件复位,TIMA周期复位TIMC,TIMA的CMP2事件复位TIMD。输出A和B配置为互补PWM,使能Dead-Time Insertion,上升沿和下降沿死区都填51。
需要注意,CubeMX里HRTIM的很多寄存器位和HAL结构体字段命名比较绕,配置完最好切到生成的代码里确认一遍实际寄存器赋值,特别是复位源和置位源,出问题很难一眼看出来。
3.2 主定时器周期基准配置
主定时器TIMA的核心作用就是提供一个稳定、无抖动的三角载波周期。它本身不输出PWM,但整个系统的相位基准都挂在它的计数方向上。
周期寄存器PERIODR直接写入850。还需要配置预装载功能,让周期值在影子寄存器中更新,在周期边界统一生效。比较寄存器MCMP2R是移相角的控制入口,同样开启预装载。这样在ISR里修改MCMP2R时,新值不会立刻写入,而是在下一个周期边界一致更新,从源头上避免移相角在周期中途跳变产生的窄脉冲。
从代码角度看,关键寄存器大致是:
// 使能HRTIM时钟 RCC->APB2ENR |= RCC_APB2ENR_HRTIM1EN; // TIMA:up-down计数,周期850 HRTIM1->TIMACR |= HRTIM_TIMACR_PREEN; // 预装载使能 HRTIM1->TIMAPER = 850; // 配置计数模式字段,使TIMA工作在连续升降计数3.3 超前桥臂与滞后桥臂的PWM输出配置
这两个桥臂的配置几乎完全对称。TIMC和TIMD都工作在up-down计数模式,周期仍由各自的PERIODR决定。由于它们被TIMA的事件周期性复位,实际上周期跟随TIMA走,PERIODR也要写成850保持一致。
桥臂输出波形的基本逻辑:在一个三角形载波周期内,输出A先高后低,输出B与之互补。占空比不需要刚好50%,因为死区时间会吃掉一部分导通区间。比如我期望上管有效占空比48.5%,下管也是48.5%,中间3%周期被死区占掉,这个比例通过比较寄存器CMP1和CMP2设置。
典型配置思路是用下面几句话概括:输出A的置位事件来自某个计数方向上的比较匹配,复位事件来自另一个计数方向上的比较匹配;输出B复用同样的比较逻辑,再经死区生成器生成互补的边沿延迟。实际操作中,置位和复位源都通过TIMxSETR和TIMxRSTR寄存器配置,可以选择本地比较事件,也可以选择其他定时器的比较事件。这里也是配置最容易出错的地方,建议严格按照参考手册中“Timer Set/Reset Mapping”的表格逐项核对。
死区生成器在输出A到输出B之间插入延迟。配置成300ns后,实测波形就能看到上下管切换之间有一段双低电平区间。如果做同步整流,还需要额外考虑反向体二极管导通时间,死区不能一味求小。
3.4 移相角在线调节方法与代码骨架
移相角的实时调节是我整个方案的核心。我把TIMA的CMP2值当作移相角控制量,CMP2的取值范围限制在0到850之间。CMP2=0时,TIMD与TIMC同相,输出最大;CMP2=850时,相位差180度,原边等效脉冲宽度被压缩到接近零,输出接近零。
在中断服务函数里更新移相角的代码骨架大致如下:
// 电压环PI输出限幅后,映射为CMP2值 static uint32_t phase_cmp; void VoltageLoopISR(void) { float err = vout_ref - vout_meas; integral += ki * err; float out = kp * err + integral; // 限幅0~850,对应0~180度 if (out > 850.0f) out = 850.0f; if (out < 0.0f) out = 0.0f; phase_cmp = (uint32_t)out; // 更新主定时器CMP2,预装载会在周期边界加载 HRTIM1->MCMP2R = phase_cmp; }这段代码看起来简单,背后有几个必须注意的点。首先是预装载,如果MCMP2R没有配置影子寄存器更新,可能在任意时刻直接写入当前计数周期,导致移相角跳变。其次是限幅,移相角不能超过180度,否则原边会进入环流状态,不仅输出电压无法继续降低,还会白白增加损耗。第三是更新频率,电压环一般几十微秒执行一次即可,不要每个PWM周期都修改移相角,否则容易引入不必要的电磁干扰噪声。
3.5 ADC联动触发与闭环控制衔接
数字电源的性能很大程度上取决于采样时刻是否精确。HRTIM与ADC的联动机制可以直接在硬件层面解决这个问题,不需要用定时器中断去触发ADC。
我配置为TIMA在周期边界附近产生一个ADC触发事件,让ADC在PWM死区结束、开关管完全导通后采样输出电压。这个时刻的电压纹波相对平稳,采集到的值更接近输出电压平均值。如果采样点正好落在开关边沿上,ADC结果会叠加大量开关噪声,闭环效果会非常差。
ADC转换完成后进入中断,在中断里做电压环PI运算并更新移相角。整个链路从采样到输出更新的延迟大约几个微秒,对几kHz带宽的电压环来说绰绰有余。如果需要电流内环,可以再配置一个ADC触发事件,在超前桥臂导通中点采样原边电流,进一步加快动态响应。
4. 常见问题与排查技巧实录
4.1 上电后PWM无输出
这是新板子最容易遇到的问题。HRTIM虽然功能强大,但输出使能链路比较长,任何一个环节没配置好,输出就是静默的。
优先级最高的是Fault输入没有清除。HRTIM一旦检测到故障输入有效,输出会被强制到预设的安全状态并锁存。调试时如果COMP比较器误触发,或者FLT引脚上拉电阻没处理好,上电瞬间就会锁死PWM。检查方法是看故障标志寄存器,如果置位了,先解除故障原因,再软件清除锁存。
其次是输出使能位。HRTIM每个定时器单元的A/B输出都有独立的输出使能位,必须把OUTA和OUTB置1。同时还要确认没有处于外部控制模式,否则输出电平由外部事件控制,配置了PWM比较逻辑也不会生效。
最后是预装载和更新事件。如果影子寄存器一直没有被更新加载,比较值始终是初始值0,输出可能保持恒高或恒低,看起来就像没有PWM。这种问题在波形上是能看出来的,用示波器测输出会发现电平有,就是没有翻转。
4.2 移相角更新无效或波形跳动
移相角更新无效,首先怀疑MCMP2R的影子寄存器配置。如果预装载没有开启,MCMP2R是立即写穿的,虽然看起来也能工作,但在某些计数位置写入会导致滞后桥臂的复位事件丢失,上一拍和下一拍的周期长度都不一样,波形出现抽动。
波形跳动还有一个原因,就是TIMA的CMP2比较事件如果取错了计数方向。前面说过,up-down模式下同一个CMP值在上升段和下降段各触发一次。如果HRTIM配置成两个事件都去复位TIMD,相当于TIMD在一个开关周期内被复位两次,输出频率直接变成2倍,而且相位无法线性调节。遇到这种异常,先切到单次触发模式看TIMA的CMP事件波形,确认每周期只产生一个有效复位事件。
4.3 死区时间不对导致直通隐患
死区配置最容易出问题的地方是寄存器单位。HRTIM死区寄存器在不同模式下分别代表不同的时间基准:有的是主计数器tick,有的是经过延迟线细分的高分辨率tick。如果混用,300ns需求可能被设置成了300个tick,也就是约1.76微秒,死区过大;或者只设置了30个tick,约176ns,对开关管来说可能不够安全。
我建议上电前先不要接功率级,用示波器直接量两个桥臂输出的Vgs波形,确认死区时间实测值和理论值一致。没有条件量高压侧栅极波形时,至少量HRTIM输出引脚到驱动芯片输入端之间的逻辑波形,也能反映死区设置是否正确。直通问题一旦发生,基本就是炸管,这个环节花几分钟确认非常值。
4.4 带载后效率不佳的排查方向
硬件调通后,效率是移相全桥的终极考验。如果效率上不去,先看滞后桥臂有没有实现ZVS。滞后桥臂切换时,原边电流往往比较小,谐振能量不足,开关管可能还在硬开关状态。外部表现是滞后桥臂开关管温度明显高于超前桥臂。
控制层面能做的调整有几个方向:一是死区时间微调,滞后桥臂的死区窗口要和谐振电感、寄生电容参数匹配,太大太小都会影响ZVS;二是移相角变化速率,负载变化时如果移相角快速穿越ZVS困难区间,动态损耗会明显增加;三是原边最小占空比限制,防止轻载时移相角过大、环流时间过长,导致效率进一步劣化。
5. 调试心得与几个值得留意的细节
5.1 寄存器操作比HAL更直观
STM32CubeG4库的HRTIM驱动封装层级很厚,一个简单的配置可能涉及好几个结构体和几十个字段,用HAL函数逐项设置反而容易搞混。我个人的做法是,用CubeMX生成基础框架后,把HRTIM相关HAL调用全部替换成寄存器直操作。HRTIM寄存器命名其实很有规律,TIMxCR、TIMxPER、TIMxCMP1R、TIMxCMP2R、TIMxRSTR、TIMxSETR、TIMxOUTR,查阅参考手册时思路非常清晰,出问题也好定位。
当然,寄存器直操作对新人来说门槛略高,所以我建议至少先用CubeMX把时钟和引脚跑通,再用寄存器方式做细微调整,两套方法配合着来。
5.2 先空载开环,再上功率闭环
移相全桥调试有一个原则:先小功率、先开环、先去掉闭环。我第一次调试时直接把电压环闭环跑起来,结果输出电压震荡,查了两天才发现是采样点和移相角更新时机不对。
正确顺序是:先把HRTIM配置好,输出固定移相角,接一个很小的负载,确认电压稳定;然后手动改变移相角,观察输出电压是否线性变化,验证相位调节逻辑;确认无误后,再打开PI闭环,同时把PI限幅设得很保守,比如先限制在0到600的CMP值,等系统稳定后再逐步扩大。
5.3 故障保护和恢复逻辑别嫌麻烦
HRTIM的Fault输入设计得很完善,有直接输出强制状态、锁定模式、清除条件等选项。我用比较器COMP检测原边电流过流,COMP输出直接接到HRTIM Fault输入,配置为锁定模式。一旦触发,PWM输出被强制为低,直到软件确认故障源消失并手动清除标志。这个机制在样机阶段救了我好几次,比单纯依赖ADC软件判断快得多也可靠得多。
另外提醒一点,HRTIM的故障优先级高于任何PWM逻辑,包括死区状态。所以故障触发时,上下管都会进入安全状态,不用担心死区逻辑把故障状态掩盖掉。调试过程中如果发现过流保护不触发,先查比较器输出是否真正送到了HRTIM的FLT输入,很多芯片内部连接需要在配置里额外开启。