基于STM32G474高精度定时器HRTIM的高频开关电源移相控制实现
1. STM32G474的HRTIM为何是高频电源设计的利器
第一次接触STM32G474的高精度定时器HRTIM时,我正被DSP28335的分辨率问题困扰。当时做的1MHz开关电源项目,150MHz主频的DSP每个时钟周期只能提供150个计数点,调节精度捉襟见肘。直到发现HRTIM的5.44GHz等效时钟频率——这意味着在1MHz开关频率下,每个周期可以分成5440个时间点,分辨率高达184皮秒!
这种变态的参数背后是STM32G474专门为数字电源设计的架构。与普通定时器不同,HRTIM包含1个主定时器和6个子定时器(Timer A-F),所有定时器都能独立工作或相互同步。最惊艳的是它的"时间分辨率放大器"技术,通过数字锁相环(DLL)将170MHz系统时钟倍频32倍,同时保持极低的抖动。
实际测试LLC谐振变换器时,用HRTIM实现的移相控制能让效率提升3%左右。这得益于其精确的死区时间控制——比如需要100ns死区时,普通定时器只能给个近似值,而HRTIM可以精确到184ps的整数倍。有次调试全桥电路,就是靠这个特性完美避开了MOSFET的共导问题。
2. 移相控制的核心配置技巧
2.1 定时器级联的黄金法则
实现移相的关键在于主定时器与子定时器的联动。我的常用配置模式是:主定时器作为时基发生器,通过比较器事件触发子定时器复位。具体到移相全桥,通常让Timer A和Timer E组成一对互补输出,Timer B/D作为另一对,相位差通过主定时器的比较器值来调节。
配置时要特别注意几个寄存器:
// 主定时器比较值设置相位差 pCompareCfg.CompareValue = Phase_shift_ticks; HAL_HRTIM_WaveformCompareConfig(&hhrtim1, HRTIM_TIMERINDEX_MASTER, HRTIM_COMPAREUNIT_1, &pCompareCfg); // 子定时器复位触发源配置 pTimerCfg.ResetTrigger = HRTIM_TIMRESETTRIGGER_MASTER_CMP1; HAL_HRTIM_WaveformTimerConfig(&hhrtim1, HRTIM_TIMERINDEX_TIMER_B, &pTimerCfg);2.2 死区时间的纳米级管理
死区时间是电源设计的生死线。HRTIM的死区控制寄存器堪称艺术品,可以分别设置上升沿和下降沿的延迟。这里有个易错点:死区值需要换算成HRTIM的时钟周期。例如要实现100ns死区:
// 计算公式:死区ticks = 所需时间(ns) / 0.184 uint16_t DeadTimeTicks = (uint16_t)(100 / 0.184); pDeadTimeCfg.RisingValue = DeadTimeTicks; HAL_HRTIM_DeadTimeConfig(&hhrtim1, HRTIM_TIMERINDEX_TIMER_A, &pDeadTimeCfg);实测中发现,当开关频率超过500kHz时,建议开启HRTIM的预装载功能,可以避免更新寄存器时的毛刺:
pTimerCfg.PreloadEnable = HRTIM_PRELOAD_ENABLED; pTimerCfg.UpdateGating = HRTIM_UPDATEGATING_INDEPENDENT;3. 多通道PWM同步实战
3.1 GPIO配置的隐藏陷阱
虽然数据手册标明了HRTIM的复用功能,但引脚配置有几个坑我踩过:
- GPIO速度必须设为Very_High,否则高频PWM边沿会有畸变
- PC6/PC7的AF映射与其他引脚不同,需要单独配置
- 输出模式必须选择AF_PP(推挽复用),普通推挽模式无法工作
正确的初始化示例:
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF13_HRTIM1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);3.2 移相全桥的典型配置
以400kHz的移相全桥为例,需要配置两对相位差180°的PWM。关键参数计算:
- 主定时器周期值 = 5.44GHz / 400kHz = 13600 ticks
- 移相90°对应的比较值 = 13600 / 4 = 3400
- 死区时间设为80ns → 435 ticks
具体代码结构:
// 时基配置 pTimeBaseCfg.PrescalerRatio = HRTIM_PRESCALERRATIO_MUL32; pTimeBaseCfg.Period = 13600; HAL_HRTIM_TimeBaseConfig(&hhrtim1, HRTIM_TIMERINDEX_MASTER, &pTimeBaseCfg); // 移相设置 pCompareCfg.CompareValue = 3400; // 90°相位差 HAL_HRTIM_WaveformCompareConfig(&hhrtim1, HRTIM_TIMERINDEX_MASTER, HRTIM_COMPAREUNIT_1, &pCompareCfg); // 输出极性配置(互补通道) pOutputCfg.Polarity = HRTIM_OUTPUTPOLARITY_HIGH; pOutputCfg.SetSource = HRTIM_OUTPUTRESET_TIMCMP1; pOutputCfg.ResetSource = HRTIM_OUTPUTSET_TIMPER;4. 高频电源的进阶技巧
4.1 ADC同步采样黑科技
HRTIM最让我惊喜的功能是硬件级ADC触发。在LLC谐振变换器中,我通常在主定时器比较点触发ADC采样,这样可以精准捕捉MOSFET关断时刻的谐振电流。配置要点:
// 设置TIMER A的比较器3作为触发源 pADCTriggerCfg.UpdateSource = HRTIM_ADCTRIGGERUPDATE_TIMER_A; pADCTriggerCfg.Trigger = HRTIM_ADCTRIGGEREVENT13_TIMERA_CMP3; HAL_HRTIM_ADCTriggerConfig(&hhrtim1, HRTIM_ADCTRIGGER_1, &pADCTriggerCfg); // 在中断中读取ADC值 void HRTIM1_TIMA_IRQHandler(void) { if(HRTIM1->sTimerxRegs[HRTIM_TIMERINDEX_TIMER_A].TIMxISR & HRTIM_TIM_IT_CMP3) { adc_val = HAL_ADC_GetValue(&hadc1); // 实时控制算法... } }4.2 动态调节的注意事项
当需要实时调整频率或占空比时,直接写寄存器会产生风险。安全做法是:
- 先停止主定时器
- 更新PERxR/CMPxR寄存器
- 设置UPDGAT位触发更新
- 重新使能定时器
// 安全更新频率示例 HAL_HRTIM_TimeBaseStop(&hhrtim1, HRTIM_TIMERINDEX_MASTER); HRTIM1->sMasterRegs.MPER = new_period; HRTIM1->sMasterRegs.MCR |= HRTIM_MCR_UPDGAT; HAL_HRTIM_TimeBaseStart(&hhrtim1, HRTIM_TIMERINDEX_MASTER);调试高频电源时,建议用示波器监控HRTIM的SYNC_OUT引脚,可以直观看到定时器的同步状态。有次诡异的相位抖动问题,就是通过这个发现是DLL校准未完成导致的。
