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)子模块 :包含 CMPA CMPB 两个比较寄存器。它们持续与 TBCNT 的值进行比较,当匹配时,会产生 CTR=CMPA CTR=CMPB 事件。这两个事件是PWM占空比控制的直接来源。
  3. 动作限定(AQ)子模块 :这是定义PWM输出行为的“法官”。它接收来自TB和CC子模块的事件( CTR=PRD CTR=ZERO CTR=CMPA CTR=CMPB CTR=DIR ),并根据 AQCTLA AQCTLB 寄存器的配置,决定在哪个事件发生时,对输出引脚 EPWMxA EPWMxB 执行何种操作:置高(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=PRD CTR=ZERO CTR=CMPA )转化为对CPU的中断请求或对DMA的启动触发信号。通过 ETSEL ETPS 寄存器,可以精细配置在事件第几次发生时才触发中断,避免过于频繁的中断影响CPU性能。

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

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

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 信号的来源,用于同步其他模块。
    • HSPCLKDIV CLKDIV : 时基时钟预分频器。PWM时钟频率 = SYSCLKOUT / (HSPCLKDIV * CLKDIV) 。这是调节PWM频率和分辨率的基础。
  • TBPRD (Time-Base Period Register) : 周期寄存器。这是决定PWM频率的关键值。在增减计数模式下,PWM频率 = PWM时钟频率 / (2 * TBPRD) 。例如,系统时钟150MHz, HSPCLKDIV=1 CLKDIV=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=ZERO CTR=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时置位)。 ZRO PRD 不动作。 这样,波形会在计数器从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 : 配置当故障发生时, EPWMxA EPWMxB 输出被强制为何种状态(高、低、高阻或不变)。例如,在全桥驱动中,通常配置为强制两路输出均为低,确保所有功率管关断。
    • TZEINT : 使能故障触发时产生CPU中断,以便在故障解除后执行恢复逻辑。

配置策略 :根据所驱动的功率器件(MOSFET/IGBT)的开关特性(开通延迟、关断延迟)计算所需的最小死区时间,并转化为 DBRED DBFED 的值。故障保护配置应作为初始化的一部分优先完成,确保系统上电后即处于保护状态。通常将 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 事件触发中断,在中断内更新 CMPA TBPRD 。使用示波器测量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)输出取信号。
    • 时间计算 DBRED DBFED 的单位是时基时钟周期,不是系统时钟周期。确保使用正确的 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,能大大提高开发效率和可靠性。

更多推荐