彻底搞懂 EPWM Global Load:从原理到多相电源实战
在数字电源和电机控制领域,TI C2000 系列 DSP 的 ePWM 模块功能极其强大。很多初学者在使用 TBPRD(周期寄存器)和 CMPA(比较寄存器)的影子寄存器(Shadow Register)后,认为已经解决了波形更新的问题。
然而,当你进入变频控制 (如 LLC 谐振变换器)或多相交错并联 (如三相逆变)等高级应用时,会发现仅靠单个模块的影子寄存器是不够的。这时候,Global Load(全局加载) 功能就成了必须掌握的核心技术。
本文将深入剖析 EPWM Global Load 的工作原理,并结合代码和实战场景,带你彻底玩转这一功能。
🤔 一、为什么我们需要 Global Load?
要理解全局加载,先得明白它解决了什么痛点。
1. 影子寄存器的局限性
我们知道,ePWM 的寄存器(如 TBPRD, CMPA)通常都有对应的影子寄存器。软件先将新值写入影子寄存器,等到计数器 TBCTR 归零或等于周期值时,硬件自动将影子值加载到活动寄存器。这解决了单个寄存器更新的平滑问题。
但是,存在两个隐患:
- 寄存器间的"撕裂"更新 :软件指令是顺序执行的。假设你在中断里先更新
TBPRD,再更新CMPA。如果中断刚好在TBCTR=0附近触发,可能TBPRD已经更新到了新周期的值,而CMPA还在用旧周期的值。这会导致当前周期波形异常(例如占空比突变)。 - 多模块间的"不同步":在多相系统中(如 ePWM1, ePWM2, ePWM3),如果不加控制,每个模块的计数器是独立运行的。即使你配置了相同的周期,它们的相位也可能因为启动时间微差而逐渐错乱。
Global Load 的核心作用: 它是一个"总指挥",确保多个不同的寄存器 (TBPRD, CMPA, CMPB, DBRED 等)以及多个不同的 ePWM 模块 ,在同一个时刻统一更新数值。
⚙️ 二、Global Load 的工作原理
全局加载机制主要由三个寄存器组控制:配置(GLDCFG) 、控制(GLDCTL) 和 触发(GLDCTL2)。
1. 核心机制图解
我们可以把全局加载的过程想象成"发令枪"模型:
- 准备阶段(写入影子寄存器):软件计算新值,写入各个寄存器的影子区。
- 举旗阶段(配置 GLDCFG & GLDCTL):告诉硬件哪些寄存器需要听指挥(GLDCFG),以及什么时候听指挥(GLDCTL)。
- 发令阶段(触发 GLDCTL2):软件给出一个信号(One-shot),或者等待硬件同步信号。
- 起跑阶段(加载生效):当满足特定条件(如计数器归零)时,所有被选中的寄存器同时从影子区加载到活动区。
2. 关键寄存器配置
GLDCFG (Global Load Configuration)
这是"白名单"。你需要在这里通过置位,明确指定哪些寄存器参与全局加载。
- 例如:
GLDCFG.bit.TBPRD_TBPRDHR = 1表示周期寄存器参与全局加载。 - 如果不配置,这些寄存器将退化为普通的局部加载模式。
GLDCTL (Global Load Control)
这是"触发条件"。定义加载发生的时机。
GLDMODE: 选择触发源,如CNT_ZRO(计数器归零),PRD_EQ(等于周期),SWFSYNC(软件同步) 等。OSHTMODE: 是否开启一次性(One-shot)模式。
GLDCTL2 (Global Load Control 2)
这是"开关"。
OSHTLD: 写 1 开启一次性加载。硬件加载完成后会自动清零。
💻 三、代码实战:DriverLib 配置流程
假设我们要配置一个变频系统,需要同时更新 TBPRD 和 CMPA。以下是基于 TI DriverLib 的标准配置步骤:
步骤 1:配置参与全局加载的寄存器
// 使能 TBPRD 和 CMPA 的全局加载功能
EPWM_enableGlobalLoadRegisters(EPWM1_BASE, EPWM_GL_TBPRD_TBPRDHR);
EPWM_enableGlobalLoadRegisters(EPWM1_BASE, EPWM_GL_CMPA_CMPAHR);
// 如果有死区更新,也可以加入:
// EPWM_enableGlobalLoadRegisters(EPWM1_BASE, EPWM_GL_DBRED_DBFED);
步骤 2:配置加载时机与模式
通常我们选择在计数器归零(CNT_ZRO)时进行加载,以保证波形对称。
// 配置全局加载模式:在计数器归零时加载
EPWM_setGlobalLoadTrigger(EPWM1_BASE, EPWM_GLOBAL_LOAD_ON_CNT_ZERO);
// 开启一次性加载模式(One-shot)
// 这意味着加载动作需要软件触发一次(OSHTLD=1),且只生效一次
EPWM_setGlobalLoadOneShotLatch(EPWM1_BASE, EPWM_GLOBAL_LOAD_ONESHOT_LATCH_ENABLE);
步骤 3:在中断中执行更新(核心)
这是最关键的一步。在中断服务函数(ISR)中,不要直接操作活动寄存器,而是按以下顺序:
__interrupt void epwm1_isr(void)
{
// 1. 计算新的周期和占空比值
uint32_t newPeriod = calculateNewPeriod();
uint32_t newDuty = calculateNewDuty();
// 2. 将新值写入影子寄存器
// 注意:此时硬件不会立即更新,值还停留在影子区
EPWM_setTimeBasePeriod(EPWM1_BASE, newPeriod);
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, newDuty);
// 3. 触发全局加载
// 这一步相当于"扣动扳机"。
// 硬件会等待下一个"计数器归零"事件,然后统一加载上述两个值。
EPWM_triggerGlobalLoadOneShotLatch(EPWM1_BASE);
// 4. 清除中断标志
EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}
🚀 四、进阶应用:多模块同步(GLDCTL2LINK)
在三相逆变或交错并联 PFC 中,我们有 ePWM1, ePWM2, ePWM3。如果在中断里依次调用上面的 triggerGlobalLoad 函数,指令执行的时间差(微秒级)会导致三相波形相位出现偏差。
解决方案:使用 GLDCTL2LINK。
TI 的 Type-4 ePWM 模块支持将多个从模块的 GLDCTL2 寄存器链接到主模块。
1. 配置链接
将 ePWM2 和 ePWM3 的加载控制链接到 ePWM1。
// 将 EPWM2 和 EPWM3 的全局加载触发源链接到 EPWM1
EPWM_linkGlobalLoadTrigger(EPWM2_BASE, EPWM1_BASE);
EPWM_linkGlobalLoadTrigger(EPWM3_BASE, EPWM1_BASE);
2. 统一触发
在中断里,只需要触发主模块(ePWM1)即可。
// 只需触发主模块,从模块会自动同步
EPWM_triggerGlobalLoadOneShotLatch(EPWM1_BASE);
效果 :ePWM1, 2, 3 将在下一个 TBCTR=0 的瞬间,纳秒级同步地完成所有寄存器的更新。这对于消除多相系统中的环流和噪声至关重要。
⚠️ 五、避坑指南
- 时钟同步是前提 :在使用全局加载前,务必确保所有 ePWM 模块的时基时钟(TBCLK)是同步的。通常在初始化最后,统一开启
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC)。 - TBPHS 不支持全局加载:相位寄存器(TBPHS)通常不支持影子模式或全局加载。如果需要改变相位,建议使用比较寄存器(CMPA/CMPB)的相对位置来模拟相位移动,或者在停止计数器时修改。
- One-shot 的自动清零 :
OSHTLD位是"写 1 生效,硬件清零"。不要在中断里死循环等待它清零,除非你确定硬件逻辑没问题,否则容易导致程序卡死。
📌 总结
EPWM Global Load 是 C2000 高级控制的"瑞士军刀"。
- 单模块:用它解决变频控制中周期与占空比更新的"撕裂"问题。
- 多模块 :配合
GLDCTL2LINK,实现完美的多相交错同步。
掌握它,你的 PWM 波形控制将从"能用"进阶到"完美"。
本文档基于TI C2000系列DSP的ePWM模块特性编写,适用于需要高级PWM控制的应用场景。