1. 从寄存器到波形:ePWM模块的底层控制哲学
在嵌入式电机控制和数字电源的世界里,我们常常谈论算法、模型和高级控制策略,但最终,所有这些精妙的构思都要落地为芯片引脚上一个个精确的脉冲。这个从“思想”到“物理信号”的桥梁,就是像TI C2000系列DSP中的增强型脉宽调制(ePWM)模块这样的硬件外设。而驾驭这头“硬件猛兽”的缰绳,正是那一组组看似冰冷、实则充满逻辑美感的寄存器。很多工程师在初学时,面对动辄几十页的寄存器手册会感到无从下手,觉得配置起来就是对着示例代码“照猫画虎”。但我想说,一旦你理解了寄存器配置背后的“因果链”和硬件行为逻辑,你就能从被动的代码搬运工,转变为主动的硬件架构师。这篇文章,我就以TI ePWM模块的几个核心寄存器组为线索,拆解从设置一个简单的比较值,到最终生成带保护、带同步的复杂PWM波形的完整过程,分享我这些年从“踩坑”到“避坑”的实战心得。
2. 核心寄存器组深度解析与配置逻辑
2.1 计数器比较子模块:CMPA/CMPB与影子寄存器机制
这是ePWM波形生成的“心脏”。CMPA和CMPB是两个16位的比较寄存器,它们的值会与时间基准计数器TBCTR进行实时比较。当TBCTR的值等于CMPA或CMPB时,硬件就会产生一个“匹配”事件。这个事件本身并不直接改变输出引脚的电平,它只是一个“通知”,告诉动作限定子模块:“嘿,比较事件发生了,你看看要不要做点什么?”
为什么需要两个比较寄存器?这提供了极大的灵活性。你可以用CMPA控制一个脉冲的上升沿(或下降沿),用CMPB控制另一个沿,从而独立地设置占空比和相位。在对称PWM(Up-Down计数模式)中,CMPA常用于控制占空比,而CMPB可以用于产生中心对齐的复杂波形或触发其他事件。
影子寄存器:硬件双缓冲的智慧这是ePWM设计中最精妙、也最容易出错的地方之一。以CMPA为例,你通过软件写入CMPA寄存器的值,默认并不是直接进入控制硬件的“有效寄存器”,而是先进入一个“影子寄存器”。CMPCTL[SHDWAMODE]位控制这个模式。
- 影子模式(SHDWAMODE=0):这是默认模式。你的写操作先更新影子寄存器,硬件会在一个特定的“加载点”自动将影子寄存器的值拷贝到有效寄存器。加载点由
CMPCTL[LOADAMODE]决定,通常是TBCTR=0(周期开始)或TBCTR=TBPRD(周期中点)。这保证了在一个PWM周期内,比较值是稳定的,避免了在计数器运行中途更新比较值可能导致的脉冲宽度畸变或毛刺。这对于电机控制这类需要严格同步的应用至关重要。 - 立即模式(SHDWAMODE=1):写入操作直接更新有效寄存器,立即生效。这适用于需要快速、实时调整PWM的场合,但风险是可能破坏当前周期的波形完整性。
实操心得:影子寄存器的“坑”与“桥”
- 状态查询:在影子模式下,如果你需要连续更新比较值,必须检查
CMPCTL[SHDWAFULL]位。如果该位为1,表示影子寄存器已满(即上一次写入的值还未被加载到有效寄存器),此时再写入会覆盖旧值,可能导致你丢失一个更新周期。安全的做法是在写入前轮询此位,确保其为0。- 同步更新:在电机控制中,我们经常需要同时更新多个PWM通道的占空比,以保证三相之间的对称性。利用影子寄存器,我们可以先依次计算并写入所有通道的
CMPA影子寄存器(此时硬件行为不变),然后通过软件强制一个同步事件,或者等待同一个TBCTR=0事件,让所有通道的影子寄存器值同时加载生效。这是实现无扰动切换的关键。- 高分辨率扩展:对于需要更高精度的场合(如数字电源环路),
CMPAHR寄存器提供了额外的8位小数分辨率。CMPA和CMPAHR可以组成一个24位的比较值(CMPA为高16位整数部分,CMPAHR为低8位小数部分)。注意,对CMPAHR的16位写入不会影响SHDWAFULL标志,但32位写入(同时写CMPA:CMPAHR)会。这要求你在做高分辨率PWM时,对数据写入顺序和时机有更精细的考量。
2.2 动作限定子模块:AQCTLA/B与软件强制
比较事件是“因”,引脚动作是“果”。连接因果的,就是动作限定寄存器AQCTLA和AQCTLB。它们定义了当特定事件发生时,对应的输出引脚EPWMxA或EPWMxB应该执行什么动作。
事件与动作的映射每个寄存器(如AQCTLA控制EPWMxA)被划分为多个2位字段,分别响应不同的事件:
ZRO:TBCTR = 0事件。PRD:TBCTR = TBPRD(周期值)事件。CAU/CAD:TBCTR = CMPA事件,且计数器在递增(CAU)/递减(CAD)。CBU/CBD:TBCTR = CMPB事件,且计数器在递增(CBU)/递减(CBD)。
每个字段可以配置为:
00:无动作(忽略事件)。01:清除(拉低输出)。10:置位(拉高输出)。11:翻转(高变低,低变高)。
通过配置组合生成标准PWM以生成一个简单的递增计数、高电平有效的PWM波(EPWMxA输出)为例:
- 设置
TBCTR在0到TBPRD之间递增计数。 - 设置
CMPA的值决定占空比(CMPA/TBPRD)。 - 配置
AQCTLA寄存器:ZRO=10(Set):计数器归零时,拉高EPWMxA。CAU=01(Clear):计数器递增到等于CMPA时,拉低EPWMxA。- 其他事件(如
PRD,CAD,CBU,CBD)均设为00(无动作)。 这样,每个周期开始时输出变高,当计数值达到CMPA时输出变低,直到周期结束,形成一个标准的PWM波。
软件强制寄存器(AQSFRC/AQCSFRC):调试与控制的利器这两个寄存器提供了通过软件直接干预输出状态的能力,无需等待硬件比较事件。
- 一次性软件强制(AQSFRC):
OTSFA/B位写1可以产生一个单次的强制事件,对应的ACTSFA/B位定义强制动作(清除、置位、翻转)。该位会自动清零。这在调试时非常有用,比如你可以手动产生一个脉冲来测试驱动电路。 - 连续软件强制(AQCSFRC):
CSFA/B位可以强制输出持续为高或低。这在故障安全状态下非常有用,你可以通过软件直接将所有PWM输出锁定为低电平(封锁驱动),其优先级高于动作限定器。特别注意:在影子模式下,连续强制动作要等到下一个影子加载事件(由AQSFRC[RLDCSF]配置)后才生效,这保证了同步性;而在立即模式下,则在下个TBCLK边沿立即生效。
2.3 死区生成子模块:DBCTL、DBRED与DBFED
在驱动半桥或全桥电路(如电机驱动的逆变桥)时,绝对不能允许上下桥臂的开关管同时导通(直通),否则会瞬间烧毁器件。死区就是在互补的PWM信号中插入的一段两个信号都为低电平的“安全区”。
死区模块的工作流程
- 输入选择(IN_MODE):决定哪个原始信号(来自动作限定器的
EPWMxA In或EPWMxB In)作为上升沿延迟和下降沿延迟的输入源。经典配置是EPWMxA In同时作为两路延迟的输入。 - 延迟生成:
DBRED寄存器配置上升沿延迟的时钟周期数,DBFED配置下降沿延迟的时钟周期数。延迟是基于TBCLK的。 - 极性选择(POLSEL):可选择是否对延迟后的信号进行取反,以生成适合不同驱动芯片(要求高电平有效或低电平有效)的互补信号。例如,
AHC模式(10)表示EPWMxB取反,常用于上管高有效、下管低有效的驱动逻辑。 - 输出模式(OUT_MODE):决定最终输出。
11表示完全使能死区,EPWMxA输出为带上升沿延迟的信号,EPWMxB输出为带下降沿延迟(并可能取反)的信号。其他模式可以部分禁用延迟,用于非对称或特殊波形生成。
避坑指南:死区时间的计算与影响死区时间
T_dead = DEL * T_tbclk,其中DEL是DBRED或DBFED的值,T_tbclk是TBCLK的周期。这个时间必须大于你所使用的功率器件(如MOSFET、IGBT)的“关断延迟时间”减去“开通延迟时间”,并留有一定裕量。常见误区:死区时间会“吃掉”有效的PWM占空比。例如,如果你设置的占空比是50%,加入死区后,实际导通时间会小于50%。在闭环控制(如电机FOC)中,这相当于引入了一个非线性的增益衰减,在极高或极低占空比时影响尤为显著。高级的控制算法有时需要对指令占空比进行前馈补偿,以抵消死区效应。
2.4 故障保护子模块:Trip-Zone寄存器组
工业应用必须安全可靠。Trip-Zone(故障区)是ePWM的硬件保护电路,当外部故障信号(如过流、过压、过热)触发时,它能以最快的速度(纳秒级)响应,绕过CPU,直接强制PWM输出进入安全状态。
三层配置逻辑
- 信号选择(TZSEL):配置哪些外部
TZ1~TZ6引脚信号可以触发本ePWM模块的故障。每个引脚可以独立配置为两种触发模式:- 单次触发(OSHTx):一旦触发,故障状态将锁存,直到软件明确清除(
TZCLR[OST])。适用于严重的、需要人工干预的故障(如短路)。 - 周期循环触发(CBCx):触发后,仅在当前PWM周期内有效,当
TBCTR回到0时自动清除。适用于可自恢复的瞬时故障(如瞬时过流)。
- 单次触发(OSHTx):一旦触发,故障状态将锁存,直到软件明确清除(
- 动作配置(TZCTL):定义当故障发生时,
EPWMxA和EPWMxB输出应被强制为何种状态。选项包括:高阻态(00,关断)、强制高(01)、强制低(10)、无动作(11)。对于大多数功率驱动场景,强制为低电平(10)是关闭功率管最安全的选择。高阻态需谨慎使用,取决于外部下拉电阻。 - 状态管理与中断(TZFLG, TZCLR, TZEINT):
TZFLG寄存器记录故障标志(OST,CBC,INT)。TZCLR寄存器用于软件清除这些标志。TZEINT寄存器用于使能故障中断,这样CPU可以在故障发生后进入中断服务程序进行故障记录、系统停机等处理。
软件强制故障(TZFRC):这个寄存器允许你通过软件模拟一个故障事件,用于测试保护逻辑是否正常工作,非常实用。
2.5 事件触发子模块:ETSEL与ETPS
ePWM不仅能输出PWM波,还能在波形的特定时刻(事件)产生中断或触发ADC开始转换,这对于实现精准的采样同步闭环控制至关重要。
事件选择(ETSEL)
SOCASEL/SOCBSEL:选择触发ADC开始转换A/B(EPWMxSOCA/B)的事件源。可选事件与动作限定器类似:TBCTR=0,TBCTR=TBPRD,TBCTR=CMPA(增/减),TBCTR=CMPB(增/减)。例如,在电流采样的FOC控制中,我们常将SOCA事件设置为在TBCTR=0或TBCTR=CMPA(中点采样)时触发ADC,以捕捉相电流。INTSEL:选择触发ePWM中断EPWMx_INT的事件源。SOCAEN/SOCBEN/INTEN:使能相应的触发或中断。
事件预分频与计数(ETPS)这是事件触发子模块的精华所在,它提供了“事件分频”或“事件计数”功能。
SOCAPRD/SOCBPRD/INTPRD:设置需要多少个选定事件发生,才产生一个ADC触发脉冲或中断。例如,设置为01是每个事件都触发,10是每两个事件触发一次,11是每三个事件触发一次。SOCACNT/SOCBCNT/INTCNT:只读计数器,显示当前已发生了多少个选定事件。
标志与清除(ETFLG, ETCLR)
ETFLG寄存器记录SOCA、SOCB和INT事件是否已发生。- 关键区别:
SOCA/SOCB标志位被置位后,硬件会继续产生触发脉冲。而INT标志位置位后,会阻塞后续的中断产生,直到软件通过ETCLR[INT]位将其清除。这意味着ADC可以连续触发采样,而中断则需要及时响应和清除,否则会丢失后续中断。
3. 典型应用场景的寄存器配置实战
理解了单个寄存器后,我们通过几个完整场景,把它们串联起来。
3.1 场景一:生成带死区的互补PWM驱动半桥
目标:用EPWM1A和EPWM1B驱动一个半桥,要求PWM频率20kHz,死区时间2us,高电平有效,带故障保护。
假设:系统时钟SYSCLKOUT=100MHz,TBCLK=SYSCLKOUT。
配置步骤:
时基模块(TB):
EPwm1Regs.TBPRD = 2500 - 1; // 周期值, 100MHz / 20kHz = 5000 TBCLK, 对称计数模式(Up-Down)需除以2 EPwm1Regs.TBCTL.bit.CTRMODE = 2; // 对称递增递减模式 EPwm1Regs.TBCTL.bit.PHSEN = 0; // 禁止相位加载 EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0; // TBCLK预分频 1 EPwm1Regs.TBCTL.bit.CLKDIV = 0;计数器比较模块(CC):
EPwm1Regs.CMPA.half.CMPA = 1250; // 初始占空比 50% (1250/2500) EPwm1Regs.CMPCTL.bit.SHDWAMODE = 0; // CMPA使用影子模式 EPwm1Regs.CMPCTL.bit.LOADAMODE = 0; // 在TBCTR=0时加载影子寄存器 // CMPB本例未使用,但需关闭其影子模式或设为安全值 EPwm1Regs.CMPCTL.bit.SHDWBMODE = 1; // CMPB立即模式 EPwm1Regs.CMPB = 0;动作限定模块(AQ):
// 配置EPWM1A:计数到0置高,计数到CMPA(递增)清零 EPwm1Regs.AQCTLA.bit.ZRO = 2; // Set on zero EPwm1Regs.AQCTLA.bit.CAU = 1; // Clear on CMPA up // 配置EPWM1B:我们希望它最终由死区模块生成互补信号,此处AQ可先不动作,或设为与A相反 // 更常见的做法是:让AQ生成一个原始PWM,然后由死区模块生成其互补带死区的信号 EPwm1Regs.AQCTLB.bit.ZRO = 1; // Clear on zero (与A相反) EPwm1Regs.AQCTLB.bit.CAU = 2; // Set on CMPA up (与A相反) // 这样,AQ输出给死区模块的就是两个互补的原始信号。死区模块(DB):
// 计算死区计数值:2us * 100MHz = 200个TBCLK周期 EPwm1Regs.DBRED = 200; // 上升沿延迟 EPwm1Regs.DBFED = 200; // 下降沿延迟 EPwm1Regs.DBCTL.bit.IN_MODE = 0; // 源为EPWMxA In EPwm1Regs.DBCTL.bit.POLSEL = 2; // AHC模式, EPWMxB输出取反 EPwm1Regs.DBCTL.bit.OUT_MODE = 3; // 使能上升沿和下降沿延迟 // 最终结果:EPWM1A = EPWMxA In 延迟上升沿200个周期。 // EPWM1B = (EPWMxA In 取反) 延迟下降沿200个周期。形成了带死区的互补信号。故障保护模块(TZ):
// 假设使用TZ1引脚作为过流保护,配置为单次触发 EPwm1Regs.TZSEL.bit.OSHT1 = 1; // 故障时,强制两路输出为低电平(安全状态) EPwm1Regs.TZCTL.bit.TZA = 2; // Force low EPwm1Regs.TZCTL.bit.TZB = 2; // Force low // 使能故障中断,以便CPU处理 EPwm1Regs.TZEINT.bit.OST = 1;
3.2 场景二:中心对齐PWM与ADC同步采样
目标:生成中心对齐PWM,并在每个PWM周期的中点(谷底)和起始点触发ADC采样,用于电流环计算。
配置步骤:
- 时基与比较值:与场景一类似,采用对称递增递减模式。
CMPA值控制占空比。 - 动作限定:配置为在
TBCTR=0和TBCTR=TBPRD时切换输出,以生成中心对齐的PWM。具体配置取决于你希望高电平在中间还是两边。 - 事件触发:这是关键。
这样,硬件会在每个PWM周期的精确时刻自动触发ADC转换,CPU则在周期中断中读取ADC结果并计算新的// 在PWM周期中点(TBCTR=CMPA且计数器递减时)触发ADC SOCA EPwm1Regs.ETSEL.bit.SOCASEL = 5; // 选择事件:TBCTR = CMPA when decrementing EPwm1Regs.ETPS.bit.SOCAPRD = 1; // 每个选定事件都触发一次 EPwm1Regs.ETSEL.bit.SOCAEN = 1; // 使能SOCA // 在PWM周期开始时(TBCTR=0)触发ADC SOCB EPwm1Regs.ETSEL.bit.SOCBSEL = 1; // 选择事件:TBCTR = 0 EPwm1Regs.ETPS.bit.SOCBPRD = 1; // 每个选定事件都触发一次 EPwm1Regs.ETSEL.bit.SOCBEN = 1; // 使能SOCB // 使能周期中断,用于执行控制算法 EPwm1Regs.ETSEL.bit.INTSEL = 2; // 选择事件:TBCTR = TBPRD (周期匹配) EPwm1Regs.ETPS.bit.INTPRD = 1; // 每个事件触发一次中断 EPwm1Regs.ETSEL.bit.INTEN = 1; // 使能ePWM中断CMPA值,写入影子寄存器,实现高精度的同步采样与控制。
4. 调试技巧与常见问题排查
没有PWM输出?
- 检查时钟:确认
TBCLK有时钟信号。检查TBCTL的CLKDIV和HSPCLKDIV分频设置。 - 检查时基模式:
TBCTL.CTRMODE不能是00(停止模式)。 - 检查输出引脚复用:确保GPIO MUX寄存器已正确配置为ePWM功能。
- 检查动作限定器:确认
AQCTL寄存器已配置了有效的“置位”和“清除”动作。一个常见的疏忽是只配置了ZRO事件,没配置CAU事件,导致输出一直为高。 - 检查强制状态:确认
AQCSFRC寄存器没有强制输出为常高或常低。确认TZ故障寄存器没有强制输出进入保护状态。
- 检查时钟:确认
PWM占空比不对或不变?
- 影子寄存器模式:在影子模式下,写入
CMPA后,需要等待特定的加载事件(如TBCTR=0)新值才会生效。检查LOADAMODE配置,并确认程序运行时间足够长,已经过了加载点。可以通过在加载点(如周期中断)更新CMPA来确保同步。 - 立即模式冲突:如果你配置为立即模式(
SHDWAMODE=1),但又在中断中频繁更新CMPA,可能会在计数器运行到一半时改变比较值,导致当前周期波形异常。 - 计数器模式与动作事件匹配:在递增递减模式下,
CAU(递增匹配)和CAD(递减匹配)都会发生。如果你的占空比大于50%,CMPA值会大于TBPRD/2。在递减计数段,TBCTR会再次等于CMPA,触发CAD事件。如果你没有为CAD事件配置动作(或配置了错误动作),就会导致输出异常。通常,在对称PWM中,我们只使用CAU事件来清除输出,而ZRO事件用来置位输出。
- 影子寄存器模式:在影子模式下,写入
死区时间不生效或效果不对?
- 输出模式:确认
DBCTL.OUT_MODE已设置为11(完全使能)。 - 输入源:确认
DBCTL.IN_MODE设置正确。如果你希望用EPWMxA生成两路互补带死区的信号,应设置为00。 - 极性:用示波器观察死区模块前后的信号。确认
POLSEL设置是否符合你的驱动芯片逻辑。一个快速测试方法是,将DBRED和DBFED设为一个较大值(如1000),观察互补信号中间是否出现明显的低电平“平台”。
- 输出模式:确认
故障保护不动作?
- 引脚配置:确认
TZx引脚已正确配置为输入功能,并且外部故障电路能产生有效的低电平信号。 - 选择寄存器:确认
TZSEL寄存器中,对应故障引脚的OSHTx或CBCx位已使能。 - 动作配置:确认
TZCTL寄存器中为故障状态配置了非“无动作(11)”的值。 - 软件强制测试:在调试阶段,可以不用连接真实故障信号,而是通过写
TZFRC寄存器的OST或CBC位来模拟故障,验证保护动作逻辑和中断响应是否正确。
- 引脚配置:确认
ADC触发或中断不产生?
- 事件选择:仔细核对
ETSEL中SOCxSEL或INTSEL的选择,是否与你期望的计数器事件(0, PRD, CMPA up等)匹配。 - 事件使能:确认
SOCAEN/SOCBEN/INTEN位已置1。 - 中断标志阻塞:对于中断
EPWMx_INT,必须确保在中断服务程序中清除了ETFLG[INT]标志(通过写ETCLR[INT]=1),否则后续中断会被阻塞。而SOCA/SOCB触发则没有这个限制。 - 预分频计数器:检查
ETPS中的SOCxCNT计数器。如果SOCxPRD设置为10(每两个事件触发一次),那么你需要看到两次匹配事件后,SOCxCNT从01变为10,才会产生一次触发脉冲。
- 事件选择:仔细核对