
前阵子调一块 STM32G484 的小板子客户要求输出 500kHz 的互补 PWM还要带死区和硬件故障封锁。我第一反应是用高级定时器 TIM1频率一拉高波形就开始变毛。后来翻手册发现这颗芯片里的 HRTIM 才是为这种场景准备的折腾完 CubeMX 配置之后把整个过程整理一下包括时钟树、参数设置和生成代码后必须注意的坑。如果你是刚接触 HRTIM这篇文章照着做基本能出波形。1. HRTIM 是什么为什么高频 PWM 场景要选它STM32G484 的数据手册里HRTIM 被放在很靠前的位置因为它不是普通定时器的升级版而是专门给高频功率变换设计的。常规定时器 TIMA、TIM1 这类高级定时器也能输出带死区的互补 PWM但主频一高问题就来了计数分辨率不够死区精度到不了 ns 级故障输入通道也没那么灵活。HRTIM 的全称是 High-Resolution Timer它在 G484 里实际是一组高分辨率定时器簇。一个 HRTIM1 外设内部包含五个独立子定时器标号从 A 到 E每个子定时器又带两路输出加起来最多十路 PWM。这十路信号可以通过内部交叉开关互相触发也可以由片内比较器、DAC、ADC 事件直接驱动。对于数字电源、逆变器、无刷电机这类需要多路高频 PWM 且讲究相位关系的场景通用定时器做起来会很费劲HRTIM 天生就是干这个的。拿普通 TIM1 和 HRTIM1 做对比特性TIM1 高级定时器HRTIM1是否支持互补 PWM支持支持且一个子定时器两路即可最大时钟与系统时钟一致与系统时钟同源可配到 170MHz 级别最小脉宽分辨率取决于分频后的计数周期支持片内高分辨率模式可达亚纳秒量级死区精度计数周期级计数周期级配合高分辨率模式更细故障输入若干固定引脚更灵活支持比较器、外部引脚等事件源子定时器同步靠主从模式内部交叉触发天然适合多相交错这张表不是说 TIM1 不行而是要提醒你如果应用频率普遍在几十 kHz 以下TIM1 完全够用没必要上 HRTIM 自找麻烦。但如果你要做 500kHz 甚至 MHz 级的功率级还想把死区时间精确控到几百纳秒HRTIM 才是正确选择。STM32G484 这颗芯片我就是看中它 HRTIM 和模拟外设的联动能力才选的配置起来复杂度高可回报也高。2. CubeMX 里把 HRTIM 的时钟支路先理清楚我用 CubeMX 配置过不下十块 ST 芯片HRTIM 是少数几个时钟没配好、后面全白搭的外设。普通定时器时钟错了最多是频率不对HRTIM 时钟错了不仅频率不对死区时间、高分辨率模式、事件触发全都可能乱。所以第一步先把时钟树理清楚。打开 STM32CubeMX新建工程选好 STM32G484 的具体型号后第一件事不是去点 HRTIM而是到 Clock Configuration 页面看系统时钟。我习惯先配 HSE 外部晶振作为 PLL 输入然后让 SYSCLK 跑到 170MHz。G484 的主频上限就是 170MHz如果你只是验证功能也可以先用内部 HSI但最终做电源类产品还是建议用外部晶振毕竟 HRTIM 输出 PWM 的抖动和参考时钟直接相关。接下来重点来了在 Clock Configuration 页面里左侧会有一组定时器时钟源HRTIM1 Kernel Clock 是可以单独选的。这里最容易踩坑很多人配完 HRTIM 的周期和死区发现输出频率和计算值差一倍或者完全不对回头一看HRTIM 的 kernel clock 被默认分频成 85MHz 了。我的做法是把 HRTIM1 的 Kernel Clock 直接选到和 HCLK 一致也就是 170MHz。这样后面手算周期、比较值、死区延时都非常方便不用每次再乘一个分频系数。为什么要强调同源因为 HRTIM 里多个子定时器之间要做同步和触发如果主定时器和子定时器用的时钟来自不同的 PLL 输出理论上能工作但相位关系在跨时钟域时很容易出现不确定性。新手阶段不要让 HRTIM 内部出现两个不同的时钟源全部同源先跑通再考虑性能优化。CubeMX 里 RCC 配置不复杂但就是你多看一眼的事节省的却是后面几小时的查错时间。3. 从零到一配置 STM32G484 的 HRTIM 输出互补 PWM3.1 新建工程与选择时钟源这一步顺手提一下新建工程时如果 CubeMX 版本比较老可能找不到 STM32G484。G4 系列支持需要较新的固件包建议直接用 CubeMX 的包管理器把 G4 的固件包更新到较新版本否则会出现器件库缺失的问题。选完芯片后在 Pinout Configuration 左侧的 Categories 列表里找到 Timers展开后能看到 HRTIM1勾选启用它界面里才会出现 HRTIM 的具体参数项。3.2 使能 HRTIM1 并挑选输出通道HRTIM 的参数配置页刚打开时会有 Timer A、Timer B、Timer C、Timer D、Timer E 这些子页签。每个子页签下都有一堆寄存器级选项第一次看会觉得有点吓人。我的建议是先只启用一个子定时器比如 Timer A并且只启用它的两路输出 TA1、TA2。你没看错一个子定时器就能输出两路信号这就是 HRTIM 做互补 PWM 最省资源的地方。启用后在模式选择里把 TA1/TA2 配置成双路互补输出不同版本 CubeMX 的字段叫法可能不一样有的叫 PWM Mode有的叫 Output Mode总之要选带 Dual 和 Complementary 的选项不选这个的话两路输出就是独立 PWM和互补没关系。引脚分配这一层不用太纠结CubeMX 会自动根据芯片封装分配引脚也可以手动改到方便测试的引脚上。3.3 Period 与 Compare 的数值计算在 HRTIM 的参数配置里Timer A 的 Period 字段决定计数器周期Compare 1、Compare 2 这类字段决定输出翻转点。和普通定时器一样实际 PWM 频率的公式是Fpwm HRTIM_CLK / (Period 1)举个例子HRTIM_CLK 为 170MHz想要输出 100kHz那么 Period 1 1700Period 就填 1699。如果想要 50% 占空比比较值可以填 850。Period 字段是 16 位的最大能填 65535所以在 170MHz 下最低输出频率大约是 2.59kHz如果你要更低的频率就得在初始化参数里加入分频再把 Period 放大。这一点很多人会忽略HRTIM 的 Counter Period 是实际计数值不是时间。CubeMX 默认显示的是寄存器值不是纳秒。我第一次用的时候直接填了 1000以为周期是 1 微秒结果示波器一看频率完全不对。后来我就养成了先做计算再填数的习惯宁可写在纸上算完也不要凭感觉在界面上乱填。3.4 死区不是随便填Insertion 与单位换算死区Dead-Time是互补 PWM 里必须认真处理的一件事。HRTIM 的死区设置在子定时器的 Dead Time 区域里通常分为上升沿延迟和下降沿延迟两个参数。这里的单位同样是 HRTIM 时钟周期不是微秒也不是纳秒。170MHz 下一个时钟周期约 5.88ns如果你要插入 200ns 死区计算下来约 34 个周期就填 34。如果填了 200实际死区就是 200 个周期约 1.18us时间直接超了五倍。死区方向也要想清楚。上升沿延迟指的是开通信号延迟下降沿延迟指的是关断信号延迟。对于半桥结构上下管的驱动信号不能同时有效必须保证一路关断后另一路过一段时间再开通这段时间就是死区。很多初学朋友只以为填了死区就安全了其实死区插入方向如果反了或者极性设置不对照样会出现直通风险。我建议先把上升沿和下降沿都设置成相同值不做不对称死区等波形确认没问题再根据功率器件的开关特性去优化。3.5 输出极性和空闲状态正确处理输出极性这个选项看着简单实际影响很大。HRTIM 输出可以配置成高电平有效或低电平有效这个取决于你的驱动电路是正逻辑还是反逻辑。如果驱动电路用的是高电平有效的隔离驱动那就选 Active High反之选 Active Low。还有一个容易忽略的字段是 Idle State也就是空闲状态。当 HRTIM 进入故障封锁、或者输出还没正式启动时引脚上的电平由该字段决定。对功率电路来说安全电平通常是关断电平比如高有效驱动的关断电平是低那就把空闲状态设为低。如果你把空闲状态设成了高一上电或一发生故障MOSFET 直接被强行打开这不是软件 bug这是安全事故。3.6 故障保护配置HRTIM 的故障保护是它区别于普通 PWM 的核心优势之一。配置 Fault 寄存器时可以指定故障源来自哪个引脚、哪个片内比较器以及故障有效电平是高还是低。比如我用的是外部过流保护信号信号平时为高过流时拉低那么故障输入的 Active Level 就选 Low同时把 TA1、TA2 的故障响应状态设为关断电平。但我要给个很实际的建议验证 PWM 输出时先不要急着开故障保护。把所有 Fault 都禁用先把波形调出来。故障保护的影响因素太多万一外部信号悬空、电平错误板子一上电输出就被封锁你会以为是 HRTIM 没配置好排查半天。等功能部分稳定了再一步步打开故障源逐项验证。4. 生成代码只完成一半HAL 接口里的启动顺序与更新机制4.1 初始化结构体与输出通道启动很多人在 CubeMX 里配置完 HRTIM生成代码后直接编译下载发现引脚没有任何波形这很正常。因为 CubeMX 生成的MX_HRTIM1_Init()只做了寄存器配置它不会自动启动输出。HRTIM 在 HAL 库里的启动分两步先启动计数器再启动输出通道。下面是我在 main 函数里加的启动代码以 Timer A 的两路输出为例/* 启动 HRTIM Timer A 计数器和 TA1/TA2 输出 */ HAL_HRTIM_WaveformCounterStart(hhrtim1, HRTIM_TIMERID_TIMER_A); HAL_HRTIM_WaveformOutputStart(hhrtim1, HRTIM_OUTPUT_TA1 | HRTIM_OUTPUT_TA2);启动顺序不要反。先启动计数器让 HRTIM 内部状态机先跑起来再打开输出使能这样 pin 脚从空闲状态切换到 PWM 波形时能保证从确定的相位开始。如果你先开了输出计数器还没到周期基准点第一个脉冲可能是残缺的虽然很多应用看不出问题但严谨的电源控制器里这是不能接受的。停止输出时也建议对称执行HAL_HRTIM_WaveformOutputStop(hhrtim1, HRTIM_OUTPUT_TA1 | HRTIM_OUTPUT_TA2); HAL_HRTIM_WaveformCounterStop(hhrtim1, HRTIM_TIMERID_TIMER_A);4.2 运行中修改占空比Compare 更新时机HRTIM 的占空比不是改一个变量就生效的。在 HAL 里运行中更新比较值要调用HAL_HRTIM_WaveformCompareSet(hhrtim1, HRTIM_TIMERID_TIMER_A, HRTIM_COMPAREUNIT_1, newCompareValue);第二个参数是子定时器 ID第三个参数是比较单元编号。这个函数本质是把比较寄存器写入 HRTIM 的寄存器空间但写入后什么时候生效取决于你在 CubeMX 里配置的预装载更新策略。很多做数字电源的朋友在这里吃过亏主循环里疯狂更新占空比结果 PWM 波形在周期中间跳变导致电流波形出现毛刺。我建议你在 CubeMX 里把比较寄存器的 Preload 使能并且把更新时机选在周期边界。这意味着当前周期内新值不会立即生效而是等这个周期结束计数器重新开始计数的那个点统一更新。这样虽然占空比响应会延迟一个周期但对控制稳定性来说延迟一个固定周期远比异步更新导致的抖动容易处理。4.3 务必用逻辑分析仪或示波器验证死区软件配置看起来都对了不代表实际波形就是安全的。我的习惯是先用逻辑分析仪看两路输出的上下沿放大到死区时间级别确认一路下降沿到另一路上升沿之间的间隔是否大于设置值。如果是两通道示波器就把 CH1 接 TA1CH2 接 TA2触发模式设为上升沿再把时间轴拉开到死区附近看点平台的宽度。这一步别偷懒。HRTIM 死区配置的寄存器位很多任何一个赋值错位都可能让两路输出出现同时为高的状态。尤其是第一次画板、第一次上电测试时建议在功率电路前面串一个小阻值电阻或者干脆先不接功率管只测控制板的 PWM 信号。等波形确认无误再接功率部分这是做功率硬件最稳妥的流程。5. 我踩过的坑和排查思路5.1 输出恒为低先查输出禁止信号遇到过好几次HRTIM 配置完输出引脚一直是低电平。查初始化代码函数都调了寄存器看着也对就是没有波形。后来发现是故障输入的问题。CubeMX 里如果启用了某个 Fault 输入但没有正确配置它的有效电平引脚悬空状态下一直触发故障HRTIM 会把输出封锁自然没有波形。排查思路很简单先用调试器读 HRTIM 的故障相关寄存器看是不是处于 fault active 状态。如果是要么把故障功能暂时 disable要么检查外部信号有没有接对。另外如果使能了外部故障引脚而该引脚没有内部上拉悬空电平容易抖动也会导致偶发封锁。这时候在 CubeMX 里把 GPIO 上拉打开或者硬件上加一个电阻问题就消失了。5.2 频率差一半多半是时钟树分频用户经常在论坛上问同样配置别人是 100kHz我实测只有 50kHz哪里错了我遇到这类问题第一反应就是查 HRTIM Kernel Clock。STM32G4 的 HRTIM 时钟来源不是简单地等于 HCLK它可能来自 PLL 的某一个输出也可能被分频。CubeMX 生成代码后你可以在SystemClock_Config()里看到 RCC 相关配置也可以在 Clock Configuration 页面直接确认 HRTIM1 Kernel Clock 的数值。如果你配置的 HRTIM 时钟是 85MHzPeriod 按 170MHz 计算那输出频率自然只有一半。反过来如果你把系统时钟配成 144MHz又在别的地方误开了分频那频率就更难猜了。我的做法是先在调试器里读一下htim1.Init.ClockDivider同时确认 RCC 里 HRTIM 的时钟使能状态再反推实际频率基本都能找到原因。5.3 互补波形出现直通查死区参数和极性直通是功率电路里最危险的现象。如果示波器看到 TA1 和 TA2 同时为高哪怕只有几十纳秒也可能让半桥上下管瞬间导通轻则发烫重则炸管。出现直通时不要急着怀疑 HRTIM 硬件先看配置第一确认你已经选了双路互补输出模式而不是两路独立输出。第二检查死区上升沿、下降沿延迟是否都大于 0。第三检查输出极性。如果 TA1 是 Active HighTA2 是 Active Low你看到两路同时为高其实是正常互补关系因为一路是有效高另一路有效低时对应引脚行为要反着看。很多直通误判其实是没有理解有效电平。如果确实出现真直通先把死区加大到当前设置值的两倍观察现象是否消失。如果消失说明原来的死区时间不够覆盖驱动电路延迟。如果加大后仍有重叠那就是输出模式或极性配置的问题需要回头逐个排除。我在实际项目中习惯留 1.5 倍到 2 倍的死区余量不能完全按照功率管数据手册的最小死区时间贴边算温度、驱动延时、PCB 寄生参数都会吃掉一部分时间。从 STM32G484 这颗芯片的使用体验来看HRTIM 的学习曲线确实比普通定时器陡峭得多。但只要你照搬这套配置思路先理清时钟再配通道、周期、死区、故障最后再启动输出和验证波形它完全可以成为你做高频电源和电机控制的一把利器。