STM32G484 HRTIM高频互补PWM配置实战:从时钟到死区与故障保护
2026/8/31 21:50:41 网站建设 项目流程

前阵子调一块 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 输出互补 PWM

3.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 = 1700,Period 就填 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 接 TA1,CH2 接 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 时钟是 85MHz,Period 按 170MHz 计算,那输出频率自然只有一半。反过来,如果你把系统时钟配成 144MHz,又在别的地方误开了分频,那频率就更难猜了。我的做法是先在调试器里读一下htim1.Init.ClockDivider,同时确认 RCC 里 HRTIM 的时钟使能状态,再反推实际频率,基本都能找到原因。

5.3 互补波形出现直通,查死区参数和极性

直通是功率电路里最危险的现象。如果示波器看到 TA1 和 TA2 同时为高,哪怕只有几十纳秒,也可能让半桥上下管瞬间导通,轻则发烫,重则炸管。出现直通时,不要急着怀疑 HRTIM 硬件,先看配置:

第一,确认你已经选了双路互补输出模式,而不是两路独立输出。第二,检查死区上升沿、下降沿延迟是否都大于 0。第三,检查输出极性。如果 TA1 是 Active High,TA2 是 Active Low,你看到两路同时为高其实是正常互补关系,因为一路是有效高,另一路有效低时对应引脚行为要反着看。很多"直通误判"其实是没有理解有效电平。

如果确实出现真直通,先把死区加大到当前设置值的两倍,观察现象是否消失。如果消失,说明原来的死区时间不够覆盖驱动电路延迟。如果加大后仍有重叠,那就是输出模式或极性配置的问题,需要回头逐个排除。我在实际项目中习惯留 1.5 倍到 2 倍的死区余量,不能完全按照功率管数据手册的最小死区时间贴边算,温度、驱动延时、PCB 寄生参数都会吃掉一部分时间。

从 STM32G484 这颗芯片的使用体验来看,HRTIM 的学习曲线确实比普通定时器陡峭得多。但只要你照搬这套配置思路,先理清时钟,再配通道、周期、死区、故障,最后再启动输出和验证波形,它完全可以成为你做高频电源和电机控制的一把利器。

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

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

立即咨询