
1. 从寄存器手册到实际应用eHRPWM的实战配置逻辑如果你曾经在TI的C2000系列DSP或者类似的微控制器上折腾过电机控制、数字电源或者精密逆变器那你肯定绕不开eHRPWM这个模块。手册上那些密密麻麻的寄存器位描述比如TBPHS、CMPA、AQCTLA初看之下就像一本天书每个字都认识连起来却不知道该怎么用。我刚开始接触的时候也是对着手册配置了半天结果PWM输出要么没波形要么频率不对要么就是两路信号死活不同步调试过程堪称“玄学”。后来踩了无数坑才明白手册只是告诉了你“有什么”而真正要掌握的是“怎么用”以及“为什么这么用”。eHRPWM的寄存器配置本质上是在搭建一个精密的数字波形合成流水线。时基模块是你的节拍器计数器比较模块是你的乐谱标记点而动作限定器就是你的演奏家负责在标记点做出具体的动作拉高、拉低、翻转。今天我就结合自己这些年调试伺服驱动器和LLC电源的实际经验抛开那些晦涩的术语带你把这些核心寄存器“盘”明白让你能真正设计出稳定、可靠的PWM波形。2. 核心模块拆解eHRPWM的三大支柱在深入每个寄存器之前我们必须先建立起eHRPWM的顶层架构视图。它不是一堆孤立寄存器的堆砌而是由几个高度协同的子模块构成的。理解数据流配置才能有的放矢。2.1 时基模块波形的“心脏”与“节拍”时基模块是整个PWM生成的时序基准你可以把它想象成一个音乐节拍器或者一个高精度的数字时钟。它决定了波形的“心跳”节奏。这个模块的核心是三个寄存器TBPRD周期寄存器、TBCNT计数器寄存器和TBPHS相位寄存器。TBPRD寄存器设定了这个节拍器的“一圈”有多长。比如你的系统时钟SYSCLKOUT是100MHz经过预分频后得到时基时钟TBCLK为50MHz周期20ns。如果你将TBPRD设置为1000那么计数器TBCNT就会从0计数到1000然后根据计数模式递增、递减或增减进行重置或反转。这样一个完整的PWM周期就是 (1000 1) * 20ns 20.02us对应的PWM频率大约是49.95kHz。这里有个关键细节在递增计数模式下周期是 (TBPRD)在增减计数模式下周期是 (2 * TBPRD)。这个区别直接影响频率计算配置错了频率直接差一倍。TBCNT是当前计数值它实时反映“节拍器”走到了哪个位置。软件可以读写它但手册里特别警告写TBCNT操作不与TBCLK同步。这意味着如果你在计数器运行时直接写入一个新值这个值会立即生效可能导致计数器“跳变”产生一个非预期的、极窄的脉冲这在功率应用中可能是灾难性的。所以除非是在初始化阶段否则尽量避免动态写入TBCNT。TBPHS是相位寄存器这是实现多通道同步的关键。假设你有两个eHRPWM模块EPWM1A和EPWM2A要驱动一个全桥电路的上、下管你需要它们的PWM波互补且有死区但起始点必须严格对齐。如果仅仅让它们的计数器自由运行即使TBPRD设置一样由于启动时间的细微差别它们的相位也可能随机偏移。这时你可以将EPWM1设为主模块EPWM2设为从模块。当主模块的计数器归零时会产生一个同步输出信号EPWMSYNCOUT给从模块的同步输入EPWMSYNCIN。如果从模块的TBCTL[PHSEN]位使能在接收到同步信号的瞬间从模块的TBCNT就会立刻被加载为TBPHS寄存器中的值。如果你设置TBPHS为0那么从模块的计数器将与主模块严格同步从0开始。你还可以设置TBPHS为一个非零值来实现固定的相位差比如移相全桥拓扑中就需要这个功能。实操心得在初始化多个同步的eHRPWM通道时务必遵循“先配置后使能同步”的顺序。即先配置好所有从模块的TBPRD、TBPHS等参数最后再使能主模块的同步输出和从模块的相位加载使能位TBCTL[PHSEN]。否则你可能在配置过程中就意外触发了一次同步导致计数器状态混乱。2.2 计数器比较模块波形的“雕刻刀”节拍器时基提供了均匀的时间格而计数器比较模块则负责在这些时间格上“刻下”标记点告诉系统在“何时”需要改变输出状态。这个模块的核心是CMPA和CMPB这两个比较寄存器以及控制它们加载行为的CMPCTL寄存器。CMPA/CMPB寄存器里存放的就是那个关键的“比较值”。TBCNT计数器在每个TBCLK周期里都会和CMPA/CMPB的值进行比较。当两者相等时就会产生一个“匹配事件”CTRCMPA 或 CTRCMPB。这个事件本身并不直接改变GPIO引脚的电平它只是一个触发信号会被送到下一个模块——动作限定器去执行具体操作。这里引入了eHRPWM一个非常重要的概念影子寄存器。在复杂的实时控制中我们经常需要在下一个PWM周期才更新比较值比如根据电流环PI运算的新结果来更新占空比。如果直接写活跃寄存器Active Register可能会在计数器计到一半时改变比较值导致当前周期波形畸变。因此CMPA/CMPB通常配有一个影子寄存器Shadow Register。当你写入CMPA时数据实际上是先到了影子寄存器。然后由CMPCTL[LOADAMODE]位来决定影子寄存器中的值在何时“提交”给活跃寄存器。通常我们设置为在计数器归零CTR0或到达周期值CTRPRD时加载。这样就能保证比较值在整个PWM周期内是稳定的只在周期边界安全地切换。CMPCTL寄存器就是管理这个过程的“调度员”。SHDWAMODE/SHDWBMODE位决定CMPA/CMPB是工作在影子模式安全用于实时控制还是立即模式直接生效用于特殊调试。LOADAMODE/LOADBMODE位则精确控制加载时机。SHDWAFULL/SHDWBFULL状态位非常有用在写入前检查一下可以避免在影子寄存器已满即上一次的值还未加载时写入导致数据被覆盖。避坑指南在电机FOC控制中我们通常在ADC采样中断其触发点一般设在PWM周期中点或结束时里计算新的占空比并写入CMPA的影子寄存器。务必确保你的写入操作发生在影子寄存器被加载到活跃寄存器之前。一个常见的策略是将LOADAMODE设置为在CTRPRD时加载并在计数器到达PRD之前例如在CTRTBPRD/2的ADC中断里完成计算和写入。同时在写入前通过SHDWAFULL位判断寄存器状态是编写健壮驱动的好习惯。2.3 动作限定器模块波形的“执行者”动作限定器AQ是连接“事件”和“动作”的桥梁。它接收来自时基模块的事件CTRPRD, CTR0和比较模块的事件CTRCMPA, CTRCMPB并根据配置输出具体的引脚控制命令置高Set、拉低Clear、翻转Toggle或无操作Do nothing。AQCTLA和AQCTLB是两个核心配置寄存器分别控制EPWMxA和EPWMxB两个输出引脚。它们的位域结构是对称且清晰的以AQCTLA为例ZRO (Bits 1-0): 当计数器等于0时对EPWMxA做什么PRD (Bits 3-2): 当计数器等于周期值TBPRD时对EPWMxA做什么CAU (Bits 5-4): 当计数器等于CMPA且计数器正在递增时对EPWMxA做什么CAD (Bits 7-6): 当计数器等于CMPA且计数器正在递减时对EPWMxA做什么CBU/CBD同理对应CMPB事件。这里的“方向”关重要。在增减计数模式下计数器会先递增到TBPRD再递减回0。一个CMPA匹配事件在递增和递减阶段会各发生一次。通过为CAU和CAD设置不同的动作我们可以轻松生成中心对称的PWM波形这在电机控制和数字电源中极为常见。例如要生成一个在计数器递增和递减阶段对称的、高电平在中间的脉冲可以这样配置设置CAU 2 (Set)CAD 1 (Clear)。这样在递增到CMPA时输出拉高在递减到CMPA时输出拉低。AQSFRC和AQCSFRC寄存器提供了软件强制干预的能力。AQSFRC用于产生一次性的强制事件One-Time Force比如在特定时刻强行拉高或拉低输出用于测试或特殊同步。AQCSFRC用于产生连续的强制Continuous Force可以强行将输出锁定在高或低电平常用于故障安全状态或调试。特别注意连续强制模式的优先级高于动作限定器产生的事件。一旦使能连续强制为高或低正常的PWM生成就被覆盖了。3. 核心寄存器配置实战从理论到波形理解了各个模块的角色我们现在来实战配置生成几种最常用的PWM波形。我会以TI C2000的典型库函数风格结合寄存器操作来解释这样你既能看到底层原理也知道在DriverLib或类似库中如何调用。3.1 基础边沿对齐PWM生成这是最简单的模式计数器仅递增TBCTL[CTRMODE] 2即增计数模式。我们希望EPWMxA输出一个占空比为40%的PWM波。步骤拆解配置时基确定PWM频率。假设系统时钟150MHz预分频设为2TBCTL[HSPCLKDIV]和[CLKDIV]得到TBCLK 150MHz / 2 75MHz。计算TBPRD。目标频率为10kHz。在增计数模式下PWM频率 TBCLK / (TBPRD 1)。因此TBPRD (TBCLK / PWM频率) - 1 (75,000,000 / 10,000) - 1 7499。设置TBPHS 0 TBCNT 0。代码体现EPwm1Regs.TBPRD 7499;EPwm1Regs.TBPHS 0;EPwm1Regs.TBCTR 0;配置比较器计算CMPA值。占空比 (CMPA / (TBPRD 1)) * 100%。对于40%占空比CMPA 0.4 * (7499 1) 3000。配置CMPCTL使CMPA工作在影子模式并在CTR0时加载确保每个周期开始时更新占空比。代码体现EPwm1Regs.CMPA.half.CMPA 3000;EPwm1Regs.CMPCTL.bit.SHDWAMODE 0;EPwm1Regs.CMPCTL.bit.LOADAMODE 0; // Load on CTR0配置动作限定器我们需要计数器为0时输出置高开始一个脉冲。计数器等于CMPA时输出拉低结束脉冲。因此设置AQCTLAZRO 2 (Set),CAU 1 (Clear)。注意在增计数模式下我们只关心CAU递增匹配CMPACAD事件不会发生。代码体现EPwm1Regs.AQCTLA.bit.ZRO 2;EPwm1Regs.AQCTLA.bit.CAU 1;这样一个简单的边沿对齐PWM就配置完成了。波形从0开始为高电平计数到3000时变低并保持到周期结束7499。3.2 中心对称增减计数PWM生成这是电机控制和逆变器中最常用的模式能有效降低谐波。计数器先增后减TBCTL[CTRMODE] 0或3即增减计数模式。我们希望EPWMxA输出一个占空比为30%的中心对称PWM。步骤拆解配置时基频率计算不同了。在增减计数模式下PWM频率 TBCLK / (2 * TBPRD)。同样目标10kHzTBCLK 75MHz则TBPRD TBCLK / (2 * PWM频率) 75,000,000 / (2 * 10,000) 3750。代码体现EPwm1Regs.TBPRD 3750;配置比较器占空比计算也不同。对于中心对称PWM高电平时间对应计数器从(TBPRD - CMPA)递增到TBPRD再从TBPRD递减回(TBPRD - CMPA)。因此高电平时间占比 (2 * CMPA) / (2 * TBPRD) CMPA / TBPRD。对于30%占空比CMPA 0.3 * 3750 1125。代码体现EPwm1Regs.CMPA.half.CMPA 1125;配置动作限定器这是关键。我们需要在计数器递增阶段当它等于(TBPRD - CMPA)时输出置高当它等于TBPRD时输出拉低。在递减阶段当它再次等于TBPRD时输出置高当它等于(TBPRD - CMPA)时输出拉低。但注意在增减模式下PRD事件的方向被定义为递减ZRO事件的方向被定义为递增。因此更直观的配置方法是利用CAU和CAD设置CAU 1 (Clear)递增到CMPA即TBPRD - CMPA等等这里容易混淆。注意在增减模式下CMPA的比较是双向的。我们需要的是在TBPRD - CMPA这个点动作。但CMPA寄存器只有一个值。为了实现中心对称我们通常设置CMPA 1125并配置PRD 1 (Clear)当计数器到达周期值峰值时拉低。CAD 2 (Set)当计数器递减到CMPA值时置高。同时ZRO 2 (Set)当计数器回到0时置高。这样波形在0时置高递增到TBPRD - CMPA即2625时由于没有事件保持高电平递增到TBPRD3750时PRD事件将其拉低递减到CMPA1125时CAD事件将其置高递减到0时ZRO事件再次置高虽然此时已经是高电平但动作是重复的无影响。这就形成了一个以周期中点为中心对称的PWM波。代码体现EPwm1Regs.AQCTLA.bit.ZRO 2; // Set when CTR0 EPwm1Regs.AQCTLA.bit.PRD 1; // Clear when CTRPRD EPwm1Regs.AQCTLA.bit.CAD 2; // Set when CTRCMPA on down-count // CAU is not used in this configuration for the main pulse更常见的简化配置实际上为了生成一个简单的、高电平在中间、占空比为D的中心对称PWM我们可以只用一个动作在ZRO时置高在CAU时拉低假设CMPA已设置为D * TBPRD。但这样产生的脉冲是从0开始到CMPA结束并非严格中心对称。真正的中心对称需要结合PRD和CAD事件或者使用两个比较寄存器CMPA和CMPB来分别控制上升沿和下降沿这更灵活。3.3 带死区的互补PWM生成驱动半桥或全桥电路必须防止上下管直通这就需要插入死区时间。eHRPWM的死区模块DB位于动作限定器AQ之后。场景用EPWM1A和EPWM1B驱动一个半桥要求互补、带死区、高电平有效。步骤拆解配置时基和比较器如上所述配置好时基和CMPA用于控制占空比。配置动作限定器将EPWM1A和EPWM1B配置为互补输出。一种常见配置是对于EPWM1A (AQCTLA)ZRO2 (Set),CAU1 (Clear)。这产生一个从周期开始、在CMPA处结束的正脉冲。对于EPWM1B (AQCTLB)我们需要它与EPWM1A反相。可以配置为ZRO1 (Clear),CAU2 (Set)。这样EPWM1B在周期开始时为低在CMPA处变高。但此时两者是瞬间互补翻转的没有死区会直通。配置死区模块DBCTL[OUT_MODE]设置为3使能上升沿和下降沿延迟。DBCTL[IN_MODE]设置为0默认模式即EPWMxA作为两个延迟单元的输入源。DBCTL[POLSEL]设置为2AHC模式。这个模式非常关键它将EPWMxB的路径上的信号取反。结合前面的AQ配置我们来看发生了什么AQ产生原始的EPWMxA高-低和EPWMxB低-高信号。两者都送入死区模块。EPWMxA路径经过一个上升沿延迟DBRED和一个下降沿延迟DBFED。EPWMxB路径先被POLSEL2取反变成高-低然后再经过同样的延迟单。最终输出EPWMxA是原始信号经过死区延迟。EPWMxB是原始信号取反后再经过死区延迟。计算死区时间DBRED和DBFED是10位寄存器死区时间 DEL值 * TBCLK周期。例如TBCLK75MHz (13.33ns)要插入500ns的死区则DEL 500ns / 13.33ns ≈ 37.5取整为38。分别设置DBRED.DEL 38DBFED.DEL 38。代码体现EPwm1Regs.DBCTL.bit.OUT_MODE 3; // Enable both rising and falling edge delays EPwm1Regs.DBCTL.bit.POLSEL 2; // Active High Complementary mode (invert EPWMxB path) EPwm1Regs.DBCTL.bit.IN_MODE 0; // EPWMxA as source for both delay lines EPwm1Regs.DBRED 38; // Rising edge delay EPwm1Regs.DBFED 38; // Falling edge delay最终EPWM1A和EPWM1B将是带死区的互补PWM有效防止了直通。4. 高级应用与故障保护配置在实际工业产品中仅有波形生成是不够的还必须考虑系统的安全性和可靠性。eHRPWM的Trip-Zone故障保护模块就是为此而生。4.1 Trip-Zone故障保护机制解析Trip-Zone模块允许外部故障信号如过流、过压、过热传感器的输出直接、快速地关断PWM输出其响应速度远快于CPU中断。它支持两种触发模式Cycle-By-Cycle (CBC)当故障信号有效时立即在当前周期采取保护动作如将输出强制为低并在下一个PWM周期开始TBCNT0时自动清除保护状态如果此时故障已消失则PWM自动恢复正常。适用于可恢复的瞬时故障。One-Shot Trip (OST)当故障信号有效时立即采取保护动作并且该状态将被锁存直到软件明确清除故障标志。即使故障信号消失PWM输出也保持保护状态。适用于严重的、需要人工干预的故障。4.2 寄存器配置实战过流保护假设我们用TZ1引脚连接一个过流比较器的输出低电平有效。我们希望实现一个CBC保护过流时立即将EPWM1A和EPWM1B都强制拉低过流消失后PWM自动恢复。步骤拆解配置故障源选择 (TZSEL)将TZ1引脚配置为CBC故障源。TZSEL[CBC1] 1。 (OSHT1保持为0如果不需要OST功能)。代码EPwm1Regs.TZSEL.bit.CBC1 1;配置故障响应动作 (TZCTL)定义当CBC故障发生时输出引脚应采取什么动作。我们希望两个输出都强制拉低。设置TZA 2 (Force low),TZB 2 (Force low)。代码EPwm1Regs.TZCTL.bit.TZA 2;EPwm1Regs.TZCTL.bit.TZB 2;可选使能故障中断 (TZEINT)如果我们希望在故障发生时让CPU感知并记录日志可以开启CBC中断。TZEINT[CBC] 1。代码EPwm1Regs.TZEINT.bit.CBC 1;同时需要在PIE和CPU级使能对应的中断。处理故障标志 (TZFLG, TZCLR)当故障发生时TZFLG[CBC]位会被置1。对于CBC故障当计数器归零且故障信号已消失时硬件会自动清除故障动作但TZFLG[CBC]标志位需要软件手动清除以便记录故障事件。在中断服务程序或主循环中检查并清除标志if(EPwm1Regs.TZFLG.bit.CBC 1) { EPwm1Regs.TZCLR.bit.CBC 1; // Clear the flag ... // Log the fault event }关键注意事项Trip-Zone的强制输出动作优先级最高高于动作限定器AQ和软件强制AQSFRC。一旦故障发生配置的强制动作高、低、高阻会立即生效。高阻High-Z模式特别有用它可以快速关断外部驱动芯片如IGBT门极驱动器让功率器件进入安全状态。务必根据你的驱动电路设计来合理选择TZCTL的强制动作。5. 调试技巧与常见问题排查配置完所有寄存器下载程序结果示波器上什么都没有或者波形奇怪这是最让人头疼的阶段。下面是我总结的一套排查流程和常见坑点。5.1 基础检查清单时钟与使能确认eHRPWM模块的系统时钟SYSCLKOUT是否已使能外设时钟控制寄存器PCLKCRx中对应的eHRPWM时钟位是否打开这是最容易被忽略的第一步。引脚复用你使用的EPWMx输出引脚如GPIO0/GPIO1对应EPWM1A/B是否已正确配置为PWM功能检查GPIO MUX寄存器确保选择了正确的备用功能。时基是否运行在调试器中实时查看TBCNT寄存器的值它应该在每个TBCLK周期变化。如果一直是0说明时基没有启动检查TBCTL[CTRMODE]是否被设置为0停止模式了。输出是否被强制检查AQCSFRC寄存器CSFA和CSFB是否被意外设置为1或2强制高/低这会将输出锁死在固定电平。同样检查Trip-Zone标志TZFLG看是否发生了故障保护。5.2 典型问题与解决方案问题1完全没有PWM输出。排查步骤1检查GPIO配置和时钟使能见上。步骤2检查TBCTL[CTRMODE]确保不是0停止。尝试设置为2增计数或3增减计数。步骤3检查AQCTLA和AQCTLB是否所有动作位ZRO, PRD, CAU, CAD, CBU, CBD都配置成了0Do nothing至少需要有一个事件触发Set或Clear。步骤4使用软件强制测试。在初始化后手动设置AQSFRC[OTSFA]1和ACTSFA2Set看引脚是否能被强制拉高。如果能说明引脚和基础驱动是好的问题在AQ或更前端。问题2PWM频率不对。排查公式核对再次确认你使用的计数模式增/增减和频率计算公式。这是最常见的错误来源。时钟源检查TBCTL[PHSEN]和HSPCLKDIV/CLKDIV分频器配置是否正确。确认你计算的TBCLK频率与实际系统时钟匹配。寄存器写入时机确保TBPRD等寄存器是在时基计数器停止或同步安全时配置的。动态修改周期寄存器需要特别注意影子寄存器机制。问题3两路PWM不同步有固定相位差。期望EPWM1和EPWM2完全同步启动。现象每次上电两者相位差是固定的但非零。原因与解决这通常是因为从模块的计数器初始相位TBPHS没有在同步事件发生时被正确加载。确保主模块EPWM1的TBCTL[SYNCOSEL]配置为产生同步输出例如CTR0时输出。确保从模块EPWM2的TBCTL[PHSEN] 1使能相位加载。关键步骤在软件初始化时先配置从模块的所有参数包括TBPHS0最后再使能主模块的计数器。或者在主模块计数器运行后手动给从模块一个软件同步信号TBCTL[SWFSYNC]1并确保PHSEN1。问题4修改CMPA值占空比无变化。排查影子寄存器模式检查CMPCTL[SHDWAMODE]是否为0影子模式。如果你在直接写活跃寄存器模式SHDWAMODE1下写入会立即生效但可能与你期望的更新时机冲突。加载时机检查CMPCTL[LOADAMODE]。如果你设置为在CTRPRD时加载但你是在CTR0之后很快写入了新的CMPA值那么这个新值会在下一个周期结束时CTRPRD才被加载当前周期占空比不变。你需要确保写入时机在加载事件之前。FIFO满在高速连续写入时如高频PID更新检查CMPCTL[SHDWAFULL]位。如果为1说明影子寄存器已满新的写入会覆盖未加载的值导致数据丢失。你需要调整算法降低更新频率或确保在加载事件发生后写入。问题5死区时间不生效或效果不对。排查模块使能DBCTL[OUT_MODE]必须设置为2或3来使能上升沿或下降沿延迟。极性模式DBCTL[POLSEL]配置错误是最可能的原因。结合你想要的输出有效电平和AQ模块的配置仔细分析信号路径。用示波器同时观察AQ输出后的信号如果有条件和DB输出后的信号进行对比。输入源DBCTL[IN_MODE]决定了哪个信号进入延迟线。对于典型的互补带死区通常使用默认值0EPWMxA作为两路延迟的输入。调试eHRPWM逻辑分析仪或带数字通道的示波器是神器。可以同时捕捉多个EPWM输出引脚、甚至关键的内部事件标志通过IO模拟输出直观地看到计数器、比较匹配、死区插入等整个时间线上的逻辑关系比单纯看寄存器值高效得多。把配置寄存器想象成在搭建一个数字电路而示波器就是你检验电路工作是否正常的眼睛。