STM32G474 HRTIM Triggered-half模式实现数字电源逐波限流详解 📅 发布时间:2026/8/29 10:17:44 👁 浏览次数: 前一阵子在调一块数字电源的样机主控用的就是STM32G474卡在一个看似不起眼、实际上很要命的需求上IGBT过流保护时的逐脉冲限流。要求是硬件比较器一旦检测到过流PWM输出必须在规定时间内输出一个宽度精确可控的关断脉冲——最短只有几个微秒靠CPU中断根本来不及。折腾了一周最后是靠G474高精度定时器HRTIM的Triggered-half模式解决的。这个模式确实是好东西但资料比较零散ST有一篇编号LAT1288的应用笔记专门讲G474上Triggered-half的实现网上讨论也不多调试时踩了不少坑把思路和代码整理出来希望能帮到做数字电源、电机驱动、逆变器这一类的朋友。Triggered-half模式简单说就是让定时器在外部触发信号到来后自动输出一个半周期宽度的脉冲然后回到空闲态等待下一次触发。整个过程中硬件自动完成CPU不参与延迟可控非常适合对时间精度要求高的保护逻辑。后面会从应用场景、原理、配置、波形实测和踩坑几个角度完整讲一遍中间会穿插实测数据和寄存器级代码尽量做到能照着跑通。1. 为什么需要Triggered-half数字电源逐波限流场景的痛点1.1 一个真实的项目场景IGBT驱动里的逐脉冲限流先还原一下我遇到的实际工况。样机是一个两相交错并联的Buck变换器开关频率100kHz也就是PWM周期10微秒半周期5微秒。IGBT母线过流保护策略要求在检测到过流的那个开关周期内必须把当前开关管强制关断并且保持一个明确宽度的关断脉冲防止下一次导通时电流继续飙升。传统做法是拿比较器去触发MCU的紧急关断通道比如TIM的刹车功能把PWM输出直接拉到安全电平。但这有个问题刹车只能“一刀切”地关断关多久、何时恢复需要额外逻辑处理。而在一些软开关拓扑里你并不希望一过流就把整个PWM永久关死而是希望“这个周期把它切掉”让系统在后续周期恢复这样电源不会直接停机能扛过短时过载。当时我的第一版方案是用普通定时器PWM加外部中断电流比较器输出接一个GPIO检测到过流就在中断里把占空比改成0。但问题很快暴露中断响应时间不稳定从比较器输出信号到PWM真正关断延迟在1~3微秒之间抖动而5微秒的半周期根本经不起这种抖动。更麻烦的是如果过流信号在PWM高电平中间到来中断处理时机不同关断点每次都不一样等效占空比没法控制测试波形惨不忍睹。1.2 普通PWM方案为什么做不到“精准半波”有的朋友可能会问既然要半周期脉冲能不能用两个定时器一个做PWM一个做单脉冲触发后输出5微秒再关思路没错但实现起来很别扭。首先是同步问题。两个定时器之间要用触发链连接硬件上和软件上都要仔细对齐否则半周期脉冲和主PWM之间的相位对不齐尤其在动态过程中会看到“拍频”一样的错位。其次是精度问题。普通定时器分辨率在170MHz主频下约等于5.88纳秒一位听起来很高但在实际项目中触发信号经过了输入滤波器、极性选择、预分频逻辑延迟有几十到几百纳秒的随机抖动这对半周期控制来说是很大的误差。还有更核心的问题普通定时器没有“触发一次、起一个脉冲、然后停”的原生状态机。你要实现这个行为得靠软件在中断里去翻转引脚、修改计数值、关闭输出。那这套逻辑的实时性和确定性又回到了中断延迟的老问题。说白了普通PWM方案是把“硬件应该干的活”硬塞给了软件结果就是延迟不可控代码越写越复杂可靠性却越来越差。1.3 Triggered-half的定位它到底解决什么问题Triggered-half模式解决的正是上面这个矛盾用硬件状态机代替软件响应。它的核心行为是定时器平时停在空闲状态外部触发事件到达后计数器从0开始向上计数当计数到周期值的一半时产生一次半周期事件这个事件可以控制PWM输出翻转、触发ADC采样、产生中断或继续触发其它定时器。之后计数器复位定时器回到空闲态等待下一个触发。关键点是“半周期”和“止步”。它只输出半个周期不会继续走完整个周期因此天然适合“只切一刀”的逐波限流场景。而且整个过程完全由HRTIM内部硬件完成触发到输出的延迟是确定的抖动可以控制在纳秒级别这在5微秒半周期的应用里基本算是“所见即所得”。ST在LAT1288应用笔记里给出的典型应用就是“comparator-triggered pulse”把电机控制或电源的电流比较器输出接到HRTIM的外部事件输入配置为Triggered-half模式过流信号一到HRTIM自动打出半周期脉冲。我在实际项目里把同一套思路用在保护逻辑和励磁控制上效果都成立。2. G474高精度定时器的触发骨架从事件输入到计数器启动2.1 HRTIM的触发源与事件路由要真正用好Triggered-half不能只看TRGHLF这一个位得先理清HRTIM的触发链路。G474的HRTIM有Master定时器加Timer A~E一共六个时基每个Timer都有各自的触发源选择逻辑。触发源可以是外部事件EEV1/EEV2、其它Timer的事件、比较器事件等。在我这个应用里选用的是外部事件EEV1由片内比较器COMP单元输出驱动。外部事件输入到HRTIM之前要先经过EEVSRC选择外部事件来源再经过ETRPS预分频和ETRPOL极性选择。这一路滤波、极性、分频配置都会影响最终触发时刻。很多人漏配了ETRPOL导致触发沿反了结果表现为要么不触发要么一上电就跑飞。我调试时第一反应也是查TRGHLF对不对结果罪魁祸首其实是极性位。触发源配置好之后真正决定“谁来触发这个Timer”的字段是TIMxCR寄存器里的TRIGER字段。TRIGER可以选外部事件1、外部事件2、其它Timer事件等多达十几路信号。Triggered-half模式本身不限定触发源所以在不同方案里可以灵活搭配。2.2 计数器状态机空闲、运行、复位与触发半模式的切换HRTIM每个Timer支持多种工作模式比如连续PWM模式、单脉冲模式、Triggered-half模式。区别主要在计数器状态机的行为上。在Triggered-half模式下计数器初始处于空闲态不计数、PWM输出保持预置电平。触发事件到来后计数器被释放从0开始向上计数这个阶段PWM输出按照比较寄存器和输出极性的配置产生翻转。当计数器到达PER值的一半时硬件会自动将计数器复位回0同时PWM输出回到空闲电平定时器重新进入等待状态。也就是说计数器实际上只跑了一个半程就停了整个半周期事件在此时刻生成。这里有个很直观的理解方式把普通PWM模式想象成跑步机计数器连续转圈把单脉冲模式想象成“跑一圈就停”Triggered-half模式则是“听到发令枪后跑到半圈就停”。发令枪就是触发事件半圈就是PER/2。正因为停在半圈上所以输出脉冲宽度天然等于半个周期。这也是为什么它叫“Triggered-half”。2.3 TRGHLF位的工作机制半周期事件到底怎么产生实现Triggered-half的关键寄存器位是HRTIM定时器控制寄存器TIMxCR中的TRGHLF位。置1后定时器就进入触发半模式。在该模式下计数器到达PER/2时产生的事件可以同时驱动PWM输出的翻转ADC的注入转换触发定时器中断标志作为事件输出到其它Timer用于级联。值得注意的是触发半模式下的半周期事件和普通PWM模式下的比较事件在硬件实现上走的是同一套比较通道。所以你需要把某个比较寄存器例如CMP1配置为PER/2。这一点很关键因为很多人以为TRGHLF模式下硬件会自动替你算PER/2实际上不是。硬件只是把“更新事件时机”绑定到了“计数到CMP”用哪个比较值、设多大仍然是软件的事。我在LAT1288的配套代码里看到的标准做法就是CMP1 PER / 2至少有一个通道的输出事件在半周期处产生。弄清楚这层关系后写代码就有方向了周期值PER决定半周期的绝对时间CMP1决定事件发生的位置。想精确控制半周期就要保证这两个寄存器写入的值是精确的。同时还要注意TIMxPER和TIMxCMPx可能都有预装载缓冲什么时候生效取决于更新事件这在后续章节会展开讲。3. 实现Triggered-half的完整配置CubeMX与寄存器双视角3.1 CubeMX下的关键配置项如果是从零开始建议先用STM32CubeMX生成一个基础工程把HRTIM和触发相关的外设先配置出来再在代码里改关键寄存器。CubeMX里HRTIM的配置界面选项非常多容易看花眼我按实际填写顺序说。第一步选择HRTIM1在Timer A的Mode里启用输出通道比如TA1。第二步在Parameter Settings里把Counter PeriodPER设为1000对应10微秒周期假设HRTIM时钟170MHz1000 / 170MHz ≈ 5.88微秒等一下这里要仔细算170MHz下周期10us需要计数1700个时钟所以PER设1699。半周期850个比较值CMP1设850。实际值你自己按芯片时钟算这里只是举例。第三步把Trigger Source选为External Event 1外部事件1EEV极性选Rising Edge预分频选1不分频。有一点要注意CubeMX的图形界面里“Triggered-half mode”不一定直接出现在默认参数列表有时在Advanced Attributes或通过修改寄存器才能看到。如果找不到不用纠结在生成的代码里手动写上TRGHLF位即可效果一样。第四步配置外部事件的输入源。在CubeMX里COMP比较器的输出可以重映射到HRTIM的EEV输入。如果使用比较器需要把COMP输出连接到HRTIM EEV1同时让COMP的极性、滞回参数与保护逻辑匹配。3.2 寄存器级代码写入顺序比想象中重要CubeMX把底层初始化代码生成后核心配置通常在函数MX_HRTIM1_Init()里但我建议另外写一个独立函数HRTIM1_TriggeredHalf_Config()把关键配置显式写清楚方便后续调整。下面这段是我整理出来的寄存器级配置框架以Timer A、外部事件1为触发源为例#include stm32g4xx_hal.h void HRTIM1_TriggeredHalf_Config(HRTIM_HandleTypeDef *hrtim) { /* 1. 先选择Timer A的触发源外部事件1 */ hrtim-Instance-sTimRegs[HRTIM_TIMER_INDEX_A].TIMxCR ~HRTIM_TIMCR_TRIGER; hrtim-Instance-sTimRegs[HRTIM_TIMER_INDEX_A].TIMxCR | (7U HRTIM_TIMCR_TRIGER_Pos); /* 具体编码以RM0440为准 */ /* 2. 配置外部事件的极性和预分频 */ hrtim-Instance-sTimRegs[HRTIM_TIMER_INDEX_A].TIMxCR | HRTIM_TIMCR_ETRPOL_0; /* 上升沿有效 */ /* ETRPS不预分频确保触发延迟最小 */ /* 3. 使能Triggered-half模式 */ hrtim-Instance-sTimRegs[HRTIM_TIMER_INDEX_A].TIMxCR | HRTIM_TIMCR_TRGHLF; /* 4. 设置周期值和比较值比较值周期/2决定半周期事件位置 */ hrtim-Instance-sTimRegs[HRTIM_TIMER_INDEX_A].TIMxPER 1700U - 1U; /* 10us 170MHz */ hrtim-Instance-sTimRegs[HRTIM_TIMER_INDEX_A].TIMxCMP1 (1700U - 1U) / 2U; /* 5. 使能Timer A输出通道 */ hrtim-Instance-sOutRegs[HRTIM_TIMER_INDEX_A].TIMxOUTR | HRTIM_OUTR_TA1EN; /* 使能TA1输出 */ /* 6. 启动Timer A进入等待触发状态 */ hrtim-Instance-sTimRegs[HRTIM_TIMER_INDEX_A].TIMxCR | HRTIM_TIMCR_EN; /* 7. 打开半周期事件对应的中断可选用于指示触发已经发生 */ hrtim-Instance-sTimRegs[HRTIM_TIMER_INDEX_A].TIMxIER | HRTIM_TIMIER_CMP1IE; }这段代码有几个容易踩的细节。第一TIMxCR的配置顺序很重要TRGHLF和触发源选择必须在使能定时器之前完成否则定时器上电后可能直接按普通模式连续运行产生一个不确定的起始相位。虽然HRTIM有复位逻辑但工程上不依赖“运行后再修改”的路径。第二如果你用的是HAL库的HAL_HRTIM_SimplePWM_Start这类接口它会把寄存器状态按照通用PWM模式重新配置一遍所以最好在HAL启动之后再手动调用上面的配置函数覆盖关键位或者直接用LL库的寄存器级接口避免HAL的通用流程把TRGHLF清掉。3.3 ADC注入采样与半周期事件的联动Triggered-half半周期事件的价值不只是输出一个脉冲还可以用它作为ADC注入采样的触发源。在逐波限流场景里我们希望刚好在PWM关断脉冲的中点附近采一次母线电流用来判断是否真的过流、是否需要持续保护。用半周期事件触发ADC注入采样采样的时间点就和PWM位置精确绑定完全不用软件干预。G474的ADC1/ADC2/ADC5都支持由HRTIM事件触发注入转换。以ADC1为例在CubeMX的ADC配置里把Injected Conversion Trigger选择为HRTIM Trigger A Event由Timer A的半周期事件驱动。如果把多个ADC配置成由不同Timer事件交错触发还能做三相电流同步采样这在电机控制里很常用。需要注意注入转换触发后ADC的采样保持时间会影响实际采样点如果采样时间太短信号还没稳定就采集了结果不准。调试时可以用DAC输出某个固定电平再用ADC注入采样观察读数确认采样时刻和信号时序是否匹配。4. 实测波形与参数确认用示波器验证时序4.1 测试平台搭建与信号连接代码写完后必须上示波器验证时序。我的测试平台很简单一块G474最小系统板、一个信号发生器、一台四通道示波器。信号发生器输出一个5V方波频率1kHz占空比10%接到外部事件EEV1对应的引脚。在G474的数据手册里EEV1是HRTIM外部事件输入具体引脚可以在CubeMX的Pinout视图里看到并指定。示波器CH1接信号发生器的输出CH2接HRTIM的TA1输出引脚。上电前先确认一件事EEV1引脚的输入模式是否配置正确。在CubeMX里如果只启用了HRTIM系统不会自动帮你把这个引脚配成输入需要在GPIO配置里手动选中该引脚并设为输入模式。这个遗漏是新手最容易犯的表现形式是代码看着都对但示波器上就是等不到输出。开始测试前先不要连接真实比较器用信号发生器手动触发。这样可以先把Triggered-half链路本身调通排除外部信号的干扰。把信号发生器频率调到500Hz占空比5%先慢速观察确认每次触发都对应一个脉冲再逐步提高频率。4.2 半周期事件的波形判读正常工作时示波器上应该看到如下时序触发信号上升沿到达经过一个短暂的硬件延迟通常几十纳秒级别TA1输出电平翻转输出一个宽度等于PER/2时钟周期的脉冲脉冲结束后输出回到空闲电平等待下一次触发。按照代码里的PER1699、CMP1850计算半周期脉冲宽度约为5微秒。实测时把示波器时基放到1微秒/格能清晰看到输出高电平持续恰好5微秒然后回落。如果显示的脉冲宽度不是5微秒先检查两点CMP1值是否真的等于PER/2预装载缓冲是否把新值延迟到了下一个更新事件才生效。另一个容易忽略的细节是TA1输出的空闲电平是低还是高取决于输出极性配置。如果把极性配置成高有效脉冲翻转逻辑就是空闲低、触发后变高反过来配置成低有效输出就是空闲高、触发后拉低。在保护电路里要确保空闲电平不会误开通功率管因此要先想清楚“空闲安全电平”是什么再决定极性。4.3 抖动与延迟从触发到事件的实际测量对于保护逻辑光有脉冲宽度还不够触发信号的延迟和抖动才是硬指标。我在示波器上开启了余晖模式累积观察数百次触发的波形。测量从触发信号上升沿到TA1输出开始翻转的延迟实测结果大约在45~55纳秒之间抖动在±3纳秒以内。这个数字远超CPU中断方案的性能也正是Triggered-half模式的核心价值。延迟的主要来源包括外部事件输入引脚的内部施密特触发器和输入滤波HRTIM事件路由逻辑以及输出驱动级的传播延迟。如果你的应用对延迟极敏感可以关闭HRTIM的输入滤波或者把滤波时间设到最小减少一个不必要的时间常数。我实测开启最长的数字滤波后延迟会增加到几百纳秒对5微秒半周期来说可能还能接受但如果半周期只有几百纳秒这个延迟就不能忽略。如果半周期时间更短比如1微秒以内建议把触发源从外部事件改成片内直接连接。G474里比较器COMP的输出可以不经过引脚直接连接到HRTIM省掉引脚出入的延迟和滤波环节。我后来做第二版保护电路时就是把比较器输出直接路由到HRTIM的EEV延迟比经过引脚再进来缩短了将近一半。5. 工程实现中的坑与对策5.1 触发器沿配置不当导致漏触发第一个坑是触发沿配置反了。因为比较器输出过流信号时可能是低电平有效也可能是高电平有效取决于比较器的非反相/反相输入接法。我之前一直默认比较器输出高电平表示过流结果实际电路接反了过流时输出低电平HRTIM一直没反应。排查方法很简单示波器同时看比较器输出和EEV引脚确认实际触发信号是上升沿还是下降沿然后根据实际波形设置ETRPOL位。如果不确定可以在代码里先留一个调试标志在HRTIM中断里翻转一个GPIO通过观察这个GPIO是否动作来判断触发硬件链路是否通畅。5.2 周期寄存器更新时机与半周期关系第二个坑和寄存器更新时机有关。HRTIM的TIMxPER和TIMxCMP1寄存器很多都有预装载缓冲写入后不会立刻生效要等到一次更新事件才正式锁存。在Triggered-half模式下计数器在半周期处复位这个复位事件同时会产生更新事件。换句话说你在计数器运行中间修改PER可能要到下一次触发时新值才生效。这在动态调整半周期宽度的场景里尤其容易踩。比如你要在系统运行中根据母线电压把半周期从5微秒改成4微秒直接写TIMxPER你会发现波形没变化直到下一次触发才跳变。如果需要在当前周期立刻生效需要额外操作把定时器临时复位或触发一次软件更新事件。我当时是在一个电流环参数的调试页面里调半周期改了参数但波形纹丝不动差点以为寄存器没写进去查了半天才发现是预装载缓冲的锅。5.3 初始化顺序与计数器复位第三个坑出现在初始化阶段。如果使能定时器EN位置1之后才配置TRIGER和TRGHLF定时器可能已经执行过一次复位产生了一个无触发的无效更新事件这会导致后续触发时间出现一个周期的偏差表现为第一次脉冲宽度不正确或者直接丢掉。正确顺序是先清空全部状态位并复位计数器再配置触发源、极性、TRGHLF、比较值、使能输出最后使能定时器。这时定时器静默等待触发不产生任何无效事件。调试时还可以在配置末尾加一段软件自测临时把触发源设为软件触发或GPIO手动拉一次验证半周期事件能正常产生再接真实外部事件这样能区分是配置问题还是外部信号问题。5.4 与ADC触发同步的竞态第四个坑发生在半周期事件触发ADC注入采样时。前面说了半周期事件和PWM输出翻转发生在同一时刻。如果ADC采样也恰好在这个时刻开始采样开关的电荷注入和开关噪声很可能污染采样结果。实际操作中我会把ADC注入采样的触发信号延时一点点或者把半周期事件先经过一个延时模块再输出给ADC保证采样点落在PWM翻转后一段时间而不是正好在翻转沿上。G474的ADC触发信号可以经过片内触发延时逻辑或者在HRTIM里用另一个比较通道在“PER/2 偏移”的位置产生ADC触发。这样采样点就避开了输出翻转的瞬间。我在验证时对比过两种配置不加偏移的ADC读数在开关沿处的噪声尖峰明显加上几百纳秒偏移后读数稳定了很多。6. 扩展从单次触发到连续突发模式的调整6.1 自动重启与连续触发Triggered-half模式天然适配单次保护触发但有些场景需要连续输出多个半周期脉冲比如软启动过程中的间歇驱动或谐振变换器的突发模式。这时候可以把半周期事件作为自身的下一次触发源形成自维持的“连续半周期”输出序列。配置方法不复杂把TRIGER字段从外部事件改成自身的更新事件再配合预分频控制触发间隔就能实现一串等间隔的半周期脉冲相当于一个不依赖软件的窄脉冲发生器。我实际测试时用这种方法在一个G474上同时输出两路相移的半周期脉冲序列避免了为每个通道单独配置一个独立PWM外设的麻烦。这种用法LAT1288笔记里没有展开但硬件能力上是支持的。6.2 多定时器级联与交错控制G474的HRTIM有五个独立Timer它们之间的触发链可以很灵活。利用Timer A的半周期事件去触发Timer B再让Timer B产生自己的半周期输出就能实现多路延迟的交错脉冲。这在多相交错Buck变换器里非常实用每一相都有自己的过流比较器过流时各自关断本相而不影响其它相的工作。我在样机里就是让Timer A和Timer B分别承担两相保护两相之间通过偏置的触发相位交错。半周期事件发生后各自关断本相等到下一个周期再统一恢复实现逐周限流而不停机。示波器上看两路PWM的关断时刻错开半个周期互不干扰逻辑清晰。6.3 结合DAC与比较器实现闭环保护如果只做“过流就关断”Triggered-half只是保护逻辑。但LAT1288的价值在于可以把它和DAC、比较器一起构成一个硬件闭环。G474片内有多个DAC和比较器比较器阈值由DAC提供比较器输出接到HRTIM的EEV输入。正常工作时PWM不受影响一旦反馈电流超过DAC设定的阈值比较器翻转HRTIM立刻输出半周期关断脉冲。这种方案把“采样-比较-关断”整个保护环全部放在硬件里延迟只取决于比较器传播延迟和HRTIM触发路径总延迟通常在100纳秒出头。CPU只需要更新DAC阈值或处理保护后状态完全不用管时序。我在做高压应用时特别依赖这套机制因为它不依赖固件执行哪怕CPU跑飞或中断卡死保护逻辑依然独立生效。后续如果要把这套方案做扎实建议再深入研究HRTIM的DTG死区时间和输出刹车逻辑这两个方向和Triggered-half配合使用基本能覆盖大部分功率变换器的硬件保护需求。实际调试时多花点时间在波形验证上把每个关键时间点都测清楚比单纯抄代码有用得多。