TMS320C6748 eHRPWM与GPIO配置实战:从架构到代码实现

TMS320C6748 eHRPWM与GPIO配置实战:从架构到代码实现

1. 项目概述与核心价值

在工业自动化、数字电源和电机驱动的嵌入式开发领域,精准的脉冲宽度调制(PWM)控制是系统的核心。很多开发者初次接触德州仪器(TI)的TMS320C6748这类高性能DSP时,面对其功能强大的增强型高分辨率PWM(eHRPWM)模块和灵活的通用输入/输出(GPIO)外设,往往会感到无从下手。数据手册虽然详尽,但更像一本字典,缺乏将各个寄存器、信号和实际应用场景串联起来的“操作指南”。我在多个伺服驱动和逆变器项目中深度使用了C6748的eHRPWM,深知从理解框图到写出稳定、可靠的驱动代码之间,有一道需要大量实践才能跨越的鸿沟。

这篇文章的目的,就是充当这座桥梁。我不会简单罗列寄存器地址,而是带你深入eHRPWM和GPIO的“五脏六腑”,从系统互联、子模块协同工作原理讲起,直到手把手完成一个包含同步、死区保护和中断响应的完整PWM输出配置。你会理解为什么需要影子寄存器,如何计算关键的时间参数,以及如何避免常见的配置陷阱。无论你是正在评估C6748用于新项目,还是正在调试一块现有的驱动板,这篇文章提供的思路和代码片段,都能让你更快地掌控这些关键外设,构建出响应迅速、鲁棒性强的实时控制系统。

2. eHRPWM模块架构深度解析

TMS320C6748芯片内部包含两个独立的eHRPWM模块(eHRPWM0和eHRPWM1),每个模块都能生成两路互补或独立的PWM输出(EPWMxA和EPWMxB)。它的强大之处在于其高度模块化和可配置性,理解其内部架构是进行任何高级配置的前提。

2.1 模块级互联与同步机制

从系统层面看,两个eHRPWM模块并非孤岛。它们通过EPWMSYNCI(同步输入)和EPWMSYNCO(同步输出)信号链在一起,这是实现多模块精确同步的关键。通常,我们可以将eHRPWM0配置为“主”模块,将其EPWM0SYNCO信号连接到eHRPWM1的EPWM1SYNCI。这样,当eHRPWM0的时基计数器(TBCTR)归零时,会产生一个同步脉冲输出,并触发eHRPWM1的计数器同步加载其相位寄存器(TBPHS)的值,从而实现两个模块的PWM波形严格对齐。这种机制在多相并联电源或三相电机驱动中至关重要,可以确保各相之间的相位差是精确和稳定的。

除了模块间同步,同步信号还可以来自外部引脚或其它外设(如eCAP模块),提供了极大的灵活性。配置同步的关键寄存器是TBCTL[SYNCOSEL],它决定了EPWMSYNCO信号的来源(可以是自身的CTR=ZERO事件、CTR=CMPB事件,或者是直接转发EPWMSYNCI输入)。

2.2 子模块协同工作原理

每个eHRPWM模块由七个核心子模块构成一条精密的信号处理流水线:

  1. 时间基准(TB)子模块:这是PWM的“心脏”,负责产生核心的时基计数器TBCNT。它决定PWM的载波频率(通过周期寄存器TBPRD)和计数模式(递增、递减或增减计数)。TBPHS寄存器用于在接收到同步信号时设置计数器的初始值,实现相位控制。
  2. 计数器比较(CC)子模块:包含CMPACMPB两个比较寄存器。它们持续与TBCNT的值进行比较,当匹配时,会产生CTR=CMPACTR=CMPB事件。这两个事件是PWM占空比控制的直接来源。
  3. 动作限定(AQ)子模块:这是定义PWM输出行为的“法官”。它接收来自TB和CC子模块的事件(CTR=PRDCTR=ZEROCTR=CMPACTR=CMPBCTR=DIR),并根据AQCTLAAQCTLB寄存器的配置,决定在哪个事件发生时,对输出引脚EPWMxAEPWMxB执行何种操作:置高(SET)、清零(CLEAR)、翻转(TOGGLE)或无操作。
  4. 死区生成(DB)子模块:在电机驱动或全桥电源中,互补的上下管PWM信号绝对不能有重叠导通的时间,否则会导致直通短路。DB子模块接收AQ输出的原始信号,通过DBRED(上升沿延迟)和DBFED(下降沿延迟)寄存器,独立地对两路信号的边沿进行延迟,从而插入一段安全的死区时间。DBCTL寄存器则控制延迟作用于哪一路信号以及输出极性。
  5. PWM斩波(PC)子模块:这是一个可选功能,用于生成高频载波信号来驱动隔离栅极驱动器(如IR21xx系列)。它通过一个可调频率和占空比的斩波信号对PWM波形进行调制,简化了外部驱动电路的设计。
  6. 故障保护(TZ)子模块:这是系统的“紧急制动”装置。TZ(Trip-Zone)引脚可以连接到过流、过压、过热等故障传感器的输出。一旦TZ信号有效,TZ子模块会根据TZSEL(选择哪些TZ引脚有效)和TZCTL(配置触发后的动作,如强制高、强制低或高阻态)的配置,立即对PWM输出采取强制保护动作,响应速度极快(纳秒级),远快于CPU中断处理。
  7. 事件触发(ET)子模块:负责将PWM周期内的关键事件(如CTR=PRDCTR=ZEROCTR=CMPA)转化为对CPU的中断请求或对DMA的启动触发信号。通过ETSELETPS寄存器,可以精细配置在事件第几次发生时才触发中断,避免过于频繁的中断影响CPU性能。

这七个子模块通过内部信号线精密耦合,使得eHRPWM能够在不频繁占用CPU资源的情况下,自主完成复杂、高精度的PWM波形生成与保护。

注意:高分辨率PWM(HRPWM)扩展是eHRPWM的一大亮点,它通过微边沿定位(MEP)技术,利用系统时钟对PWM边沿进行微调,可以将有效分辨率从传统的150ps左右提升到惊人的10ps级别。这对于需要极高精度调制的数字电源环路至关重要。它主要扩展了CMPAHRTBPHSHR等寄存器。

3. 关键寄存器功能详解与配置策略

面对数十个寄存器,盲目配置效率低下。我们需要抓住核心,理解每组寄存器的角色和配置逻辑。以下是对关键寄存器组的解析,配置策略基于常见实践。

3.1 时间基准(TB)子模块寄存器

这是配置的起点,决定了PWM的“心跳”。

  • TBCTL (Time-Base Control Register):核心控制寄存器。

    • CTRMODE: 设置计数模式。00=停止,01=递增计数,10=递减计数,11=增减计数。电机控制中常用增减模式,因为它能产生中心对称的PWM,谐波特性更好。
    • PHSEN: 相位加载使能。置1后,在同步信号EPWMSYNCI有效时,TBPHS的值会加载到TBCNT
    • PRDLD: 周期寄存器加载模式。0=影子寄存器模式(在CTR=0时从TBPRD影子寄存器加载到活动寄存器),1=立即加载模式。强烈建议使用影子寄存器模式,这允许你在任意时刻安全地更新TBPRD(写入影子寄存器),而不会干扰当前周期的波形生成,更新在下一个周期开始时生效,避免了毛刺。
    • SYNCOSEL: 选择EPWMSYNCO信号的来源,用于同步其他模块。
    • HSPCLKDIVCLKDIV: 时基时钟预分频器。PWM时钟频率= SYSCLKOUT / (HSPCLKDIV * CLKDIV)。这是调节PWM频率和分辨率的基础。
  • TBPRD (Time-Base Period Register): 周期寄存器。这是决定PWM频率的关键值。在增减计数模式下,PWM频率= PWM时钟频率 / (2 * TBPRD)。例如,系统时钟150MHz,HSPCLKDIV=1CLKDIV=1,则PWM时钟为150MHz。若需20kHz PWM,则TBPRD = 150MHz / (2 * 20kHz) = 3750

  • TBPHS (Time-Base Phase Register): 相位寄存器。用于在同步模式下,设置本模块计数器相对于同步信号的初始偏移量,实现多个PWM通道之间的固定相位差。

  • TBCNT (Time-Base Counter Register): 时基计数器(只读)。实时反映当前的计数值,可用于监控或调试。

配置策略:首先根据所需的PWM频率和系统时钟确定TBPRD,选择增减计数模式以优化频谱。若需多模块同步,配置主模块的SYNCOSEL使其在CTR=ZERO时输出同步信号,并从模块使能PHSEN并设置TBPHS为期望的相位值。务必使能影子寄存器模式以确保安全更新。

3.2 计数器比较(CC)与动作限定(AQ)子模块寄存器

这两部分共同决定了PWM的占空比和输出行为。

  • CMPA/CMPB (Counter-Compare A/B Register): 比较寄存器。在增减计数模式下,它们通常用于控制占空比。例如,若希望EPWMxA输出高电平的时间位于一个PWM周期的中心,可以配置在CTR递增过程中,当CTR=CMPA时清除输出;在CTR递减过程中,当CTR=CMPA时置位输出。这样,CMPA的值就直接控制了高电平脉冲的宽度。CMPB可用于生成更复杂的波形或作为第二个事件触发点。它们同样有影子寄存器(CMPCTL[LOADAMODE/LOADBMODE]控制加载时机),建议配置为在CTR=ZEROCTR=PRD时加载,以安全更新占空比。

  • AQCTLA/AQCTLB (Action-Qualifier Control Register): 动作限定寄存器。这是配置的难点和核心。你需要为每个输出通道(A和B)定义在特定事件发生时采取的动作。

    • ZRO: 当CTR=ZERO时动作。
    • PRD: 当CTR=PRD时动作。
    • CAU/CAD: 当CTR=CMPA且计数器递增(UP)或递减(DOWN)时动作。
    • CBU/CBD: 当CTR=CMPB且计数器递增或递减时动作。 每个字段可以设置为:00无操作,01清零,10置位,11翻转。

一个典型配置示例(增减模式,对称PWM): 我们希望EPWMxA输出一个中心对称的PWM波,高电平时间由CMPA控制。

  • AQCTLA配置:CAD = CLEAR(递减过CMPA时清零),CAU = SET(递增过CMPA时置位)。ZROPRD不动作。 这样,波形会在计数器从0增加到CMPA时保持低电平,超过CMPA后变为高电平,直到计数器从TBPRD减回到CMPA时恢复低电平。高电平时间= 2 * (TBPRD - CMPA)个时钟周期。

3.3 死区生成(DB)与故障保护(TZ)子模块寄存器

这两个子模块关乎系统的安全和可靠性。

  • DBCTL/DBRED/DBFED (Dead-Band Registers)

    • DBCTL中的OUT_MODE选择对哪路信号(A, B或两者)插入死区,POLSEL选择输出极性(是否交换高低有效边沿)。
    • DBRED定义上升沿延迟的时钟周期数,DBFED定义下降沿延迟的时钟周期数。死区时间= 延迟周期数 * PWM时钟周期。例如,PWM时钟150MHz,DBRED=10,则上升沿延迟约66.7ns。
  • TZSEL/TZCTL/TZEINT (Trip-Zone Registers)

    • TZSEL: 选择哪些TZ引脚(TZ1/TZ2/TZ3)能够触发故障保护,以及是电平触发还是边沿触发。
    • TZCTL: 配置当故障发生时,EPWMxAEPWMxB输出被强制为何种状态(高、低、高阻或不变)。例如,在全桥驱动中,通常配置为强制两路输出均为低,确保所有功率管关断。
    • TZEINT: 使能故障触发时产生CPU中断,以便在故障解除后执行恢复逻辑。

配置策略:根据所驱动的功率器件(MOSFET/IGBT)的开关特性(开通延迟、关断延迟)计算所需的最小死区时间,并转化为DBREDDBFED的值。故障保护配置应作为初始化的一部分优先完成,确保系统上电后即处于保护状态。通常将TZ引脚配置为低电平有效,TZCTL配置为强制输出安全状态(如全低)。

4. eHRPWM完整配置流程与代码实现

理论之后,我们通过一个具体的场景来串联所有配置:使用eHRPWM1模块生成一对带死区的互补PWM信号(EPWM1A和EPWM1B),频率为20kHz,死区时间500ns,并启用CMPA中断用于在周期中点进行ADC采样(电流环常见做法)。

4.1 初始化步骤分解

  1. 时钟使能与引脚复用: 首先,需要使能eHRPWM1模块的时钟(通过PSC模块)。然后,通过PINMUX寄存器将对应的GPIO引脚(例如GPIO8_14和GPIO8_15)配置为EPWM1A和EPWM1B功能模式,而非普通的GPIO。

    // 假设相关宏和寄存器地址已定义 // 1. 使能eHRPWM1模块时钟 (位于PSC0) *(volatile unsigned int *)PSC0_MDCTL[EPWM1_MODULE_ID] &= ~0x1F; // 清除模块状态 *(volatile unsigned int *)PSC0_PTCMD = 0x1 << EPWM1_MODULE_ID; // 发送使能命令 while(!(*(volatile unsigned int *)PSC0_PTSTAT & (0x1 << EPWM1_MODULE_ID))); // 等待使能完成 // 2. 配置GPIO8_14和GPIO8_15为EPWM1A/1B功能 // 假设PINMUX寄存器基址为PINMUX_BASE *(volatile unsigned int *)(PINMUX_BASE + GPIO8_14_MUX_OFFSET) = 0x1; // 模式1为EPWM1A *(volatile unsigned int *)(PINMUX_BASE + GPIO8_15_MUX_OFFSET) = 0x1; // 模式1为EPWM1B
  2. 配置时间基准(TB)子模块: 设定PWM频率和计数模式。假设系统时钟SYSCLKOUT为150MHz。

    #define SYSCLKOUT_MHZ 150 #define PWM_FREQ_KHZ 20 // 计算TBPRD值 (增减模式) // PWM时钟 = SYSCLKOUT / (HSPCLKDIV * CLKDIV), 先假设分频为1 #define TBPRD_VALUE ((SYSCLKOUT_MHZ * 1000) / (2 * PWM_FREQ_KHZ)) // 3750 volatile struct eHRPWM_REGS *ePwm1Regs = (void *)EPWM1_BASE; // 停止时基计数器 ePwm1Regs->TBCTL.bit.CTRMODE = TB_COUNT_DISABLE; // 配置时钟分频: HSPCLKDIV=/1, CLKDIV=/1 ePwm1Regs->TBCTL.bit.HSPCLKDIV = TB_DIV1; ePwm1Regs->TBCTL.bit.CLKDIV = TB_DIV1; // 设置增减计数模式 ePwm1Regs->TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // 设置周期值,并启用影子寄存器模式(在CTR=0时加载) ePwm1Regs->TBPRD = TBPRD_VALUE; ePwm1Regs->TBCTL.bit.PRDLD = TB_SHADOW; // 相位寄存器清零(独立运行,无同步需求) ePwm1Regs->TBPHS.all = 0; ePwm1Regs->TBCTL.bit.PHSEN = TB_DISABLE; // 设置同步输出信号源为CTR=0(可作为主模块) ePwm1Regs->TBCTL.bit.SYNCOSEL = TB_SYNC_OUT_CTR_ZERO;
  3. 配置计数器比较(CC)子模块: 设置CMPA的值以控制占空比,并配置其影子寄存器加载方式。

    // 假设初始占空比为30% #define DUTY_CYCLE_PERCENT 30 // 计算CMPA值:对于增减模式,高电平时间 = 2*(TBPRD - CMPA) // 占空比 = 高电平时间 / (2*TBPRD) = (TBPRD - CMPA) / TBPRD // 因此 CMPA = TBPRD * (1 - 占空比) uint16_t cmpAValue = (uint16_t)(TBPRD_VALUE * (1.0 - DUTY_CYCLE_PERCENT/100.0)); ePwm1Regs->CMPA.half.CMPA = cmpAValue; // 配置CMPA在CTR=0时从影子寄存器加载 ePwm1Regs->CMPCTL.bit.LOADAMODE = CC_LOAD_ON_CNTR_ZERO; ePwm1Regs->CMPCTL.bit.SHDWAMODE = CC_SHADOW; // CMPB本例未使用,可禁用 ePwm1Regs->CMPCTL.bit.LOADBMODE = CC_LOAD_ON_CNTR_ZERO; ePwm1Regs->CMPCTL.bit.SHDWBMODE = CC_SHADOW;
  4. 配置动作限定(AQ)子模块: 定义EPWM1A和EPWM1B的原始输出行为(在死区模块之前)。

    // 配置EPWM1A (AQCTLA): 增减模式,对称PWM // 递增过CMPA时置位,递减过CMPA时清零 ePwm1Regs->AQCTLA.bit.CAU = AQ_SET; ePwm1Regs->AQCTLA.bit.CAD = AQ_CLEAR; // 配置EPWM1B (AQCTLB): 我们希望它与EPWM1A互补 // 递增过CMPA时清零,递减过CMPA时置位 ePwm1Regs->AQCTLB.bit.CBU = AQ_CLEAR; // 使用CMPB事件,但CMPB未设置,这里仅为示例逻辑 ePwm1Regs->AQCTLB.bit.CBD = AQ_SET; // 更常见的做法是:让EPWM1B直接使用与A相同的CMPA事件,但动作相反。 // 或者,更简单的方法是:先配置A路,然后通过死区模块的极性控制来生成互补对。
  5. 配置死区生成(DB)子模块: 插入死区时间,并生成最终的互补信号。

    // 计算死区时间对应的时钟周期数 #define DEAD_TIME_NS 500 // PWM时钟周期 = 1 / (SYSCLKOUT_MHZ) ns = 6.67ns @150MHz #define PWM_CLK_PERIOD_NS (1000.0/SYSCLKOUT_MHZ) uint16_t dbCounts = (uint16_t)(DEAD_TIME_NS / PWM_CLK_PERIOD_NS + 0.5); // 四舍五入,约75个周期 // 配置死区时间 ePwm1Regs->DBRED = dbCounts; ePwm1Regs->DBFED = dbCounts; // 假设上升沿和下降沿延迟相同 // 配置死区控制:对A和B路都使能死区,模式为“A路输入,产生A和B的延迟输出” ePwm1Regs->DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // 使能A和B路的死区 ePwm1Regs->DBCTL.bit.POLSEL = DB_ACTV_HIC; // 主动高互补模式。A路高有效,B路低有效,且插入死区后B与A互补。 // IN_MODE配置为00,表示死区模块的输入源是动作限定器(AQ)的输出。
  6. 配置事件触发(ET)与中断: 使能在CTR=CMPA时触发中断,用于周期中点采样。

    // 选择中断事件源:CTR=CMPA事件 ePwm1Regs->ETSEL.bit.INTSEL = ET_CTR_CMPA; // 设置每个事件都触发中断(ETPS[INTPRD]=1) ePwm1Regs->ETPS.bit.INTPRD = ET_1ST; // 清除可能挂起的中断标志,并使能中断 ePwm1Regs->ETCLR.bit.INT = 1; ePwm1Regs->ETSEL.bit.INTEN = 1; // 使能ePWM中断 // 接下来需要在CPU中断控制器(INTC)中配置ePWM1的中断向量和使能。 // 假设ePWM1_INT对应某个CPU中断号,此处省略INTC配置代码。
  7. 启动PWM: 最后,启动时基计数器。

    // 如果之前停止了计数器,现在启动它 if(ePwm1Regs->TBCTL.bit.CTRMODE == TB_COUNT_DISABLE) { ePwm1Regs->TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; }

4.2 中断服务例程(ISR)处理

在配置的中断触发后,需要在ISR中处理关键任务,并清除中断标志。

// ePWM1中断服务函数示例 __interrupt void ePWM1_ISR(void) { // 1. 读取ADC采样值(假设ADC已在别处配置好,并与PWM同步触发) uint16_t adcResult = readADCResult(); // 2. 执行控制算法(例如PI调节),计算新的占空比 float newDuty = currentControlLoop(adcResult); // 计算新的CMPA值 uint16_t newCmpA = (uint16_t)(TBPRD_VALUE * (1.0 - newDuty)); // 安全更新CMPA影子寄存器(在CTR=0时生效) ePwm1Regs->CMPA.half.CMPA = newCmpA; // 3. 清除ePWM模块内的中断标志,否则会持续触发 ePwm1Regs->ETCLR.bit.INT = 1; // 4. 清除CPU中断控制器的相应中断标志(此处省略INTC操作) // ... // 5. 确认中断返回 __asm(" NOP"); }

实操心得:在增减计数模式下,将采样中断放在CTR=CMPA(即PWM波形的峰值点)是一个经典做法,因为此时功率器件的电流通常处于稳定状态,采样噪声小。同时,在中断中更新的是CMPA的影子寄存器,实际生效是在下一个PWM周期的开始(CTR=0时加载),这避免了在当前周期中间修改比较值可能导致的脉冲宽度异常,是保证输出波形稳定的关键。

5. GPIO外设配置与eHRPWM联动应用

GPIO在PWM控制系统中扮演着多种角色:作为普通输入读取状态,作为输出控制使能信号,或者配置为外部中断来响应紧急事件。

5.1 GPIO寄存器组精讲

C6748的GPIO被组织成多个Bank(0-8),每个Bank包含16个引脚。其寄存器设计非常高效,尤其是“置位/清零”寄存器,实现了原子操作,在多任务环境中无需关中断即可安全操作GPIO。

  • DIRx (Direction Register): 方向寄存器。每位对应一个引脚,0=输入,1=输出。
  • OUT_DATAx (Output Data Register): 输出数据寄存器。直接写入该寄存器会覆盖所有指定Bank的引脚输出值。
  • SET_DATAx / CLR_DATAx (Set/Clear Data Register)最常用、最安全的寄存器。向SET_DATAx的某位写1,对应引脚输出高电平;向CLR_DATAx的某位写1,对应引脚输出低电平。写0无效。这种机制允许多个任务或中断例程独立地设置或清除不同的引脚,而不会产生竞态条件。
  • IN_DATAx (Input Data Register): 输入数据寄存器。读取该寄存器获取对应Bank所有引脚的电平状态。
  • SET_RIS_TRIGx / CLR_RIS_TRIGx 等 (Interrupt Registers): 用于配置引脚的中断触发方式(上升沿、下降沿或两者),以及使能/禁止中断。INTSTATx寄存器则指示哪个引脚触发了中断。

5.2 与eHRPWM协同工作示例:使能控制与故障反馈

假设我们使用GPIO Bank5的引脚0(GPIO5_0)作为电机驱动芯片的使能信号(输出),使用GPIO Bank5的引脚1(GPIO5_1)作为故障反馈信号(输入,下降沿触发中断)。

  1. GPIO初始化与配置

    // 假设GPIO Bank5的寄存器基址为GPIO5_BASE volatile struct GPIO_REGS *gpioBank5 = (void *)GPIO5_BASE; // 1. 配置引脚方向 gpioBank5->DIR.bit.PIN0 = 1; // GPIO5_0 输出 gpioBank5->DIR.bit.PIN1 = 0; // GPIO5_1 输入 // 2. 初始化输出状态:使能信号默认为低(禁用) gpioBank5->CLR_DATA.bit.PIN0 = 1; // 清零操作,输出低 // 3. 配置GPIO5_1为下降沿中断 // 首先,清除可能存在的上升沿触发设置 gpioBank5->CLR_RIS_TRIG.bit.PIN1 = 1; // 然后,设置下降沿触发 gpioBank5->SET_FAL_TRIG.bit.PIN1 = 1; // 清除该引脚的中断状态标志(如果有) if(gpioBank5->INTSTAT.bit.PIN1) { // 通过读取IN_DATA来清除电平敏感型中断标志?不对。 // 对于边沿触发,标志通常在中断服务程序中通过软件序列清除。 // 需要参考具体手册,有时写1清除,有时需要操作特定寄存器。 // 假设这里写1到CLR_RIS_TRIG/CLR_FAL_TRIG可以清除标志(此为示例,需查证) gpioBank5->CLR_FAL_TRIG.bit.PIN1 = 1; // 尝试清除下降沿触发标志?此操作不标准。 // 更标准的做法是:在ISR中,先处理,然后向一个特定的“中断清除寄存器”对应位写1。 } // 4. 使能整个Bank5的中断(BINTEN寄存器) *(volatile unsigned int *)(GPIO_INT_BASE + BINTEN_OFFSET) |= (1 << 5); // 5. 在CPU的INTC中配置GPIO Bank5对应的系统中断(例如Event 59) // ... (INTC配置代码省略)
  2. 在eHRPWM应用中控制使能: 在启动PWM输出前,先拉高使能引脚;在系统故障或停机时,先关闭PWM输出,再拉低使能引脚。

    // 启动驱动 gpioBank5->SET_DATA.bit.PIN0 = 1; // 使能电机驱动芯片 delay_us(100); // 等待驱动芯片自举稳定 // ... 然后启动eHRPWM计数器(见第4.1节) // 安全停机序列 ePwm1Regs->TBCTL.bit.CTRMODE = TB_COUNT_DISABLE; // 先停止PWM delay_us(10); // 等待当前周期结束 gpioBank5->CLR_DATA.bit.PIN0 = 1; // 再禁用驱动芯片
  3. GPIO故障中断服务例程

    __interrupt void GPIO5_ISR(void) { // 1. 读取中断状态寄存器,确定是哪个引脚触发 uint32_t intStat = gpioBank5->INTSTAT.all; if(intStat & (1 << 1)) { // 检查是否是PIN1触发 // 2. 紧急处理:立即封锁PWM输出(通过TZ模块或软件) // 方法A:强制触发软件TZ事件(如果TZ引脚未用) ePwm1Regs->TZFRC.bit.OST = 1; // One-shot Trip force // 方法B:直接禁用PWM输出(可能不够快) // ePwm1Regs->TZCTL.bit.TZA = TZ_FORCE_HI; // 强制为高或低,取决于安全状态 // ePwm1Regs->TZCTL.bit.TZB = TZ_FORCE_HI; // 3. 记录故障日志,设置系统故障标志 systemFaultFlag = FAULT_OVER_CURRENT; // 4. 清除GPIO引脚的中断标志(具体操作取决于寄存器设计) // 假设通过向CLR_FAL_TRIG写1来清除标志(仅为示例) gpioBank5->CLR_FAL_TRIG.bit.PIN1 = 1; // 或者可能需要向一个专门的标志清除寄存器写1 // gpioBank5->INTSTAT.bit.PIN1 = 1; // 写1清除 } // 5. 清除CPU INTC中GPIO Bank5的中断标志 // ... (INTC清除代码省略) }

注意事项:GPIO中断的响应速度虽然很快(最快可达2个SYSCLK4周期),但对于过流等极端快速的故障,其响应时间(包括中断延迟、ISR入口处理)可能仍不足以保护功率管。因此,对于纳秒级要求的硬保护,必须使用eHRPWM自带的TZ(Trip-Zone)引脚,它直接连接到PWM输出逻辑,无需CPU干预即可在几十纳秒内强制PWM进入安全状态。GPIO中断更适合用于故障后的状态记录、系统停机管理和软恢复。

6. 高级应用与调试技巧

6.1 利用影子寄存器实现平滑参数更新

在电机控制或数字电源的闭环控制中,PWM的周期(频率)和占空比(CMPA/CMPB)需要动态调整。直接写入活动寄存器会导致当前周期波形畸变。影子寄存器机制是解决这一问题的关键。

  • 周期更新:配置TBCTL[PRDLD] = 0(影子模式)。当你写入TBPRD寄存器时,实际上是写入了影子寄存器。硬件会在CTR=ZERO(对于增减模式)或CTR=PRD(对于递增模式)时,自动将影子寄存器的值加载到活动寄存器。因此,更新操作可以在任何时刻安全进行。
  • 占空比更新:配置CMPCTL[LOADAMODE][SHDWAMODE]。通常设置为在CTR=ZERO时加载(LOADAMODE=0)。这样,在中断服务程序中计算出的新CMPA值写入后,会在下一个PWM周期开始时生效,实现无毛刺切换。

调试技巧:在调试动态更新时,可以启用CTR=ZERO事件触发中断,在中断内更新CMPATBPRD。使用示波器测量PWM输出,应看不到脉冲宽度异常或周期抖动。

6.2 高分辨率PWM(HRPWM)配置要点

HRPWM通过微边沿定位器(MEP)在传统的数字时钟边沿之间插入一个模拟延迟线,从而实现亚纳秒级的分辨率。

  1. 使能:首先确认使用的eHRPWM模块支持HRPWM(C6748的eHRPWM0和eHRPWM1均支持)。通过HRCNFG寄存器使能MEP控制。
  2. 精度与范围:HRPWM的高精度通常只适用于占空比的微调(CMPAHR)或相位的微调(TBPHSHR),其调整范围有限(例如,最多覆盖一个系统时钟周期)。CMPA寄存器负责“粗调”(决定大致的边沿位置),CMPAHR寄存器负责“精调”(在粗调确定的边沿附近进行微移)。
  3. 配置步骤
    • 正常配置eHRPWM的TB、CC、AQ等模块。
    • HRCNFG寄存器中的EDGMODE设置为双边沿调制或单边沿调制。
    • 在控制算法中,计算出需要的精细占空比。将整数部分写入CMPA,小数部分经过换算后写入CMPAHR
    • CMPAHR的值与模拟延迟线的步进时间有关,需要根据芯片数据手册的MEP步进参数进行计算。

注意:MEP的特性会随工艺、电压和温度变化。TI提供了校准库和算法,在实际产品中可能需要运行校准程序来保证HRPWM的精度。

6.3 常见问题排查实录

  1. 问题:PWM没有输出。

    • 检查顺序
      1. 时钟和电源:确认PSC模块已正确使能eHRPWM时钟。检查芯片电源和复位信号是否稳定。
      2. 引脚复用:使用PINMUX工具或直接查寄存器,确认GPIO引脚已配置为EPWM功能,而非普通GPIO。
      3. 输出使能:检查AQCTL寄存器是否配置了有效的动作(SET/CLEAR/TOGGLE)。如果全部是无操作,肯定没输出。
      4. 时基计数器:读取TBCNT寄存器,看它是否在循环计数。如果停在0或某个值,检查TBCTL[CTRMODE]是否被设置为停止模式。
      5. 死区和故障保护:检查DBCTL是否禁用了输出?检查TZCTL是否因故障信号将输出强制为高阻态?读取TZFLG寄存器查看故障标志。
  2. 问题:PWM频率不对。

    • 计算公式:务必确认所用计数模式下的频率公式。增减模式:Fpwm = Fclk / (2 * TBPRD);递增模式:Fpwm = Fclk / (TBPRD + 1)
    • 时钟源:确认TBCTL[HSPCLKDIV][CLKDIV]的分频系数。Fclk是经过分频后的时基时钟,不是系统主频。
    • 寄存器加载:如果修改了TBPRD但频率未变,检查是否配置为影子寄存器模式,并且写的是影子寄存器。在调试时,可以读取TBPRD活动寄存器的值来确认。
  3. 问题:死区时间不生效或不对。

    • 极性模式DBCTL[POLSEL]配置错误会导致输出信号逻辑混乱。务必根据驱动芯片要求的输入信号极性(高有效/低有效,互补/同相)来配置。
    • 输入源DBCTL[IN_MODE]需配置为从动作限定器(AQ)输出取信号。
    • 时间计算DBREDDBFED的单位是时基时钟周期,不是系统时钟周期。确保使用正确的Fclk进行计算。
  4. 问题:中断无法进入。

    • 中断使能链:这是一个常见的多层失配问题。确保:
      1. eHRPWM模块内部中断使能(ETSEL[INTEN]=1)。
      2. CPU级别的中断控制器(INTC)中,对应的eHRPWM中断通道已使能,并且优先级设置正确。
      3. 全局中断已开启(在C代码中通常通过__enable_irq()或类似指令)。
    • 标志清除:在中断服务程序中,必须清除eHRPWM的ETFLG[INT]标志(通过写ETCLR[INT]=1),否则会持续触发中断。同时也要清除INTC中的相应标志。
    • 事件选择与分频:检查ETSEL[INTSEL]选择的事件是否正确,以及ETPS[INTPRD]是否设置为你期望的触发频率(每次事件触发、每两次事件触发等)。
  5. 问题:使用影子寄存器更新CMPA,但变化有延迟或不对。

    • 加载点:确认CMPCTL[LOADAMODE]的设置。如果你在CTR=CMPA的中断里更新CMPA,但加载点设置在CTR=ZERO,那么更新将在下一个PWM周期的起点生效,而不是当前周期。这是正常且期望的行为,以避免毛刺。
    • 影子与活动寄存器:在调试器中,可以同时观察CMPA(影子寄存器)和CMPA活动寄存器的值(有时需要通过特定方式读取)。确认你写入的值确实存储在了影子寄存器中。

通过以上步骤的梳理和代码示例的实践,你应该能够建立起对TMS320C6748 eHRPWM和GPIO外设从原理到实现的完整认知。记住,理解每个子模块的信号流和寄存器间的联动关系,是进行复杂配置和高效调试的基础。在实际项目中,建议结合TI提供的ControlSUITE或C2000Ware中的驱动程序库和示例进行开发,它们提供了经过验证的初始化框架和高级API,能大大提高开发效率和可靠性。