做了几年电机控制和数字电源的工程师,大概率都经历过类似的场面:实验室里正调着板子,突然“啪”一声,IGBT炸了,或者MOS管冒烟了。排查下来,多数情况不是算法算错了,而是保护没来得及动作——等CPU的中断跑到,功率器件早就凉了。在TI C2000系列DSP上,解决这个问题的核心就是CMPSS(比较器子系统)、DCEVT(数字比较事件)和Trip-Zone(跳闸区)这三层硬件保护链路。这篇文章我就把这套机制从原理到配置完整拆开讲,包括寄存器怎么配、阈值怎么算、哪些坑最容易踩,以及怎么验证保护链路是真的“快”。
如果你用过STM32的刹车功能(Break Input),再看C2000这套东西,会发现它的思路是把“刹车”拆成了三个独立又互相咬合的层级:CMPSS负责把模拟信号快速变成数字事件,DCEVT负责对这个事件做源选择和滤波整形,最后一层的Trip-Zone才真正去强制PWM引脚输出安全电平。每一层都能独立配置,组合起来就能实现纳秒级响应的硬件保护,完全不依赖软件中断。下面我按这条链路从前到后、再从原理到实战,一层层讲清楚。
1. 为什么要用三层硬件链路:纯软件保护的响应速度根本不够
1.1 一个让人肉疼的真实场景
先说一个我早年的教训。第一次做BLDC电机控制器时,我用的是最“朴素”的方案:电流采样通过运放放大后送进ADC,然后ADC转换完成中断里判断电流是否超限,超了就软件拉低PWM输出。程序写起来非常直观,调起来也顺利,直到有一天做堵转测试——电机堵住,电流迅速飙升,当我看到波形上电流已经超过IGBT额定值而PWM还在正常输出时,就知道这个方案要出事。后来改了思路,把过流信号引到MCU的GPIO外部中断里,情况好了一些,但外部中断从触发到进入ISR、再执行PWM寄存器清零,中间隔了十几个时钟周期,加上中断响应本身的延迟和GPIO去抖时间,整体下来也要几百纳秒到几微秒。对功率器件来说,几百纳秒的短路电流已经足够让它进入危险区。
这就是纯软件保护的先天缺陷:它走的是“模拟采样→ADC/比较器→中断→CPU执行指令→改寄存器”这条路,每一步都有不可控的延迟。而功率器件烧毁往往就在几十到几百纳秒之间。
1.2 硬件保护链路的精妙分工
CMPSS、DCEVT和Trip-Zone的组合,本质上把“检测→决策→执行”全部从CPU手上拿走了。CMPSS里有一个模拟比较器,它实时比较外部输入电压和内部DAC设定的阈值电压,只要输入超过阈值,比较器输出翻转。注意这一步是纯硬件的,延迟只有几十纳秒,比任何ADC都要快得多。DCEVT在EPWM模块内部,负责对CMPSS送过来的数字信号做源选择、极性处理、滤波整形、blanking窗口管理,最终生成一个可控的数字比较事件。这个事件可以直接触发Trip-Zone。Trip-Zone收到触发后,立即将PWM输出强制为预先设定的安全电平(比如强制低或高阻),完成保护动作的“最后一跳”。
这套链路中,软件CPU完全不需要参与触发过程,整个过程都在硬件内部完成。软件要做的事是提前配置好阈值、滤波参数和强制动作,以及在故障中断里记录事件、判定故障类型、决定后续恢复策略。理解了这个分工,后面看每一层寄存器的功能就有目标了。
2. CMPSS比较器子系统:从模拟信号到数字事件的“哨兵”
2.1 CMPSS的基本架构和工作模式
CMPSS全称是Comparator Subsystem,在F28004x、F2837x这些较新的C2000型号上是标配。每个CMPSS模块内部有两个独立的模拟比较器,一个叫高端比较器(CTRIPH),一个叫低端比较器(CTRIPL),外加两个12位的DAC和对应的输出滤波器。CTRIPH用于检测输入信号是否高于某个阈值,CTRIPL用于检测是否低于某个阈值,所以我通常会拿一组CMPSS同时做“过流保护”和“母线欠压保护”,比如用CTRIPH监视相电流上桥臂并设定过流阈值,用CTRIPL监视母线电压并设定欠压阈值。
比较器的输入引脚固定连接到CMPINx,可接受的电压范围和ADC输入一样,一般是0~3.3V。如果你要检测的是大电流信号,外部必须有对应的电流传感器和调理电路,把电流信号线性映射到这个电压范围内。具体选什么采样电阻、运放电路留到后面实战部分再说,这里先明确一点:CMPSS的输入信号必须是电压,而且必须在0~3.3V范围内,否则内置ESD保护二极管都不一定能救得了你的引脚。
2.2 DAC阈值电压的计算
CMPSS内部DAC是12位,参考电压一般是VDAC,通常是3.3V。计算非常简单,最终DAC输出电压是:
[ V_{DAC} = \frac{DACVAL}{4096} \times V_{DAC_REF} ]
反过来,给定一个需要的阈值电压 ( V_{TH} ),需要的寄存器值是:
[ DACVAL = \frac{V_{TH}}{V_{DAC_REF}} \times 4096 ]
举个例子,我的电流检测电路里传感器输出0.5V代表无电流,满量程3.0V对应100A,我想在85A时触发过流保护,那么85A对应的电压就是 ( 0.5 + (85/100) \times (3.0-0.5) = 2.625V )。算下来 DACVAL = ( 2.625 / 3.3 \times 4096 \approx 3258 ),取整后写成3258就可以了。这个值可以在运行中随时修改,因为它支持shadow加载模式,配合PWM同步信号可以在周期起始点更新,实现动态过流点。
注意:CMPSS的DAC寄存器默认工作在shadow模式,修改CMPSSDACVAL寄存器后,需要等待特定同步事件到来才会真正生效到比较器的参考端。如果你第一次配置完发现比较器总是没反应,多半是忘了等shadow加载完成,或者没有触发同步。
2.3 输出极性、滤波与锁存
CMPSS比较器原始的异步输出,既可以直连给后级模块使用,也可以先经过数字滤波再输出。在CMPSSCTL1寄存器里,可以通过COMPDACE位使能DAC,通过COMPHSOURCE选择输入源,通过INVHSOURCE选择比较器输入是否反相。CMPSSCTL2寄存器则是滤波配置的核心:CTRIPHFILCLK是滤波时钟分频,CTRIPHFILTHRESH是滤波采样阈值,CTRIPHFILEN打开滤波使能,CTRIPHINV控制输出极性。滤波的本质是:在一个采样周期窗口内,需要连续采样到N次高电平,输出才判定为高。这就把尖峰干扰过滤掉了。
这里要做一个很重要的权衡。滤波强度越高,抗干扰能力越强,但引入的延迟也越大。虽然滤波器都在硬件里,延迟也就几百纳秒级别,可对短路保护来说,每多一百纳秒,IGBT承受的短路能量就多一分。我一般建议:除非你的应用存在明显的开关振铃干扰,否则过流保护这条路径上不要开太强的滤波。滤波器的配置值可以先从一个较低的门槛开始,比如连续采样4次通过,测试时再看误触发的频率。
CMPSS还有一个锁存功能,在CMPSSCTL1里配置TRIPHLATCH置1后,比较器输出一旦有效就会锁存住,即使输入信号恢复,输出也保持有效状态,必须软件写1到对应锁存清除位才能解锁。这个特性很适合做“故障记忆”,因为对电机控制来说,过流之后无论电流是否恢复,系统都需要停机检查,让故障状态保持住,软件才能可靠地记录发生过的事。但要注意,锁存后的清除操作是有顺序的:必须先消除触发条件(比如把DAC阈值调到安全范围,或等输入电压回到正常区间),再清锁存,否则锁存会立刻再次置位。
3. DCEVT数字比较事件:把比较结果变成PWM可控事件的桥梁
3.1 DCEVT在EPWM中的位置
CMPSS输出的CTRIPH/CTRIPL信号并不会直接跳到Trip-Zone,而是先进到EPWM模块内部的DCEVT。EPWM模块里有两组数字比较事件输入,一组叫DCA(Digital Compare A,与EPWMxA关联),一组叫DCB(Digital Compare B,与EPWMxB关联)。每组内部又有EVT1和EVT2两个事件。整个DCEVT的作用就是把各种源信号,通过一个可编程的多路选择器和滤波网络,整理成事件信号,再送给Trip-Zone和ADC触发等下游模块。
为什么要多这一层中转?直接接不是更快吗?从延迟角度,直连确实快,TI的数据手册里,CMPSS的异步输出直连Trip-Zone路径延迟可以压到非常低。但问题是,直接直连你就失去了所有灵活性:没办法切换信号源、没办法加blanking窗口屏蔽开关噪声、没办法做多个信号的组合逻辑。DCEVT这层虽然增加了一点传递延迟,但换来了工程上极其重要的灵活性。实际项目中,我几乎总是让CMPSS信号先经过DCEVT再触发TZ,只有某些对延迟极其敏感的短路保护场景,才会额外走一条CMPSS直连TZ的旁路。
3.2 DCTRIPSEL源选择与事件组合
DCTRIPSEL寄存器负责选择DCAH、DCAL、DCBH、DCBL这四个输入源分别接到哪个CMPSS通道、哪个外部引脚。比如我想让DCA的H通道对应CMPSS1的CTRIPH输出,那么:
EPwm1Regs.DCTRIPSEL.bit.DCAHCOMPSEL = 0; // 选择CMPSS1 CTRIPH每个源也可以关闭,或者选择来自INPUTXBAR的外部信号,这样GPIO上的外部故障信号、紧急停止信号也能进入同一个DCEVT逻辑,统一管理。DCACTL和DCBCTL寄存器则定义EVT1和EVT2的触发源是滤波前的输入还是滤波后的输入,以及是否需要同步到某个时钟域。我习惯使用滤波后的信号,因为在电机驱动中,开关瞬间的振铃太常见了,完全不用滤波等于把误触发风险全部抛给后级。
事件组合的逻辑也很有用。比如DCAEVT1可以用DCAH触发,也可以用DCAL触发,甚至可以通过DCACTL里的SRCSEL位选择是否用另一个事件的异或组合。实质上让你两个比较器、四路信号,通过配置就能构成简单的与或逻辑。工程上最常见的用法是:DCAEVT1选择DCAH,即只当过流信号有效时才触发;DCAEVT2选择DCAL,用于检测母线欠压。
3.3 Blanking窗口:消除PWM开关噪声的利器
DCFCTL寄存器控制滤波和blanking。滤波前面已经说过原理,blanking是另一个非常实用的功能,它可以设置一个时间窗口,在这个窗口内屏蔽DCEVT输入,防止PWM开关瞬间的电流尖峰引起误触发。电机驱动的电流波形,在MOSFET开关动作时会有明显的振铃,如果CMPSS阈值设置得离正常工作点太近,每次开关都可能误报过流。blanking窗口的触发源通常选择为PWM时基的周期事件或比较事件,窗口的起点和宽度由BLANKE选择、BLANKINV决定窗口在事件之前或之后,BLANKPULSE设置脉冲宽度。
以一个20kHz、周期50微秒的PWM为例,PWM周期开始时,上管开通,电流瞬态尖峰可能持续几百纳秒。我可以在PWM周期事件,也就是计数归零的时刻,产生一个blanking窗口,窗口长度设置为几百纳秒到一微秒。在这个窗口内,即使CMPSS比较器输出翻转,DCEVT事件也不会生成,自然就不会误触发Trip-Zone。窗口结束后,比较器的输出实时性完全恢复。这里的关键是窗口不能太长,太长了等于把故障屏蔽掉一部分,我有一次为了消除误触发,把blanking窗口拉到5微秒,结果真的过流时保护慢了一拍,差点出事。经验值:blanking窗口长度不超过PWM周期的1%到2%,或者不超过开关振铃持续时间的1.5倍。
DCFCTL还有一个PUSHSRC位和PULSESEL位,可以控制DCEVT事件是否会被一个短脉冲扩展。因为比较器事件可能持续的时间极短,后级模块如果来不及采样就可能错过,脉冲扩展可以把它拉长到一个确定的宽度,保证下游一定能识别到。对Trip-Zone这种边沿触发敏感的模块,合理使用脉冲扩展能避免漏保护。
4. Trip-Zone的强制动作机制:从事件到引脚安全电平的最后一跳
4.1 TZSEL:把事件路由到正确的触发源
Trip-Zone直译叫“跳闸区”,它本质上是一个强制输出控制模块。每个EPWM模块有多路Trip-Zone源,可以是来自外部引脚的TZ1、TZ2、TZ3信号,也可以是内部DCEVT的事件信号,以及一些CMPSS的直连信号。TZSEL寄存器决定哪些信号源有效,以及是以one-shot模式还是cycle-by-cycle模式触发。
One-shot模式适合真正的故障保护:一旦触发,PWM输出立即被强制到预设的安全状态并一直保持,直到软件明确清除标志。Cycle-by-cycle模式俗称“过流限流”模式:每个PWM周期都会检查故障信号,如果在周期内故障消失,PWM会在下一个周期自动恢复。它很适合那种不希望彻底停机、想要折叠限流继续运行的应用,比如电机启动瞬间的大电流限制。
TZSEL寄存器的底层实现是每个源对应一个位,写1表示使能该源并选择one-shot还是CBC,写0表示禁用。拿我们最常用的配置来说:
// DCAEVT1触发one-shot,DCAEVT2触发CBC EPwm1Regs.TZSEL.bit.DCAEVT1 = 1; // OST,用于过流故障一次跳闸 EPwm1Regs.TZSEL.bit.DCAEVT2 = 3; // CBC,用于逐周期限流TZSEL位域的具体编码,不同型号略有差异,但大的逻辑一致。我会以F28004x为例,读者在其他型号上需要对照对应技术参考手册(TRM)的寄存器描述确认编码。
4.2 TZCTL:配置PWM引脚的强制输出状态
Trip-Zone触发后,EPWMxA和EPWMxB引脚输出什么状态,由TZCTL寄存器决定。每个PWM输出通道可以单独配置,选项有:强制高、强制低、强制高阻、不做改变。对于电机控制的桥式电路,我习惯把上下管对应的EPWMxA和EPWMxB都强制为低,这样无论之前占空比是多少,故障时两个管子都关断,避免直通烧毁;对于某些需要外部硬件上拉到安全电平的场景,也可以配置为高阻,让外部电路决定最终状态。
关键点来了:TZCTL只是定义了触发后的输出状态,它不会管你是否配置了PWM动作限定(AQ)的优先级。当TZ生效时,它的优先级高于所有正常的PWM动作(比如比较器匹配、周期匹配),所以无论之前PWM输出的是什么,都会被立刻覆盖到安全状态。这也是Trip-Zone可靠的底气所在。
还需要注意,F28004x的TZCTL里还有个TZCTL2寄存器,用于配置DCAEVT1和DCAEVT2信号本身作为强制源时的状态。在一些更复杂的拓扑,比如T型三电平逆变器里,故障时A相和B相需要不同的安全状态,TZCTL2能让每个DCEVT事件对应不同的输出动作,这点设计工具往往没注意,实际上是三电平项目里的关键寄存器。
4.3 中断、标志位和清除时序
每次TZ触发后,事件会记录在TZFLG寄存器中。OST标志位记录one-shot触发,CBC标志位记录cycle-by-cycle触发,INT标志位表示TZ中断是否发生。这些标志需要软件确认后写TZCLR清除,而且清除顺序有讲究:必须先清除触发源造成的标志,再清除中断标志。
如果故障源本身没有被消除,比如CMPSS输入信号仍然超过阈值,即使你把TZCLR清零了,Trip-Zone也会立刻再次强制PWM到安全状态。所以软件上的处理顺序应该是:进入TZ中断后,先读取故障状态(例如CMPSS比较器输出寄存器、TZFLG),判断是哪一路触发的;然后关闭PWM或者封锁驱动使能,防止重新开启;接着把CMPSS阈值调整到安全范围或者确认输入信号已经回落;最后才清除TZ标志并重新使能PWM。
TZFRC寄存器是一个用于软件强制触发Trip-Zone的测试位,可用于调试。在刚焊接好新板子、还没有实际电流时,我经常用TZFRC把TZ强制触发,验证PWM波形是否会在故障时正确落到低电平。这是保护机制验证的关键手段,后面实战部分会细说。
5. 实战:从零搭建一条完整过流保护链路
5.1 系统需求分析与方案选型
假设我要做一个电机驱动,母线电压48V,额定相电流20A,IGBT规格按37A选取,电流传感器用霍尔型,输出0~3.3V线性对应-50A到+50A。项目要求过流保护点设定在30A,并且一旦过流就永远停机,直到人工复位。同时希望在正常运行电流超过25A时,PWM自动折叠限流,电流降下来后能自动恢复。
根据这个需求,我选择用CMPSS1的CTRIPH做30A短路保护,走DCAEVT1触发one-shot Trip-Zone;用CMPSS2的CTRIPH做25A的逐周期限流,走DCAEVT2触发CBC Trip-Zone。两个CMPSS的阈值换算一下:30A对应的电压是 ( (30/50) \times 3.3 / 2 + 1.65 ? ),我这里假设传感器中点1.65V对应0A,那么30A对应2.64V,25A对应2.475V。DACVAL分别算好写入。有人会奇怪为什么不用一个CMPSS的两个比较器,主要是我还想留一路L比较器做母线欠压,用两个模块更清晰。
5.2 CMPSS初始化代码与说明
F28004x的CMPSS1寄存器初始化如下:
void CMPSS_Init(void) { EALLOW; // CMPSS1:30A过流保护,one-shot Cmpss1Regs.CMPSSDACCTL.bit.DACSOURCE = 0; // 使用DACLOOP源 Cmpss1Regs.CMPSSDACVAL.bit.DACVAL = 2.64 / 3.3 * 4096; // 约3277 Cmpss1Regs.CMPSSCTL1.bit.COMPDACE = 1; // DAC输出使能 Cmpss1Regs.CMPSSCTL1.bit.COMPHSOURCE = 0; // 比较器H输入选择CMPIN1 Cmpss1Regs.CMPSSCTL1.bit.INVHSOURCE = 0; // 不反相输入 Cmpss1Regs.CMPSSCTL2.bit.CTRIPHSEL = 0; // 滤波采样配置 Cmpss1Regs.CMPSSCTL2.bit.CTRIPHFILEN = 1; // 使能滤波 Cmpss1Regs.CMPSSCTL2.bit.CTRIPHFILCLK = 0; // 滤波时钟不额外分频 Cmpss1Regs.CMPSSCTL2.bit.CTRIPHFILTHRESH = 4; // 连续采样4个周期为高才判定为高 Cmpss1Regs.CMPSSCTL2.bit.CTRIPHINV = 0; // 输出极性不反转 Cmpss1Regs.CMPSSCTL1.bit.CTRIPHLATCH = 1; // 锁存故障 // CMPSS2:25A限流,CBC Cmpss2Regs.CMPSSDACCTL.bit.DACSOURCE = 0; Cmpss2Regs.CMPSSDACVAL.bit.DACVAL = 2.475 / 3.3 * 4096; // 约3072 Cmpss2Regs.CMPSSCTL1.bit.COMPDACE = 1; Cmpss2Regs.CMPSSCTL1.bit.COMPHSOURCE = 0; Cmpss2Regs.CMPSSCTL1.bit.INVHSOURCE = 0; Cmpss2Regs.CMPSSCTL2.bit.CTRIPHSEL = 0; Cmpss2Regs.CMPSSCTL2.bit.CTRIPHFILEN = 1; Cmpss2Regs.CMPSSCTL2.bit.CTRIPHFILCLK = 0; Cmpss2Regs.CMPSSCTL2.bit.CTRIPHFILTHRESH = 4; Cmpss2Regs.CMPSSCTL2.bit.CTRIPHINV = 0; Cmpss2Regs.CMPSSCTL1.bit.CTRIPHLATCH = 0; // CBC不需要锁存,故障消失可自动恢复 EDIS; }这段代码里有两处值得单独解释。一是滤波:CMPSS1是30A短路保护,按理说延迟越小越好,但开关振铃也是客观存在的,所以我开了连续4次采样滤波,这个配置在SYSCLK为120MHz时大约会带来几十纳秒的延迟,对IGBT保护仍然够快。二是故意不给CMPSS1开锁存以外的复杂配置,因为30A是一次性故障,触发后就应该锁死,等待人工复位。
5.3 DCEVT和Trip-Zone配置代码
接下来把两个CMPSS事件接到EPWM1的Trip-Zone上:
void EPWM_TripZone_Init(void) { EALLOW; // DCEVT源选择:DCAH接CMPSS1 CTRIPH,DCAL不接 EPwm1Regs.DCTRIPSEL.bit.DCAHCOMPSEL = 0; // CMPSS1 CTRIPH EPwm1Regs.DCTRIPSEL.bit.DCALCOMPSEL = 1; // CMPSS2 CTRIPH // DCFCTL:使能blanking,用PWM周期事件产生blanking窗口 EPwm1Regs.DCFCTL.bit.PUSHSRC = 0; // 输入源为DCTRIPSEL选择后的信号 EPwm1Regs.DCFCTL.bit.BLANKEN = 1; EPwm1Regs.DCFCTL.bit.BLANKE = 0; // 使用T2周期事件作为blanking参考 EPwm1Regs.DCFCTL.bit.BLANKINV = 0; // 窗口在参考事件之后 EPwm1Regs.DCFCTL.bit.BLANKPULSE = 100; // 1us窗口(需要根据PWM周期换算) // DCAEVT1:使用滤波后的输入,作为one-shot触发 EPwm1Regs.DCACTL.bit.EVT1SRCSEL = 1; // 使用滤波后的输入信号 EPwm1Regs.DCACTL.bit.EVT1FRCSYNCSEL = 0; EPwm1Regs.DCACTL.bit.EVT1SOCE = 0; // 不触发ADC SOC // DCAEVT2:同样使用滤波后输入,用于CBC限流 EPwm1Regs.DCACTL.bit.EVT2SRCSEL = 1; EPwm1Regs.DCACTL.bit.EVT2FRCSYNCSEL = 0; EPwm1Regs.DCACTL.bit.EVT2SOCE = 1; // 限流事件同时触发ADC采样,记录电流值 // TZSEL:DCAEVT1 -> OST,DCAEVT2 -> CBC EPwm1Regs.TZSEL.bit.DCAEVT1 = 1; // one-shot EPwm1Regs.TZSEL.bit.DCAEVT2 = 3; // CBC // TZCTL:故障时EPWMxA和EPWMxB都强制低 EPwm1Regs.TZCTL.bit.TZA = 2; // 2 = force low EPwm1Regs.TZCTL.bit.TZB = 2; // 2 = force low // 使能TZ中断:OST和CBC都进中断 EPwm1Regs.TZEINT.bit.OST = 1; EPwm1Regs.TZEINT.bit.CBC = 1; EDIS; }这段代码有几个容易踩的细节。第一,DCACTL的EVT2SRCSEL是EVT2的源选择位,需要看数据手册的位域定义,它和EVT1不完全一样。第二,BLANKPULSE的单位不是纳秒,而是由PWM时基时钟决定的计数值,所以要计算好。第三,CBC模式下,即使故障信号消失,TZFLG的CBC标志也必须由软件清除,否则PWM不会恢复——这一点经常被当成“CBC坏了”来排查,其实只是没清标志。
5.4 中断服务程序与故障恢复逻辑
TZ中断ISR中,读取TZFLG和CMPSS状态寄存器,判断是过流(OST)还是限流(CBC):
__interrupt void epwm1_tz_isr(void) { uint16_t tzflg = EPwm1Regs.TZFLG.all; if (tzflg & TZFLG_OST_MASK) { // 过流故障:锁死PWM输出,点亮故障灯,记录错误码 fault_code = FAULT_OVERCURRENT; EPwm1Regs.TZCLR.bit.OST = 1; // 清除OST标志 // 注意:此时PWM输出仍处于强制低状态,必须重新初始化才能恢复 // 因此这里什么都不做,等待人工复位 } if (tzflg & TZFLG_CBC_MASK) { // 逐周期限流事件:清除标志即可,PWM会自动恢复 EPwm1Regs.TZCLR.bit.CBC = 1; } EPwm1Regs.TZCLR.bit.INT = 1; // 最后清除中断标志 PieCtrlRegs.PIEACK.all = PIEACK_GROUP3; }注意ISR里清除顺序:先清TZFLG的OST/CBC,再清INT。如果你的代码里反过来,很可能中断反复进入,因为中断标志一直被置位。还有一个细节,OST触发后PWM输出会被强制到安全状态,但这并不意味着EPWM时基停止了——时基仍然在跑,只是输出通道被强制住。所以在人工复位时,你不光要清TZ标志,还要检查是否需要重新执行一遍EPWM初始化,把输出重新使能。CBC恢复时则不需要,它会在下个周期自动恢复正常调制度。
5.5 上板实测:用TZFRC模拟故障验证保护链路
写代码只是第一步,上板验证才是关键。我的习惯是先做“无电流强制触发测试”:给系统上电,PWM正常输出,然后用一行代码软件强制触发TZ:
EALLOW; EPwm1Regs.TZFRC.bit.OST = 1; // 模拟过流 EDIS;用示波器同时观察EPWM1A和EPWM1B引脚,以及CMPSS1输入信号。正常情况下,PWM波形会立刻变为低电平,而且不会再恢复。从TZFRC置位到引脚真正变低的延迟,在示波器上几乎是同一个时刻,这正是硬件保护链路的意义。
接下来做真实过流测试。用小电流测试平台把电流慢慢加到25A,先观察CBC限流是否在正常运作——PWM会被限制在一个较低的有效占空比,电流不会继续上升,同时每次限流发生时CBC中断标志会周期性置位。然后继续加大电流到30A,一旦超过,PWM立刻被锁定为低,电机停转,故障指示灯亮。这个流程走通之后,这条保护链路才算真正可靠。
6. 工程实用经验:滤波脉宽、误触发规避与调试技巧
6.1 滤波参数和blanking窗口怎么权衡
我在第一部分提到过,滤波和blanking都是抗干扰的手段,但它们都会“偷走”一部分保护速度。实际调参时,我建议遵循以下顺序找出最优参数。先不开放任何滤波和blanking,让系统在额定工况下运行,观察有没有偶发的TZ触发。如果有,用示波器捕捉CMPSS输入信号,看触发时刻的波形特征。通常你会发现触发点正好在某个开关动作的上升沿或下降沿附近,这就明确指向开关振铃。此时再精确测量振铃持续时间,把blanking窗口设置为振铃窗口结束后的1.2倍,而不是随手填一个大数。如果blanking窗口覆盖完以后仍然有零星误触发,才考虑增加CMPSS的滤波采样次数。
有一点容易被忽略:blanking窗口的起点是PWM时基的周期或比较事件,所以如果你把PWM占空比调到很大,开关沿位置会发生变化,原本的blanking窗口可能不再和实际振铃位置对齐。因此参数定下来之后,最好在几个极端占空比下都跑一下,确保全范围内没有误触发漏洞。
6.2 排查“保护不动作”和“莫名其妙触发”的思路
“保护不动作”比“误触发”更危险。遇到PWM该降不降的情况,我有一套固定排查顺序。先用TZFRC强制触发,看Trip-Zone链路是不是好的,如果强制触发都没反应,那大概率是TZCTL的被强制状态配置错了,或者EPWM输出被其他模块(比如GPIO MUX)接管了。如果强制触发PWM能正确变低,那问题就出在CMPSS/DCEVT这层:比如CMPSS的DAC其实还没加载新值(shadow模式的问题),或者DCTRIPSEL的源选择落在了通道0上,又或者比较器输入引脚被MUX配置成了其他功能,芯片引脚根本没有把信号送进比较器。
误触发则集中在几个原因:CMPSS输入信号本身偏置太大,正常工作电流已经接近阈值;滤波参数太弱;blanking窗口没生效;或者TZSEL里本不该使能的源被使能了,比如外部TZ引脚悬空,被干扰拉低了。排查时我通常会把TZSEL里的所有源全部清掉,再一个一个使能,用二分法定位出哪条路径是凶手。
6.3 一个被很多人忽视的“软恢复”细节
关于CBC模式清标志和PWM恢复之间还有一个坑。CBC模式中,PWM是否恢复不仅取决于TZCLR的CBC标志是否清除,还取决于触发源信号在PWM周期边界时是否仍然有效。如果在清除CBC标志的瞬间,故障源还在(比如电流仍然超过25A),PWM不会恢复。只有当下一个PWM周期开始时,检测到故障源已经消失,并且CBC标志已被清除,PWM才会真正恢复。所以,软件想要实现“电流回落后自动恢复”,需要保证两件事:一是及时清除CBC标志,二是不要在故障源仍存在时去清标志,否则会出现“清了又马上触发”的假象。
6.4 这套机制能扩展的玩法
CMPSS和DCEVT不只是用来做过流保护,它还能做很多事情。比如用DCEVT事件触发ADC的SOC,在过流发生的那个周期立即启动采样,记录故障瞬间的电流值,这对事后分析非常有价值。再比如,DCEVT的输出可以通过TRIPOUT信号引出到外部,接到下一级功率器件的驱动封锁引脚。还有一些电源项目里,会用CMPSS做输入电压的快速前馈,在母线电压突然跌落时,用CBC模式逐周期降低占空比,防止电感电流失控。玩法非常多,但底层都是这套架构。
我个人的体会是,做C2000项目,一定要舍得花时间先把保护链路焊死在“不依赖软件”的基础上,再回头调控制环。因为功率电路出问题,往往是毫秒级甚至微秒级的事,软件再聪明也扛不住这种速度。CMPSS、DCEVT、Trip-Zone这套三层架构你把它吃透了,它不仅能救你的功率器件,还能大幅缩短整机调试时间——很多故障从“烧管子”变成了“记录故障码”,这种事情多经历几次,你就知道它的价值了。