做电机控制、数字电源这块的朋友,对TI C2000家族里的CMPSS(Comparator Subsystem,比较器子系统)应该不陌生。F280049上有4组CMPSS,每一组里包含两个模拟比较器、两个12位DAC、数字滤波器和斜坡发生器,最关键的是它可以直接和PWM模块的Trip Zone(TZ)联动,实现纯硬件的过流保护、过压保护。也就是说,CPU还没反应过来,PWM已经被硬件拉掉了,这对功率器件保护来说,是最后一道救命防线。
这篇就按我在实际调板子时的顺序,把CMPSS从内部结构、寄存器配置、代码实现到调试排坑整个走一遍,末尾还附了一段可以直接拿去做过流保护触发的完整示例代码。不管你是刚接手F280049的新人,还是想用硬件比较器替代“ADC采样+软件判断”保护逻辑的老手,这篇应该都能帮你省下不少时间。
1. CMPSS到底解决什么问题,内部结构怎么理解
1.1 为什么非要硬件比较器,软件判断不行吗
很多人第一次接触CMPSS都会有这个疑问:我ADC采电流、进中断、判断阈值、封波,难道不行?不是不行,是“不够快、不够稳”。
软件过流检测完整路径大概是:电流信号经过采样电阻或霍尔传感器,进运放调理,再进ADC,ADC转换完成后触发中断,中断服务函数里读结果、做阈值判断,最后修改PWM寄存器去封波。这条路走下来,短则几微秒,长则几十微秒,而且中间还受中断优先级、其他任务干扰、编译器优化等因素影响,响应时间并不确定。
电机堵转、功率管直通这类故障,相电流在微秒量级就能从正常工作电流冲到远超器件额定值。你拿软件判断,等检测到的时候,MOSFET或者IGBT可能已经过热甚至击穿了。CMPSS不一样,它是纯模拟比较器,信号跨越阈值那一刻,比较器输出在纳秒到百纳秒级翻转,再通过内部交叉开关直接送到PWM的TZ引脚,硬件强制拉高/拉低PWM输出。整个链路不依赖CPU,是“硬连线”的保护通道。
所以我的观点很明确:CMPSS这类模块不是ADC的替代品,而是ADC之上额外的一道硬件保护墙。你要让它替代软件保护,它就干这个活;你要拿它做峰值电流模式控制里的逐周期限流,它也能干。它就是功率变换器里专门干“快保护”的。
1.2 内部四个部分,一图看懂信号链路
F280049的CMPSS模块,内部大致可以拆成四块:比较器(CMPH/CMPL)、DAC参考、数字滤波器、输出与状态逻辑。我用文字把信号链路捋一遍:
模拟输入信号从CMPINxP和CMPINxN两个引脚进来,进到比较器的正端和负端。比较器把这两个电压一比,输出一个0/1电平。这个“原始比较结果”可以不走滤波直接出去,也可以先经过数字滤波器把毛刺滤掉,再形成CTRIPH(高电平比较器触发)和CTRIPL(低电平比较器触发)信号。CTRIP信号有四路输出可供选择,之后接到芯片内部的交叉开关(X-BAR),最终映射到PWM模块的TZ输入或者某个GPIO。
这里有两个比较器:CMPH和CMPL。CMPH带宽更高、响应更快,适合做过流、过压这类快速保护;CMPL偏省功耗、适合长时间在线的低频监测,比如输入电压跌落检测。两个比较器各有自己独立的DAC,也就是说你可以给CMPH设一个2.5V阈值,同时给CMPL设另一个1.8V阈值,互不干扰。
每个CMPSS还带一个斜坡发生器(RAMP),这是给峰值电流模式控制做斜率补偿用的。它可以在一个开关周期内让DAC阈值自动线性变化,用来抑制次谐波振荡。这块比较复杂,真正用的人不多,但这功能确实是CMPSS的一大特色,我在4.4节再稍微展开。
1.3 CTRIP输出和PWM TZ是怎么接上的
这是CMPSS配置里最容易绕晕的地方。你不是光配置CMPSS本身就行,还得把它的输出信号“路由”到PWM模块的TZ输入上。
F280049内部有一套 X-BAR(交叉开关),CMPSS的CTRIP输出信号会作为X-BAR的输入源。你需要在X-BAR里做一次“源选通”配置,让某个TZ输入通道接收CMPSS1的滤波后CTRIPH信号。然后在PWM模块里,再把TZ输入对应的触发事件使能,并配置触发后的动作——比如把PWM输出强制置为高阻、强制拉低,或者逐周期封锁。
注意这个链路是“CMPSS产生信号 -> X-BAR路由 -> PWM TZ接收并执行动作”,三个环节缺一不可。很多新手卡在“CMPSS配置没问题,CTRIP在寄存器里也能看到翻转,但PWM就是没反应”,十有八九是中间X-BAR那一环没配上。
1.4 什么时候需要CMPSS,什么时候不需要
也不是所有项目都必须上CMPSS。我的判断标准是这样的:
如果系统里只有慢速过温保护、状态监测这类需求,ADC完全够用,没必要上CMPSS。但如果电路里存在:输出短路、相间直通、负载突变导致的瞬时过流、数字电源里的逐周期限流、或者任何“超过阈值必须在一个微秒内动作”的场景,那CMPSS就是刚需。
电机驱动里最常见的就是相电流过流保护,把采样电阻上的电压直接送进CMPINxP,DAC阈值设为“最大允许电流对应电压”,CTRIP接PWM TZ,动作置为高阻。这一套下来,硬件自动封波,软件只需要记录故障标志、做故障复位即可,保护可靠性比纯软件方案高一个量级。
2. 配置前必须拿捏准的几个关键参数
2.1 DAC参考电压选择与阈值计算
CMPSS内部DAC产生的参考电压,是用来和外部输入信号做比较的基准。你首先得想明白:CMPINxP上正常信号范围是多少,故障阈值电压又是多少,然后才能算DAC的写入值。
DAC的满量程参考由COMPDACCTL寄存器的DACSOURCE位决定,通常可选VDDA(3.3V模拟电源)或者内部高精度参考(约1.2V)。选3.3V还是1.2V,取决于你的信号范围。如果被监测信号本来就接近0~3.3V范围,就用VDDA;如果信号很小、需要更细腻的阈值分辨率,就选1.2V内部参考。需要注意的是,选择1.2V参考时,DAC满量程对应的是1.2V附近,输入信号不能超过这个范围,否则比较器一直输出“超过阈值”,保护就失去意义了。
12位DAC的阈值计算很简单:
DACVAL = 目标阈值电压 / 满量程参考电压 * 4095
举一个实际例子:我在一块电源板子上做过流保护,采样电阻0.01欧姆,设计保护电流60A,那阈值电压就是0.6V。当时选VDDA 3.3V作为DAC参考,算下来DACVAL = 0.6 / 3.3 * 4095 ≈ 745。如果你用的是16位高精度模式,寄存器会换成COMPDACVALA,写入值要按65536满量程计算,并且注意是左对齐还是右对齐,这个必须以TRM的寄存器描述为准,不同批次器件可能有细节差异。
2.2 比较器正负端选择:外部引脚还是内部DAC
CMPSS每个比较器都有正输入和负输入。在F280049上,正输入CMPINxP和负输入CMPINxN都引到了芯片引脚上,但也有一种更常用的接法:负输入不接外部引脚,而是内部直连到DAC输出。
这两种接法各有适用场景。外部负输入接法适合“两个外部信号直接比较”的场景,比如你用外部基准电压芯片产生一个精密阈值,或者同时比较两路模拟信号。内部DAC负输入接法更通用,它等于把“阈值电压”变成了软件可编程的数值,你可以在程序里根据工况动态调整保护点,不用改硬件。
我当时做电机驱动时,负输入就是内部DAC,正输入接相电流采样信号。这样调节试电流限制值时,直接改DACVAL就行,连烙铁都不用动。有一点需要注意:选择内部DAC作为负输入时,CMPINxN引脚就释放出来了,别随意悬空,毕竟引脚输入本身也可能会引入干扰,最好在PCB上做一个短接到地的处理。
2.3 数字滤波器:毛刺和响应速度怎么权衡
CMPSS比较器输出翻转极快,这是优点,但也因为太快,一个几十纳秒的干扰尖峰就可能引发误触发。所以CMPSS内部设计了数字滤波器,由CTFILCT寄存器里的SAMPWIN和THRESH两个字段控制。
SAMPWIN定义采样窗口长度,单位是滤波时钟周期;THRESH是窗口内“反相样本”的个数阈值。只有在一个窗口内检测到超过THRESH个反相信号,比较器输出才会跟着翻转。本质就是一个“计数防抖”逻辑,和按键消抖一个思路。
这里要特别注意,滤波器的延迟直接影响保护响应时间。我见过有人把滤波参数设得特别大,结果过流信号到了,PWM要等两三微秒才被封掉,这就违背了用CMPSS做快速保护的初衷。我的经验是:先按无滤波或极小滤波把功能和阈值调通,然后用示波器观察实际运行中CTRIP翻转的毛刺频率,再逐步增加SAMPWIN和THRESH,直到误触发消失且响应延迟可接受。不要一上来就把滤波拉到最大,给自己埋坑。
2.4 从信号越过阈值到PWM动作,总共要多少时间
CMPSS的整个保护链路延迟,粗略拆成三部分:比较器翻转延迟、数字滤波窗口延迟、X-BAR到PWM动作的传播延迟。
比较器本身翻转大约几十纳秒,数字滤波延迟取决于SAMPWIN和滤波时钟,X-BAR和PWM TZ动作延迟大概也在几十纳秒量级。如果不开滤波,整个链路通常在几百纳秒内就能走完,这是“硬件保护”比“软件保护”快几个数量级的关键。开了滤波之后,延迟就要把窗口时间算进去,这一点在设计保护参数时必须心里有数。
我在调试数字电源的时候,会专门把“阈值跨越时刻”和“PWM输出关闭时刻”同时抓到示波器上,量一下实际延迟。这样既能验证配置是否生效,也能验证是否留够了保护裕量。如果你发现延迟远超预期,优先检查数字滤波窗口和X-BAR路由是不是中间被别的东西拖慢了。
3. 手把手配置CMPSS:寄存器级代码实战
3.1 初始化主框架:时钟、引脚、CMPSS使能顺序
在F280049里,CMPSS属于系统外设,第一步是把外设时钟打开。用C2000Ware的driverlib是这样写的:
// 使能CMPSS1外设时钟 SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CMPSS1);如果你用传统寄存器方式,对应的操作是把PCLKCR0寄存器里CMPSS1的时钟使能位置1。建议先用SysCtl_enablePeripheral,这样代码更清晰,也更好维护。
时钟使能之后,要配置GPIO引脚复用。CMPSS的模拟输入引脚在GPIO MUX表里有对应的复用功能编号,需要把那几个引脚从普通GPIO模式切成CMPIN模式。这一步可以手动写GPIO寄存器,也可以在SysConfig工具里图形化选择CMPSS1、使能输入引脚,自动生成代码。手动写法大致长这样:
// 以CMPSS1_INP为例,GPIO编号和mux值需要按板子原理图和F280049C数据手册填写 GPIO_setPinMux(CMPSS1_INP_GPIO, GPIO_MUX_CMPIN1P); GPIO_setDirectionMode(CMPSS1_INP_GPIO, GPIO_DIR_MODE_IN);这里有个小坑:CMPIN是模拟输入,不能像普通GPIO那样配置上拉/下拉,保持高阻输入就行。如果你看到配置后引脚上电压被拉偏,八成就是复用配置没写对,或者某个GPIO上拉被意外使能了。
3.2 配置DAC阈值:COMPDACCTL、COMPDACVAL
DAC配置是CMPSS比较阈值的关键。以CMPSS1为例,配置2.5V阈值电压,DAC参考选VDDA 3.3V,12位模式下计算得DACVAL约等于3102。
// 配置CMPSS1 DAC CMPSS1_REGS.COMPDACCTL.bit.COMPDACEN = 0; // 先关闭DAC,修改参数 CMPSS1_REGS.COMPDACCTL.bit.DACSOURCE = 0; // 0: VDDA参考, 1: 内部高精度参考 CMPSS1_REGS.COMPDACCTL.bit.SELCOMP = 0; // 0: 该DAC给CMPH用; 1: 给CMPL用 CMPSS1_REGS.COMPDACVAL.bit.COMPDACVAL = 3102; // 2.5V / 3.3V * 4095 ≈ 3102 CMPSS1_REGS.COMPDACCTL.bit.COMPDACEN = 1; // 写入完成,使能DAC读代码的时候容易忽略SELCOMP这一位,但它非常重要。它决定这组DAC的输出是给CMPH还是CMPL参考。如果CMPH用的是DAC0,CMPL用的是DAC1,而你只改了DAC0却指望CMPL阈值变化,那肯定是徒劳。项目里如果CMPH和CMPL都要用,脑子里必须有一张“DAC和比较器对应关系”的图。
3.3 配置比较器输出路径:CTRIPSEL、CTRIPOUTSEL、数字滤波
DAC阈值设好之后,下一步配置比较器本身的输出路径。
// 配置CMPH比较器的触发源和输出选择 CMPSS1_REGS.CMPHCTL.bit.CTRIPSEL = 0; // 选择CMPH比较器输出作为源 CMPSS1_REGS.CMPHCTL.bit.CTRIPOUTSEL = 1; // 1: 使用滤波后的输出; 0: 使用原始输出 CMPSS1_REGS.CMPHCTL.bit.CTRIPFILEN = 1; // 使能数字滤波,只有CTRIPOUTSEL=1时才有意义如果希望比较器输出完全不过滤、追求极速响应,CTRIPOUTSEL设0即可。但如果选了0,CTRIPFILEN即使置1也不起作用,这一个组合关系很容易让人踩坑。
启用滤波时,要设置CTFILCT寄存器:
// 数字滤波参数:窗口16个样本,阈值8个反相样本 CMPSS1_REGS.CTFILCT.bit.SAMPWIN = 15; // 窗口长度 = SAMPWIN + 1 = 16 CMPSS1_REGS.CTFILCT.bit.THRESH = 8; // 窗口内至少8个反相样本才翻转需要注意的是,SAMPWIN和THRESH具体对应的滤波延迟时间,要以F28004x TRM里给出的公式为准。不要随便拍脑袋定这两个数,否则“保护慢半拍”和“干扰乱触发”你会轮流体验一遍。
3.4 把CTRIP信号路由到PWM TZ:X-BAR配置
CMPSS配置完成只是第一步,接下来最关键的是中间路由。
简单说就是两步:第一步在Input X-BAR里把CMPSS1的某一路CTRIP输出映射到PWM TZ输入通道;第二步在PWM模块的TZ逻辑里,把这个输入通道对应的事件使能,并定义触发动作。
用driverlib的大致风格是:
// Input X-BAR: 把CMPSS1的滤波后CTRIPH信号接到TZ输入通道1 XBAR_setInputSource(XBAR_TRIP1, XBAR_CMPSS1_CTRIPH_FILT); // PWM模块TZ配置:TZ输入通道1对应的事件1使能,触发后封锁PWM输出 EPwm1Regs.TZSEL.bit.DCAEVT1 = 1; // 使能数字比较A事件1 EPwm1Regs.DCACTL.bit.EVT1SRCSEL = 1; // 事件源来自Input X-BAR EPwm1Regs.TZCTL.bit.DCAEVT1TOSA = 1; // 输出A强制高阻 EPwm1Regs.TZCTL.bit.DCAEVT1TOSB = 1; // 输出B强制高阻 EPwm1Regs.TZFLGCLR.bit.OST = 1; // 清除TZ事件标志各位千万别把这里的API名和寄存器位名当“标准答案”去背,因为不同SDK版本、不同器件型号,函数签名和位定义可能有差异。关键在于理解流程:CMPSS -> X-BAR -> PWM TZ。用SysConfig的XBAR连接可视化界面拖线,是最直观、最不容易出错的配置方式,尤其是刚上手时,强烈建议先用SysConfig生成基础代码,再去手动改优化寄存器。
3.5 读取比较结果与中断处理
有时候你并不需要CMPSS触发PWM TZ,而只是想读取比较结果做状态判断,那就直接读状态寄存器。
uint16_t cmpStatus = CMPSS1_REGS.CMPSSSR.bit.CMPHSTS; // 读取CMPH比较结果这里有个很容易忽视的细节:CMPSSSR是“读清零”寄存器。你在调试代码里读一次状态,就可能把故障标志清掉了,导致后续中断逻辑判断错乱。正确做法是:需要记录故障时,先把CMPSSSR保存到局部变量,再基于这个变量做判断,而不是反复直接读寄存器。
如果需要进中断处理,还要配置PIE中断使能、CMPSS1中断源选择等。CMPSS中断响应路径比较直接,但注意保护的“第一道防线”永远是PWM TZ硬件动作,CMPSS中断只是用来“善后”,记录故障、做状态上报,不要指望中断里的软件动作来真正保护功率器件。
4. 调试路径与常见问题排查实录
4.1 用信号发生器把CMPSS“打通”
这套模块配置完毕,先别急着接真实电机或功率级,很容易把板子烧了。我习惯先把CMPSS当作一个独立器件来验证。
用信号发生器在CMPIN1P上灌一个偏置电压,DAC阈值设为2.5V,然后让信号发生器输出2.5V以下/以上的直流电平,观察CTRIP输出状态是否翻转。再用示波器一路测输入电压、一路测CTRIP,手动把电压从2.4V慢慢调到2.6V,看翻转点准不准。
这个测试能做到“电压过阈值,CTRIP立即翻”之后,再接X-BAR、PWM TZ链路。我调过很多次,这套分步验证法能省下大量排查时间,因为你一旦把“CMPSS本身是好的”确认了,后面出问题基本就锁定在X-BAR路由和PWM TZ配置上。
4.2 常见问题速查表
| 现象 | 可能原因 | 排查建议 |
|---|---|---|
| 改了DACVAL但阈值不生效 | DAC未重新使能、SELCOMP选错DAC、参考源不对 | 回读COMPDACVAL,确认COMPDACEN=1 |
| CTRIP一直为高/一直为低 | 正负输入端接反、阈值电压不对、输入信号超出比较器共模范围 | 用万用表量CMPINP/CMPINN电压,对比DAC阈值 |
| CTRIP在无故障时乱跳 | 引脚干扰、数字滤波太弱、PCB走线靠近开关节点 | 加大SAMPWIN/THRESH,输入端加RC滤波 |
| CTRIP翻转正常但PWM没封波 | X-BAR路由没配置、PWM TZSEL事件没使能、TZ动作配置无效 | 先查X-BAR源选通,再查TZCTL动作字段 |
| 读取CMPSSSR后中断逻辑混乱 | CMPSSSR读清零,状态被调试代码清掉 | 先把状态存到局部变量再处理 |
| PWM封波后无法恢复 | TZ配置成了锁存模式(OSHT),需要软件清除标志 | 写TZFLGCLR,或改用逐周期(CBC)模式 |
4.3 几个亲身踩过的坑
第一个坑是DAC的“缓冲锁存”。CMPSS的DAC写入不是立刻生效的,部分位域需要等模块时钟走几个周期,且使能顺序不能错。我在项目里遇到过“改了DACVAL,阈值纹丝不动”,后来发现是COMPDACEN被我在参数更新时关掉了,又没重新置1,等于一直在用上一次的旧阈值。所以记得:修改阈值前关DAC,修改完成后开DAC,缺一不可。
第二个坑是滤波参数的“保命错觉”。有段时间电机驱动老是无缘无故保护停机,我以为是干扰,就把SAMPWIN和THRESH调大,结果误触发确实少了,但后来用示波器实测,保护延迟从不到1微秒飙到接近10微秒。当时就出了一身冷汗:幸好没真出短路故障,否则这“保护”根本保护不了。从那以后我给自己定了规矩:滤波参数必须配合示波器实测延迟,绝不能盲调。
第三个坑是PCB布局和参考地。CMPIN的模拟输入走线一定要远离功率管的开关节点和电感,采样信号线尽量短而粗,DAC参考电容要靠近芯片引脚放。我有一块板子,CMPSS在原理图、代码里怎么查都没问题,就是CTRIP偶尔误触发,后来把采样线换了屏蔽层、调整了布线,问题才消失。硬件比较器对“比较输入质量”非常敏感,你的参考电压不干净,阈值就是漂的。
第四个坑,也是我认为最重要的一个:千万别把CMPSS的“中断恢复”当成“保护恢复”。PWM TZ触发封波之后,故障源可能还在,比如电流如果真的短路,你软件里清标志、关中断,让PWM恢复输出,等于在明知故障的情况下重新给功率级上电。正确做法是:封波后先持续监测CMPSS状态,确认过流信号消失并等待一段安全时间,再做恢复动作,否则就是拿一整套系统在赌。
4.4 进阶思路:斜坡发生器与双阈值窗口比较
CMPSS里真正有深度的是斜坡发生器(RAMP)。做峰值电流模式控制时,电感电流内环很容易在占空比大于50%时产生次谐波振荡,传统做法是在电流采样信号上叠加一个斜率补偿的斜坡,抵消振荡。CMPSS的RAMP就是干这个的:它在开关周期内让DAC阈值自动变化,等效于给电流环加了斜坡补偿。这样一来,硬件限流和斜率补偿可以共用一个比较器模块,电路能省不少元件。
另外一个实用玩法是“双阈值窗口比较”:把CMPH的上限阈值和CMPL的下限阈值都配置好,比如CMPH设2.5V,CMPL设1.2V,那么输入信号只有落在这两个阈值之间才视为正常,超出任何一端都触发保护。这在一些要求“既不能过压也不能欠压”的场景(比如母线电压监测)里特别方便,一个CMPSS模块就能搞定窗口监控。
我个人在实际调F280049时最大的体会是:CMPSS的坑大多不在比较器本身,而在“从比较器输出一路送到PWM TZ”这条链路的打通。按信号发生器验证CMPSS翻转、再配X-BAR、最后接PWM TZ这个顺序来,基本不会走弯路。等以后把RAMP配合峰值电流模式控制那套调完,我再专门写一篇斜率补偿的实践,欢迎到时候来看。