1. 项目概述与ePWM核心价值
在嵌入式系统,尤其是电机控制、数字电源和逆变器这类对时序和功率精度要求极高的领域,脉冲宽度调制(PWM)技术是绝对的基石。我们常说的PWM,本质上是利用数字信号的通断时间来等效模拟电平,通过调节占空比来控制平均电压或电流。然而,当项目从简单的LED调光升级到驱动一个三相无刷电机,或者构建一个多相交错的DC-DC变换器时,简单的定时器PWM输出就捉襟见肘了。你需要的不只是单个PWM通道,而是一个能精确同步、相位可调、死区可控、事件触发灵活的完整波形生成系统。这就是增强型PWM(ePWM)模块大显身手的地方。
我接触过不少从标准PWM转向ePWM的工程师,初期往往会被其众多的子模块和寄存器搞得头晕——时间基准(TB)、计数器比较(CC)、动作限定器(AQ)、死区(DB)、事件触发(ET)等等。但一旦理清其核心逻辑,你会发现它是一套设计极其精妙的“乐高积木”,让你能像搭积木一样构建出几乎任何你能想到的复杂PWM波形。今天,我就结合自己调试电机驱动和数字电源的实际经验,深入拆解ePWM最核心的三个部分:时间基准子模块(TB)、计数器比较子模块(CC)和动作限定器子模块(AQ)。理解这三者的协同工作,是玩转ePWM的关键。无论你是正在评估TI C2000系列芯片,还是已经上手但对其内部机制感到模糊,这篇文章都将带你从“知道怎么配寄存器”深入到“明白为什么这么配”,从而在复杂系统中游刃有余。
2. 时间基准(TB)子模块:一切节奏的起源
如果把整个ePWM模块比作一个交响乐团,那么时间基准(Time-Base, TB)子模块就是乐团的指挥。它决定了整个PWM波形的“节拍”——频率、相位和计数模式。所有其他子模块(CC, AQ等)的动作,都严格遵循TB子模块提供的“时间轴”来执行。
2.1 核心计数器与工作模式
TB子模块的核心是一个16位的向上/向下计数器TBCTR。它的行为模式由TBCTL[CTRMODE]位域控制,主要有四种:
- 向上计数模式(Asymmetrical Up):计数器从0开始,递增到周期值
TBPRD,然后归零,重新开始。这种模式生成的是非对称PWM波形,其周期为(TBPRD + 1) * T_{TBCLK}。这是最基础的模式,常用于简单的单边调制。 - 向下计数模式(Asymmetrical Down):计数器从
TBPRD开始,递减到0,然后重新加载TBPRD。同样生成非对称波形,周期计算同上。在某些特定调制策略中会用到。 - 向上-向下计数模式(Symmetrical Up-Down):计数器从0开始递增到
TBPRD,然后立即递减回0,如此循环。这是生成对称(中心对齐)PWM波形的关键,其周期为2 * TBPRD * T_{TBCLK}。在电机控制和全桥变换器中,对称PWM能显著减少谐波,是更常用的模式。 - 冻结模式(Frozen):计数器停止在当前值,用于调试或紧急停止。
选择哪种模式?这完全取决于你的应用。驱动一个H桥的半桥,通常使用向上-向下模式来生成对称PWM,以减少电磁干扰(EMI)。而如果你只是做一个简单的降压转换器(Buck),向上计数模式可能就足够了。在我的一个伺服电机项目中,为了精确控制电流环,就采用了向上-向下模式,因为其波形的中心对称性使得电流采样的时刻更加明确和一致。
2.2 同步机制:多模块协同的基石
单个ePWM模块能力有限,真正的威力在于多个ePWM模块的协同工作。例如,一个三相逆变器需要6个PWM通道(每相上下桥臂),且它们之间必须有严格的相位关系。TB子模块的同步输入(EPWMxSYNCI)和同步输出(EPWMxSYNCO)功能正是为此而生。
同步的本质是让一个模块(从模块)的计数器TBCTR在特定时刻,被强制加载为主模块设定的相位值TBPHS。这个“特定时刻”就是同步脉冲到来的时刻。配置TBCTL[PHSEN] = 1即可启用此功能。
这里有三个关键的同步源:
- 外部同步脉冲(
EPWMxSYNCI):通常来自上一个ePWM模块的EPWMxSYNCO输出,形成同步链。例如,ePWM1作为主模块,其EPWM1SYNCO连接到 ePWM2 的EPWM2SYNCI,以此类推。 - 软件强制同步:通过写
TBCTL[SWFSYNC] = 1来产生一个同步脉冲。这在初始化或动态调整相位时非常有用。 - 数字比较事件同步:高级功能,当某些外部或内部数字比较条件满足时(如过流保护信号),可以触发同步,实现基于事件的全局相位重置。
相位控制是同步的精髓。通过为每个从模块设置不同的TBPHS值,你可以让它们的PWM波形相对于主模块产生固定的相位差。比如,在交错并联的Boost电路中,两个通道的PWM需要相差180度相位以减小输入电流纹波。假设主模块ePWM1的TBPRD=1000(向上-向下模式,一个完整周期计数2000次),要让ePWM2滞后180度,只需设置ePWM2.TBPHS = 500。这样,当同步脉冲到来,ePWM2的计数器会从500开始计数,其波形自然就滞后了半个周期。
实操心得:同步链的延迟手册中提到,同步信号从主模块传到从模块有
1 TBCLK或2 x VCLK3的延迟。这个延迟在超高开关频率(例如几百kHz)下必须考虑。如果你的多个通道要求绝对的同时性(纳秒级),可能需要使用全局时钟同步功能(TBCLKSYNC位)。正确的启用顺序是:先停止所有时钟(TBCLKSYNC=0),配置好各模块的预分频器和模式,再同时启动(TBCLKSYNC=1)。这样可以确保所有ePWM模块的TBCLK第一个上升沿严格对齐,从根本上消除因模块使能时间不同步带来的微小相位差。
2.3 时钟与周期配置
TBCLK是TB子模块的计数时钟源,由系统时钟SYSCLKOUT经过高速时钟预分频器(HSPCLKDIV)和时钟预分频器(CLKDIV)两级分频得到。TBPRD寄存器则决定了计数器的周期值。
计算PWM频率的公式:
- 向上/向下计数模式:
PWM Frequency = 1 / [(TBPRD + 1) * T_{TBCLK}] - 向上-向下计数模式:
PWM Frequency = 1 / [2 * TBPRD * T_{TBCLK}]
其中,T_{TBCLK} = 1 / (SYSCLKOUT / (HSPCLKDIV * CLKDIV))。
配置步骤示例:假设系统时钟SYSCLKOUT = 100 MHz,需要生成一个20 kHz的对称PWM。
- 选择向上-向下计数模式。
- 设定分频。为了获得较高的计数器分辨率,通常尽量让
TBPRD大一些。设HSPCLKDIV和CLKDIV均为1,则TBCLK = 100 MHz,T_{TBCLK} = 10 ns。 - 计算
TBPRD:TBPRD = 1 / (2 * PWM Frequency * T_{TBCLK}) = 1 / (2 * 20k * 10e-9) = 2500。 - 验证:实际频率
= 1 / (2 * 2500 * 10e-9) = 20 kHz。
注意事项:影子寄存器
TBPRD寄存器也有影子寄存器,由TBCTL[PRDLD]控制。在波形运行中更新TBPRD时,强烈建议使用影子模式(TBCTL[PRDLD] = 0),并选择在CTR=0或CTR=TBPRD时加载。这样可以避免在计数器运行中途更新周期值而导致当前周期波形畸变,确保PWM频率切换平滑无毛刺。
3. 计数器比较(CC)子模块:定义关键时间点
如果说TB子模块定义了时间的“标尺”,那么计数器比较(Counter-Compare, CC)子模块就是在标尺上“刻下”关键的事件点。它的工作很简单但至关重要:持续比较时间基准计数器TBCTR的值与两个用户定义的比较寄存器CMPA和CMPB的值,当相等时,产生CTR = CMPA和CTR = CMPB这两个事件。
3.1 比较事件与影子寄存器
CMPA和CMPB是决定PWM占空比或脉冲位置的核心寄存器。在向上计数模式下,CMPA的值直接决定了输出高电平或低电平的时长。在向上-向下计数模式下,CMPA和CMPB可以分别控制上升沿和下降沿的位置,从而实现对称调制。
CC子模块最精妙的设计之一是影子寄存器机制。CMPA和CMPB各有一个对应的影子寄存器。在影子模式下(CMPCTL[SHDWAMODE] = 0),你软件写入的值是进入影子寄存器,而硬件真正用于比较的是“活动寄存器”。影子寄存器向活动寄存器加载的时机由CMPCTL[LOADAMODE]和[LOADBMODE]控制,通常选择在CTR=0或CTR=PRD的时刻。
为什么需要影子寄存器?想象一下你在电机运行中需要动态调整PWM占空比(比如响应速度指令)。如果没有影子寄存器,你直接在任意时刻写CMPA,可能会发生这种情况:你写入新值时,计数器刚好跨过这个值,导致本次周期比较事件丢失或产生一个极窄的脉冲(glitch),这可能会引起功率管误开通,造成短路!影子寄存器确保了更新只发生在周期或零点的安全边界,保证了一个完整的PWM周期内,比较值保持不变,波形稳定。
3.2 不同计数模式下的比较行为
理解比较事件在不同计数模式下的触发次数,对于正确配置动作限定器至关重要。
- 向上计数模式:
TBCTR从0到TBPRD单向变化。因此,CTR=CMPA和CTR=CMPB事件每个PWM周期只发生一次。 - 向下计数模式:与向上模式类似,每个周期每个比较事件也只发生一次。
- 向上-向下计数模式:
TBCTR先上后下。如果比较值CMPx在0和TBPRD之间(不包括0和TBPRD),那么CTR=CMPx事件每个PWM周期会发生两次:一次在递增过程中,一次在递减过程中。如果CMPx等于0或TBPRD,则只会在计数器等于该值时触发一次。
这个特性是生成对称PWM的基础。例如,要生成一个中心对称的PWM,我们通常配置:在CTR=CMPA且计数器递增时(CAU事件)设置输出高,在CTR=CMPA且计数器递减时(CAD事件)清除输出低。这样,高电平脉冲就以周期点为中心对称分布。
3.3 比较值大于周期值的特殊情况
手册中特别提到了一个容易忽略的边界情况:当CMPA或CMPB的值大于TBPRD时,比较事件的行为会发生变化。
- 向上计数模式:如果
CMPx > TBPRD,则CTR=CMPx事件永远不会发生,因为计数器最大只到TBPRD。 - 向下计数模式:如果
CMPx >= TBPRD,则CTR=CMPx事件会在CTR=PRD(即计数器起始点)时发生。 - 向上-向下计数模式:如果
CMPx >= TBPRD,则递增过程中的比较事件会在CTR=PRD时发生,递减过程中的比较事件也会在CTR=PRD时发生(实际上合为一次)。
这个特性可以被巧妙利用。例如,在向上计数模式下,如果你想实现0%-100%的占空比范围,一种配置方法是:在CTR=0时置高输出,在CTR=CMPA时拉低输出。那么,当CMPA=0时,一上来就拉低,占空比0%;当CMPA=TBPRD时,在周期点拉低,占空比接近100%;当CMPA=TBPRD+1(大于周期)时,比较事件永不发生,输出始终为高,占空比100%。这就实现了全范围调节。
避坑指南:影子寄存器加载时机与脉冲丢失在向上-向下模式生成对称PWM时,如果你选择在
CTR=0的时刻加载影子寄存器到活动寄存器,那么你的CMPA/CMPB值必须大于等于1。为什么?假设TBPRD=1000,你在CTR=0时加载了CMPA=0。那么在本周期,活动寄存器的CMPA就是0。在计数器从0递增的瞬间,TBCTR就等于CMPA,会立即触发一个CAU事件。但这个事件可能过于短暂,或者与CTR=0的事件在优先级上冲突,导致预期的动作(比如置高)被忽略,造成一个PWM周期内没有脉冲输出。同理,如果在CTR=PRD时加载,则CMPA/CMPB值应小于等于 TBPRD-1。这个小细节是很多人在调试时发现占空比无法调到0%或100%的根源。
4. 动作限定器(AQ)子模块:事件的执行者
时间基准提供了节拍,计数器比较定义了音符出现的时刻,而动作限定器(Action-Qualifier, AQ)子模块就是乐手,负责在正确的时刻执行正确的动作——控制输出引脚EPWMxA和EPWMxB的电平。它是将时间事件转化为实际波形的最终环节。
4.1 事件、动作与配置
AQ子模块的输入是来自TB和CC子模块的四种事件:
CTR = PRD: 计数器等于周期值。CTR = ZERO: 计数器等于零。CTR = CMPA: 计数器等于比较值A。CTR = CMPB: 计数器等于比较值B。
对于每个输出通道(EPWMxA和EPWMxB),AQ子模块都可以独立配置,当上述某个事件发生时,要执行何种“动作”:
- 置高(Set High):将输出引脚驱动为高电平。
- 拉低(Clear Low):将输出引脚驱动为低电平。
- 翻转(Toggle):输出引脚当前电平取反。
- 无操作(Do Nothing):保持引脚当前电平不变。注意,即使配置为无操作,该事件仍然可以触发中断或ADC启动转换。
配置是通过AQCTLA和AQCTLB寄存器完成的。这些寄存器的位域非常直观,例如AQCTLA.CAU = AQ_SET就表示:当CTR=CMPA事件发生且计数器处于递增(Up)状态时,对EPWMxA执行置高动作。
4.2 事件优先级
一个关键问题是:如果多个事件在同一时刻(同一个TBCLK边沿)发生,听谁的?AQ子模块有严格的硬件优先级。基本原则是:软件强制事件优先级最高,然后是发生在“当前计数方向”上的比较事件,最后是周期/零点事件。
以最复杂的向上-向下计数模式为例,其优先级如下表所示:
| 优先级 (1最高) | TBCTR 递增时 (0 -> PRD) | TBCTR 递减时 (PRD -> 0) |
|---|---|---|
| 1 | 软件强制事件 | 软件强制事件 |
| 2 | CTR = CMPB(递增) | CTR = CMPB(递减) |
| 3 | CTR = CMPA(递增) | CTR = CMPA(递减) |
| 4 | CTR = ZERO | CTR = PRD |
| 5 | CTR = CMPB(递减) | CTR = CMPB(递增) |
| 6 | CTR = CMPA(递减) | CTR = CMPA(递增) |
为什么需要优先级?考虑一个常见场景:在向上-向下模式中,如果你设置CMPA = TBPRD,那么在计数器到达峰值TBPRD时,CTR=CMPA(递减事件,因为接下来要递减)和CTR=PRD(周期事件)会同时发生。根据上表,此时CTR=PRD的优先级高于CTR=CMPA(递减)。如果你同时配置了这两个事件对同一个引脚产生动作,那么只有高优先级的CTR=PRD动作会生效。理解优先级可以避免波形出现非预期的行为。
4.3 典型波形生成配置解析
手册中给出了多个经典配置的代码示例,这里我挑两个最常用的,结合我的经验深入解读:
配置一:向上计数,非对称PWM,独立调制两路输出(图21-20)这是最基础的配置,常用于两个独立的开关管控制。
// 初始化代码片段 EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // 向上计数模式 EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // CTR=0 时,EPWM1A 置高 EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // CTR=CMPA(递增)时,EPWM1A 拉低 EPwm1Regs.AQCTLB.bit.ZRO = AQ_SET; // CTR=0 时,EPWM1B 置高 EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR; // CTR=CMPB(递增)时,EPWM1B 拉低- 波形分析:两路输出都在��期开始时(
CTR=0)变高,然后分别在CMPA和CMPB时刻变低。CMPA和CMPB独立控制两路输出的占空比。占空比 =CMPx / (TBPRD + 1)。 - 实操要点:
CMPA和CMPB必须在[0, TBPRD]范围内。如果CMPx = 0,则CAU/CBU事件与ZRO事件同时发生,根据优先级(ZRO最低),CAU/CBU的清除动作会生效,导致输出始终为低(0%占空比)。如果CMPx = TBPRD,则清除动作发生在周期末尾,占空比接近100%。
配置二:向上-向下计数,对称PWM,互补输出带死区(图21-24)这是全桥或半桥驱动的标准配置,生成两路互补的对称PWM,并且通过CMPA和CMPB的差值天然形成死区。
// 初始化代码片段 EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // 向上-向下计数模式 EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // CTR=CMPA(递增)时,EPWM1A 置高 EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR; // CTR=CMPA(递减)时,EPWM1A 拉低 EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR; // CTR=CMPB(递增)时,EPWM1B 拉低 EPwm1Regs.AQCTLB.bit.CBD = AQ_SET; // CTR=CMPB(递减)时,EPWM1B 置高- 波形分析:
EPWM1A在计数器递增到CMPA时变高,递减到CMPA时变低,形成一个以周期点为中心的高电平脉冲。EPWM1B则相反,在递增到CMPB时变低,递减到CMPB时变高。如果CMPB > CMPA,则EPWM1A的高电平区间被EPWM1B的低电平区间所包围,两者之间就有了(CMPB - CMPA) * T_{TBCLK}的死区时间,防止上下管直通。 - 死区计算:死区时间 =
(CMPB - CMPA) * T_{TBCLK}。通过分别调节CMPA和CMPB,可以独立控制占空比和死区时间,非常灵活。但请注意,这种方式产生的死区会同时影响脉冲的前沿和后沿。 - 对比专用死区模块:ePWM还包含一个独立的死区(DB)子模块,它可以提供更传统的、基于上升沿延迟和下降沿延迟的死区生成方式,并且可以独立于占空比进行配置。对于大多数桥式驱动应用,我更喜欢使用DB模块,因为它将占空比调节(通过CC模块)和死区插入(通过DB模块)解耦,逻辑更清晰,不易出错。AQ模块生成互补波形的能力,更适合用于不需要可变死区,或者需要特殊脉冲位置控制的场景。
经验之谈:调试AQ模块的“三板斧”
- 先静态,后动态:首先在初始化代码中固定
TBPRD、CMPA、CMPB的值,用示波器观察输出波形是否与预期一致。确认基础配置正确后,再尝试在运行中动态修改比较值。- 善用软件强制:
AQSFRC寄存器可以软件强制输出高、低或翻转。在调试初期,你可以通过强制输出特定的电平,来快速验证GPIO引脚、驱动电路是否正常,排除硬件问题。- 关注影子加载时机:动态更新
CMPA/CMPB时,务必确认CMPCTL[LOADxMODE]的设置与你当前的计数模式匹配。在向上-向下模式下,如果你在CTR=ZERO时加载,而你的CMPA新值设为0,就可能会遇到前面提到的脉冲丢失问题。一个稳健的做法是,在运行中更新比较值时,先写入影子寄存器,然后通过检查CMPCTL[SHDWAFULL]或CMPCTL[SHDWBFULL]位来确认影子寄存器是否已满(即新值已就绪),或者简单地确保你的更新速度远慢于PWM周期。
5. 从理论到实践:一个完整的配置流程与调试案例
理解了三大子模块的原理后,我们来看一个完整的实战案例:配置一个ePWM模块,用于驱动一个三相逆变器中的其中一相上下桥臂(互补对称PWM,带死区)。
5.1 需求分析与配置规划
- 目标:生成一对互补的、中心对称的PWM波形(
EPWM1A和EPWM1B),开关频率20kHz,死区时间2us。 - 系统时钟:
SYSCLKOUT = 100 MHz。 - 选用模式:向上-向下计数模式生成对称PWM,使用动作限定器(AQ)生成互补波形,但死区通过专用的死区(DB)模块插入,以获得更稳定独立的控制。
- 计算参数:
TBCLK配置:为简化且获得高分辨率,设HSPCLKDIV=1,CLKDIV=1, 则TBCLK = 100 MHz,T_{TBCLK} = 10 ns。TBPRD计算:TBPRD = 1 / (2 * 20kHz * 10ns) = 2500。- 死区时间换算:死区时间
T_{dead} = 2 us = 2000 ns。需要的死区计数器值DBRED = DBFED = T_{dead} / T_{TBCLK} = 200(假设使用对称上升/下降沿延迟模式)。
5.2 分步配置代码与注释
以下是基于TI C2000系列芯片的典型驱动库代码风格:
// 步骤1: 配置时间基准 (TB) 子模块 EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // 向上-向下计数模式 EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // 本例作为主模块,禁用相位加载 EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW; // TBPRD使用影子寄存器 EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // 在CTR=0时产生同步输出,供其他模块同步 EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // 高速时钟预分频 = 1 EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; // 时钟预分频 = 1 EPwm1Regs.TBPHS.half.TBPHS = 0; // 相位寄存器清零 EPwm1Regs.TBPRD = 2500; // 设置周期值,对应20kHz EPwm1Regs.TBCTR = 0; // 计数器清零 // 步骤2: 配置计数器比较 (CC) 子模块 // 假设我们初始占空比为50%,即高电平时间占半个周期。对于对称PWM,CMPA值决定了脉冲宽度。 // 在向上-向下模式,高电平时间 = 2 * (TBPRD - CMPA) * T_TBCLK? 不对。 // 更直观:我们希望EPWM1A在计数到CMPA时置高,计数到CMPA时拉低(对称)。 // 对于50%占空比,高电平应覆盖整个周期的一半,即CMPA应设置在TBPRD/2附近。 // 但注意,AQ动作是在CAU和CAD事件。如果我们设置CAU=SET, CAD=CLEAR。 // 那么高电平时间就是从CAU事件到CAD事件,即 (TBPRD - CMPA) * 2 * T_TBCLK? 推导一下: // 计数器从0到TBPRD再到0。CAU发生在计数上升沿等于CMPA时,CAD发生在计数下降沿等于CMPA时。 // 两点之间的计数值差为: (TBPRD - CMPA) + (TBPRD - CMPA) = 2*(TBPRD - CMPA)。 // 因此,高电平时间 = 2*(TBPRD - CMPA) * T_TBCLK。 // 占空比 = 高电平时间 / 周期 = [2*(TBPRD - CMPA) * T_TBCLK] / [2*TBPRD*T_TBCLK] = (TBPRD - CMPA) / TBPRD。 // 所以,CMPA = TBPRD * (1 - DutyCycle)。 // 对于50%占空比,CMPA = 2500 * 0.5 = 1250。 EPwm1Regs.CMPA.half.CMPA = 1250; // 初始50%占空比 // CMPB在本例中暂未用于占空比控制,可设为任意值(例如0),或用于其他事件触发。 EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; // CMPA使用影子寄存器 EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; // CMPB使用影子寄存器 EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // 在CTR=0时加载CMPA影子值 EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; // 在CTR=0时加载CMPB影子值 // 步骤3: 配置动作限定器 (AQ) 子模块生成互补波形 // EPWM1A: 递增过CMPA时置高,递减过CMPA时拉低。 EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR; // EPWM1B: 我们希望它与EPWM1A互补。 // 一种简单配置:EPWM1B在递增过CMPA时拉低,递减过CMPA时置高。 // 但这样没有死区。更常见的做法是,AQ生成不带死区的互补信号,然后交给DB模块插入死区。 // 我们先配置AQ生成完全互补(无死区)的信号: EPwm1Regs.AQCTLB.bit.CAU = AQ_CLEAR; EPwm1Regs.AQCTLB.bit.CAD = AQ_SET; // 此时,EPWM1A和EPWM1B是瞬间互补的,存在直通风险。 // 步骤4: 配置死区 (DB) 子模块插入死区 EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // 使能EPWM1A和EPWM1B的上升沿和下降沿延迟 EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // 高电平互补模式。EPWM1A为参考信号,EPWM1B为其反相。 EPwm1Regs.DBCTL.bit.IN_MODE = DBA_ALL; // EPWM1A作为上升沿和下降沿延迟的源 EPwm1Regs.DBRED = 200; // 上升沿延迟,200个TBCLK = 2us EPwm1Regs.DBFED = 200; // 下降沿延迟,200个TBCLK = 2us // 经过DB模块后,最终的EPWM1A和EPWM1B输出会自动插入2us的死区。 // EPWM1A的上升沿延迟2us,EPWM1B的下降沿延迟2us(相对于原始的、瞬间互补的信号)。 // 步骤5: 配置事件触发 (ET) 和中断(可选) // 例如,我们可以在CTR=0时触发ADC采样(电流采样)。 EPwm1Regs.ETSEL.bit.SOCAEN = 1; // 使能ADC开始转换A组事件 EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTR_ZERO; // 选择CTR=0作为触发源 EPwm1Regs.ETPS.bit.SOCAPRD = ET_1ST; // 每个事件触发一次5.3 调试中常见问题与排查
即使按照上述步骤配置,在实际硬件调试中仍可能遇到问题。以下是我总结的常见问题排查清单:
| 现象 | 可能原因 | 排查步骤与解决方法 |
|---|---|---|
| 完全没有PWM输出 | 1. ePWM模块时钟未使能。 2. GPIO复用功能未配置到ePWM。 3. TBCLK分频过大或TBPRD为0。4. 输出被Trip-Zone强制拉高/低。 | 1. 检查系统控制模块中对应ePWM的外设时钟使能位(例如PCLKCR0寄存器)。2. 检查GPIO MUX寄存器,将对应引脚配置为ePWM功能。 3. 用仿真器读取 TBCTR寄存器,看它是否在循环计数。检查TBCTL[CLKDIV]和HSPCLKDIV。4. 检查 TZCTL寄存器,确保Trip-Zone未强制动作,或正确配置了错误处理方式。 |
| PWM频率不对 | 1.TBPRD计算错误或写入错误。2. TBCLK分频配置错误。3. 计数模式选择错误(向上 vs 向上-向下)。 | 1. 复核频率计算公式和系统时钟频率。 2. 确认 SYSCLKOUT频率,检查TBCTL中的分频位。3. 确认 TBCTL[CTRMODE]设置。用示波器测量周期,向上模式周期=(TBPRD+1)*T_TBCLK,向上-向下模式周期=2*TBPRD*T_TBCLK。 |
| 占空比无法调节或调节异常 | 1.CMPA/CMPB影子寄存器未正确加载。2. CMPA/CMPB值超出有效范围(如大于TBPRD)。3. AQ事件配置错误(例如 CAU和CAD动作设反)。4. 在错误的时间点更新了活动寄存器(无影子模式或加载时机不对)。 | 1. 确认CMPCTL[LOADxMODE]设置,并确保在CTR=0或PRD时更新影子寄存器。运行时,先写CMPA/CMPB影子寄存器,等待一个PWM周期后再观察。2. 确保 CMPA/CMPB值在[0, TBPRD]内(对于对称PWM,通常还要避开0和TBPRD)。3. 对照手册波形图,仔细检查 AQCTLA和AQCTLB寄存器的每一位配置。4. 启用影子模式,并确保在安全点( CTR=0/PRD)加载。 |
| 两路PWM互补但有重叠(无死区) | 1. 死区模块未使能或配置错误。 2. AQ模块生成的原始信号就不是互补的。 3. 死区时间值 DBRED/DBFED设置过小或为0。 | 1. 检查DBCTL[OUT_MODE]是否使能了死区生成。2. 暂时旁路死区模块( DBCTL[OUT_MODE]=0),直接观察AQ输出的原始信号是否互补。3. 计算并确认 DBRED/DBFED值对应的死区时间符合预期(T_dead = DBRED * T_TBCLK)。 |
| 同步功能不起作用 | 1. 主模块的SYNCOUT未正确配置或输出。2. 从模块的 SYNCI未使能相位加载(PHSEN=0)。3. 同步链中时钟分频不一致,导致计数器无法对齐。 4. 同步脉冲在从模块计数器禁止时发出。 | 1. 检查主模块TBCTL[SYNCOSEL],确保其能在特定事件(如CTR=0)产生同步脉冲。2. 检查从模块 TBCTL[PHSEN]是否置1,并设置了正确的TBPHS。3. 确保同步链上所有ePWM模块的 TBCLK分频设置(HSPCLKDIV,CLKDIV)完全一致。4. 确保在启动同步前,所有模块的计数器已使能( TBCLKSYNC=1)。 |
一个真实的调试故事:在一次电机驱动板调试中,我发现其中一相PWM的占空比在高速时(>90%)会突然跳动。示波器显示波形偶尔会缺失一个脉冲。排查了很久,最终发现是中断服务程序(ISR)中更新CMPA的代码执行时间过长。虽然使用了影子寄存器,但我的ISR可能在某个PWM周期内被多次触发,导致影子寄存器在尚未被加载到活动寄存器之前就被再次写入,发生了数据覆盖。解决方法是将占空比计算和寄存器更新放在后台循环中,仅由ISR设置一个标志位,或者使用ePWM自身的事件触发中断(ET),确保每个PWM周期只更新一次。这个坑让我深刻理解了“影子寄存器不是万能的”,软件与硬件的协同时序至关重要。
6. 进阶应用与性能优化思考
掌握了基础配置后,ePWM还有一些高级特性可以挖掘,以提升系统性能。
1. 利用数字比较(DC)和Trip-Zone(TZ)进行高级保护ePWM的DC子模块可以监控外部引脚或内部信号(如比较器输出),并与CMPA/CMPB等内部事件进行逻辑组合,产生特定事件。TZ子模块则可以在故障信号(如过流、过压)发生时,强制PWM输出进入安全状态(高阻、拉高或拉低)。将两者结合,可以实现逐周期电流限制。例如,用ADC采样电流,通过比较器产生一个数字信号连接到TZ输入。当电流超限,TZ模块可以立即关闭PWM输出。同时,DC模块可以监控这个故障信号,并产生同步事件,在故障清除后让所有ePWM模块重新同步启动,确保多相之间的相位关系不乱。
2. 高分辨率PWM(HRPWM)对于需要极高精度占空比控制的应用(如LLC谐振变换器的频率调节),标准ePWM的占空比分辨率受限于TBCLK周期。HRPWM技术通过一个微边沿定位(MEP)逻辑,在TBCLK的粗调基础上,实现了次周期的精细调节(精度可达150ps级别)。这需要特定的芯片支持(如C2000的Delfino系列),并配合特殊的HRMSTEP校准流程使用。启用HRPWM后,CMPA寄存器的一部分位会用于MEP控制,从而获得远超TBCLK频率限制的分辨率。
3. 动态相位调整与载波移相在并联交错或级联系统中,常常需要动态调整各相PWM之间的相位差。ePWM的同步和相位寄存器TBPHS为此提供了硬件支持。你可以在运行中,通过软件修改从模块的TBPHS值,并在下一个同步脉冲到来时生效,实现相位的平滑迁移。这对于实现功率因数校正(PFC)的相位 shedding或多相VRM的负载均衡非常有用。
4. 最小化中断延迟与CPU开销ePWM的事件触发(ET)子模块可以精确定时地触发ADC转换,实现无延迟的采样。将电流采样点配置在PWM周期的中点(对于对称PWM)或开关管关断时刻,可以避开开关噪声,获得最准确的采样值。同时,应尽量利用ePWM的硬件自动动作,减少CPU干预。例如,通过配置AQ和CC,让PWM波形完全由硬件产生,CPU只需在后台更新CMPA/CMPB即可改变占空比。将ADC结束中断与PWM周期中断错开,可以平衡CPU负载,避免在同一个时间点处理过多任务。
ePWM模块的深度和灵活性远不止于此,但时间基准、计数器比较和动作限定器这三个核心子模块是其灵魂。从理解计数器如何跳动,到比较器如何标记时刻,再到动作器如何执行指令,这条链路贯穿了所有ePWM应用。我个人的体会是,初期多花时间研究手册里的波形图,并用开发板的GPIO输出这些波形,用示波器亲自观察CTR=PRD、CTR=CMPA这些事件对应的边沿,比读十遍代码都管用。当你脑中能清晰地浮现出计数器在波形图上滑动,并在各个比较点触发动作的画面时,你就真正驾驭了ePWM。