Tiva C系列PWM高级应用:状态监控、故障保护与同步触发实战

📅 2026/7/18 4:09:26 👁️ 阅读次数 📝 编程学习
Tiva C系列PWM高级应用:状态监控、故障保护与同步触发实战

1. 项目概述与核心价值

在嵌入式开发,尤其是电机驱动、电源转换或者LED调光这类对时序和可靠性要求极高的场景里,PWM(脉宽调制)模块的配置往往是项目成败的关键。很多开发者初期可能只关注如何生成一个特定频率和占空比的波形,认为调通了PWMnLOADPWMnCMPA寄存器就万事大吉。然而,在实际的工业产品中,PWM模块的状态监控、故障保护、同步更新和事件触发这些“高级”功能,才是区分业余玩具和专业产品的分水岭。它们确保了系统在异常情况下(如过流、过压)能安全停机,在多路PWM协同工作时能保持精确的同步关系,并能精准地触发ADC采样等关键操作。

Tiva™ C系列微控制器(以TM4C123GH6ZRB为例)的PWM模块设计得非常完善,其寄存器组提供了从基础波形生成到高级系统集成的全套控制能力。但官方数据手册动辄数百页,寄存器描述分散且偏重定义,缺乏从“解决问题”角度的串联讲解。本文将以一个资深嵌入式工程师的视角,聚焦于PWM模块中状态、故障、更新与中断这四组核心控制寄存器,拆解它们在实际项目中的协同工作逻辑。我会结合真实的电机控制案例,不仅告诉你每个比特位是什么,更会深入解释为什么要这样设计,以及如何通过配置它们来构建一个鲁棒、高效且响应及时的控制系统。无论你是正在调试无刷电机驱动板,还是设计一个多通道精密调光系统,理解这些寄存器的内涵,都能让你从“能跑通代码”进阶到“能驾驭硬件”。

2. 核心寄存器功能解析与设计思路

Tiva™ C系列的PWM模块包含多个发生器(Generator),每个发生器能独立产生一对PWM信号(PWM A和PWM B)。为了管理这些发生器并确保系统安全,芯片设计了一套层次化的寄存器控制体系。我们重点关注的这几类寄存器,分别扮演着“哨兵”、“安全员”、“调度员”和“信使”的角色。

PWM状态寄存器(PWMSTATUS)是系统的“哨兵”。它是一个只读寄存器,实时反映着每个PWM发生器是否触发了未锁存的故障条件。所谓“未锁存”,指的是故障信号是实时电平敏感的。一旦外部故障输入引脚(如FAULT0)变为有效电平,对应位(如FAULT0)会立刻置1;故障消失,该位则清零。它提供的是最原始、最快速的系统状态快照,常用于实时监控和快速诊断。

PWM故障条件值寄存器(PWMFAULTVAL)是预置的“安全预案”。当“哨兵”发现故障后,系统需要立即采取行动。这个寄存器允许你为每一路PWM输出(MnPWM0~7)预先设定在故障发生时的输出电平(高或低)。例如,在驱动电机时,我们通常将故障值设为0(输出低电平),这样一旦发生过流故障,所有驱动桥臂立即关闭(输出低电平),电机刹车,避免损坏。这个寄存器的配置,是实现“故障安全”(Fail-Safe)逻辑的硬件基础。

PWM更新使能寄存器(PWMENUPD)是精细的“输出调度员”。它控制着PWMENABLE寄存器(用于使能/禁用PWM输出到引脚)的更新时机。为什么需要控制更新时机?想象一下,你正在控制一个三相逆变器,三个PWM发生器需要严格同步地开启或关闭输出,任何微小的时序错位都可能导致桥臂直通,烧毁MOSFET。PWMENUPD提供了三种模式:立即更新、局部同步(在下个计数器归零时更新)和全局同步(在所有发生器同步后,下个计数器归零时更新)。通过选择全局同步模式,你可以确保多路PWM输出的使能/禁用在完全相同的时钟周期生效,这对于多相电源和电机驱动至关重要。

PWM控制寄存器(PWMnCTL)是每个PWM发生器的“本地指挥官”。它功能繁杂,但核心围绕三点:故障处理策略寄存器更新同步发生器工作模式。例如,LATCH位决定故障是电平触发还是锁存触发;MINFLTPER位可以滤除故障输入上的短时毛刺;CMPAUPDLOADUPD等位则控制着比较值、重载值等关键参数的更新时机(局部或全局同步),确保在修改PWM参数时波形不会出现断裂或畸变。MODE位选择计数器是递减模式还是先增后减模式,这直接决定了PWM的中心对齐或边沿对齐方式。

PWM中断和触发使能寄存器(PWMnINTEN)是高效的“事件信使”。PWM模块内部有丰富的时基事件,如计数器归零、计数器等于装载值、计数器等于比较器A/B值(递增或递减时)。PWMnINTEN允许你精确选择哪些事件能产生CPU中断,哪些事件能触发ADC自动开始一次转换。这是实现闭环控制的核心。例如,在电机FOC控制中,我们可以在PWM计数器归零(或到达峰值)时触发ADC采样相电流,采样完成后在ADC中断中执行电流环计算并更新PWM比较寄存器,从而实现高同步性的电流控制。

这五组寄存器相互配合,构成了一个从故障检测、安全响应、同步管理到事件触发的完整闭环。理解它们之间的关联,是进行高级PWM应用开发的基石。

3. 寄存器详解与实战配置指南

下面,我们脱离数据手册的平铺直叙,以实战需求为牵引,逐一对这些寄存器进行“庖丁解牛”。

3.1 PWM状态寄存器(PWMSTATUS):实时系统健康仪表盘

PWMSTATUS寄存器位于偏移地址0x020,是一个32位只读寄存器。其低4位(位0-3)FAULT0FAULT3分别对应PWM发生器0至3的故障状态。

位域详解与实战意义:

  • FAULTn (位n, n=0,1,2,3): 当该位为0时,表示对应的PWM发生器n没有有效的故障条件。当为1时,表示该发生器检测到了一个有效的、未锁存的故障条件。
  • 关键联动机制: 该位的状态直接受外部故障输入引脚电平控制(当PWMnCTL.FLTSRC = 0时),或者受PWMnFLTSRC0/1寄存器配置的数字故障源控制。它反映的是故障源的实时状态,而非历史状态。

实战配置示例:假设我们使用PWM发生器0和1驱动一个H桥电机,并将外部过流保护电路的信号连接到MCU的FAULT0引脚(映射到PWM发生器0)。

// 通常无需主动“配置”PWMSTATUS,它是只读的。我们的工作是“读取”它。 // 在系统的主循环或高优先级任务中,定期或实时检查故障状态。 uint32_t fault_status = HWREG(PWM0_BASE + PWM_O_STATUS); if (fault_status & PWM_STATUS_FAULT0) { // PWM发生器0报告故障!立即执行安全操作,例如: // 1. 通过PWMFAULTVAL寄存器,确保输出为安全状态(如果未提前设置)。 // 2. 记录故障日志。 // 3. 可能触发系统级报警或停机。 SysCtlDelay(SysCtlClockGet() / 100); // 短暂延时,防抖 // 再次读取,确认是否为稳定故障 if (HWREG(PWM0_BASE + PWM_O_STATUS) & PWM_STATUS_FAULT0) { handleMotorFault(); // 用户自定义的故障处理函数 } }

注意PWMSTATUS反映的是未锁存的故障。如果故障信号是一个短暂的脉冲,该位会在脉冲结束后自动清零。因此,在用于关键保护时,建议配合PWMnCTL.LATCH位使用锁存模式,或者软件自身实现故障状态的锁存与保持。

3.2 PWM故障条件值寄存器(PWMFAULTVAL):定义安全输出状态

PWMFAULTVAL寄存器位于偏移地址0x024,可读写。其低8位(位0-7)PWM0PWM7分别控制8路PWM输出(MnPWM0至MnPWM7)在故障发生时的输出值。

位域详解与实战意义:

  • PWMm (位m, m=0..7): 当该位为0时,如��对应的故障使能位(在PWMFAULT寄存器中)被置位,则在故障条件下,该路PWM输出强制为低电平。为1时,则强制为高电平。
  • 关键联动机制: 此寄存器的生效,必须PWMFAULT寄存器中对应故障源的使能(FAULTn位)为前提。同时,最终输出还受PWMINVERT寄存器控制。逻辑关系为:最终输出 = PWMFAULTVAL.PWMm ^ PWMINVERT.INVn(异或)。

实战配置示例:继续上面的电机驱动例子。我们希望当任何故障(FAULT0)发生时,H桥的上下管全部关闭(输出低电平),电机自由停车或刹车。

// 假设MnPWM0和MnPWM1控制H桥的一个半桥,MnPWM2和MnPWM3控制另一个半桥。 // 设置故障安全值:所有相关PWM输出在故障时拉低。 uint32_t faultval = 0x0; // 所有位默认为0,故障时输出低电平。 // 更精确的设置可以只设置用到的位: // faultval = 0; // 因为复位值就是0,也可以不写。 HWREG(PWM0_BASE + PWM_O_FAULTVAL) = faultval; // 接下来,必须使能故障源对相应PWM输出的控制。 // 假设FAULT0控制所有4路PWM输出。 HWREG(PWM0_BASE + PWM_O_FAULT) |= (PWM_FAULT_FAULT0 | PWM_FAULT_FAULT1); // 使能故障0和1(对应发生器0和1)? // 注意:PWM_O_FAULT寄存器的位是FAULT0/1,它控制的是整个发生器的故障响应,而非具体某一路PWM。 // 更常见的做法是配置PWMnFLTSRC0/1寄存器,将故障源映射到具体的发生器。 // 这里为了简化,假设已配置FAULT0引脚同时控制发生器0和1。 // 一个更清晰的流程是: // 1. 配置PWM0CTL.FLTSRC = 0,让发生器0使用FAULT0输入。 // 2. 配置PWM1CTL.FLTSRC = 0,让发生器1也使用FAULT0输入(或配置为其他故障源)。 // 3. PWMFAULTVAL寄存器已经设置了安全值。 // 4. 当FAULT0引脚有效时,发生器0和1进入故障状态,其输出的PWM0/1/2/3会自动变为PWMFAULTVAL中设定的值。

重要心得: 务必在系统初始化、PWM输出使能之前就配置好PWMFAULTVAL。这是一个“安全保险”,确保系统上电或任何意外发生时,PWM输出处于已知的安全状态。同时,要理解PWMFAULTVALPWMINVERT的交互。如果你在正常输出时使用了输出反转功能(例如为了驱动高边栅极驱动器),那么在设置故障安全电平时,需要仔细计算异或后的最终结果是否符合安全逻辑。

3.3 PWM更新使能寄存器(PWMENUPD):精准的时序同步控制器

PWMENUPD寄存器位于偏移地址0x028,可读写。它为每一路PWM输出(MnPWM0~7)独立设置了一个2位的字段(ENUPD0~ENUPD7),用于控制PWMENABLE寄存器中对应使能位的更新模式。

字段详解与实战意义:每个2位字段(例如ENUPD0控制PWM0EN)可设置为:

  • 0x0 (立即更新): 写入PWMENABLE.PWM0EN后,PWM0输出立即生效或失效。可能破坏多路同步性,仅在单路、对时序无严格要求时使用。
  • 0x2 (局部同步): 写入PWMENABLE.PWM0EN后,改变将在该PWM发生器的下一个计数器归零时刻生效。这保证了该路PWM波形本身的完整性(不会在半周期中间被切断或开启),适用于独立通道的平滑启停。
  • 0x3 (全局同步): 写入PWMENABLE.PWM0EN后,改变将被挂起。只有当软件向PWMCTL寄存器(注意,这是PWM模块的全局控制寄存器,不是发生器的PWMnCTL)写入特定的同步更新请求后,所有配置为全局同步模式的PWM通道,将在下一个同步的计数器归零时刻一起生效。这是实现多路PWM严格同步启停的关键。

实战配置示例:在一个三相逆变器中,我们使用PWM发生器0、1、2分别产生U、V、W三相的PWM信号。要求三路PWM必须同时开始输出,同时停止,以避免上下管直通。

// 第一步:将所有PWM输出的更新模式设置为全局同步。 // ENUPD字段每2位控制一路PWM。假设我们使用PWM0, PWM2, PWM4(对应发生器0的A/B,发生器1的A,发生器2的A?需根据实际引脚映射)。 // 更常见的映射是:发生器0 -> PWM0/PWM1 (U相), 发生器1 -> PWM2/PWM3 (V相), 发生器2 -> PWM4/PWM5 (W相)。 // 我们需要设置PWM0, PWM1, PWM2, PWM3, PWM4, PWM5的更新模式为全局同步。 // 计算ENUPD寄存器的值: // ENUPD7 ENUPD6 ... ENUPD1 ENUPD0 // 每个字段2位,0x3表示全局同步。 // 对于PWM0 (ENUPD0): 0x3 // 对于PWM1 (ENUPD1): 0x3 // ... // 对于PWM5 (ENUPD5): 0x3 // 假设PWM6,7未用,设为0。 uint32_t enupd_value = (0x3 << (0*2)) | // PWM0 (0x3 << (1*2)) | // PWM1 (0x3 << (2*2)) | // PWM2 (0x3 << (3*2)) | // PWM3 (0x3 << (4*2)) | // PWM4 (0x3 << (5*2)); // PWM5 // 即 enupd_value = 0x0000FFFF & 0x55555555? 不对,0x3的二进制是11。 // 更清晰的写法: enupd_value = 0; for(int i=0; i<=5; i++) { enupd_value |= (0x3 << (i*2)); } HWREG(PWM0_BASE + PWM_O_ENUPD) = enupd_value; // 第二步:初始化所有PWM发生器的参数(LOAD, CMPA, CMPB等),但先不要使能输出(PWMENABLE寄存器保持为0)。 // 第三步:当所有参数就绪,需要同时启动所有PWM输出时: // 1. 将PWMENABLE寄存器中对应位(PWM0EN-PWM5EN)全部置1。注意,此时由于是全局同步模式,输出并不会立即改变。 HWREG(PWM0_BASE + PWM_O_ENABLE) |= (PWM_ENABLE_PWM0 | PWM_ENABLE_PWM1 | PWM_ENABLE_PWM2 | PWM_ENABLE_PWM3 | PWM_ENABLE_PWM4 | PWM_ENABLE_PWM5); // 2. 向全局PWM控制寄存器PWMCTL(注意基址,可能是PWM0_BASE)写入同步更新命令。 // 假设我们使用PWM0模块(基址0x40028000)的全局控制寄存器。 // 查找数据手册,PWMCTL寄存器的UPDATE位(可能是某一位)用于请求全局同步更新。 // 例如:PWM_O_CTL寄存器的某一位(如位0)是GLOBAL_SYNC_UPDATE。 HWREG(PWM0_BASE + PWM_O_CTL) |= PWM_CTL_GLOBAL_SYNC_UPDATE; // 请求全局同步 // 此后,所有PWM发生器会在下一个计数器同步归零的时刻,同时将输出使能状态更新为PWMENABLE寄存器中的值,从而实现完美同步启动。

避坑指南PWMENUPD控制的是PWMENABLE寄存器的更新时机,而PWMnCTL中的CMPAUPDLOADUPD等控制的是比较值、重载值等波形参数的更新时机。两者概念相似但对象不同。在需要同时更新波形参数和输出使能时,需要协调好两者的同步设置。通常,我们会将所有的更新模式都设置为全局同步,然后通过一次对PWMCTL.UPDATE的写操作,来触发所有挂起的更新。

3.4 PWM控制寄存器(PWMnCTL):发生器的指挥中枢

PWMnCTL寄存器是每个PWM发生器的控制核心,地址偏移分别为0x040(PWM0CTL),0x080(PWM1CTL)等。我们将其功能分组解读。

3.4.1 故障处理策略配置(位18-16)

  • LATCH (位18): 故障锁存使能。0=非锁存(电平敏感),1=锁存。锁存模式下,一旦故障有效,即使故障源消失,故障状态也会保持,直到软件通过清除PWMISC寄存器中的INTFAULTn位来清除它。在需要捕捉瞬时故障脉冲(如短路)的应用中,必须置1
  • MINFLTPER (位17): 最小故障周期使能。置1后,使能一个单次触发计数器,用于延长故障输入的有效时间,确保能被稳定捕获。延��时间由PWMnMINFLTPER寄存器设定。用于滤除故障输入线上的噪声毛刺
  • FLTSRC (位16): 故障源选择。0=使用默认的故障输入引脚(如FAULT0);1=使用PWMnFLTSRC0/1寄存器配置的扩展故障源(如ADC比较器、GPIO等)。当需要复杂的故障��辑(如多条件“与/或”)时,选择1并进行扩展配置

3.4.2 寄存器更新模式配置(位15-3)这一组位(DBFALLUPD,DBRISEUPD,DBCTLUPD,GENBUPD,GENAUPD,CMPBUPD,CMPAUPD,LOADUPD)分别控制死区下降沿延迟、上升沿延迟、死区控制、生成器B动作、生成器A动作、比较器B、比较器A、重载值这些参数的更新时机。每个字段通常为2位或1位,含义与PWMENUPD类似:

  • 局部同步 (通常值0或0x2): 参数在下一次本发生器计数器归零时生效。
  • 全局同步 (通常值1或0x3): 参数更新被挂起,直到软件向全局PWMCTL寄存器请求同步更新后,在下一次同步的计数器归零时刻生效。
  • 立即更新 (通常值0x0): 立即生效(可能破坏波形连续性,慎用)。

3.4.3 发生器工作模式配置(位2-0)

  • DEBUG (位2): 调试模式。0=调试时计数器暂停,1=调试时计数器继续运行。在实时性要求高的控制中,通常设为1,确保调试时控制环路不中断。
  • MODE (位1): 计数器模式。0=递减模式(边沿对齐PWM),1=先增后减模式(中心对齐PWM)。电机控制中为了减小谐波和开关损耗,普遍使用中心对齐模式(MODE=1)
  • ENABLE (位0): 发生器使能。0=禁用整个发生器模块(无时钟,最省电),1=使能。注意: 数据手册特别提醒,禁用发生器不会清零计数器值。在重新使能前,应通过系统控制模块的SRPWM寄存器复位PWM模块,或手动确保计数器从正确值开始,否则可能导致第一个PWM周期异常。

实战配置示例(电机控制场景):

// 配置PWM发生器0为中心对齐、调试不停机、故障锁存、参数全局同步更新。 uint32_t pwm0ctl_config = 0; // 1. 故障处理:锁存模式,使能最小故障周期,使用默认故障源0。 pwm0ctl_config |= PWM_CTL_LATCH; // 锁存故障 pwm0ctl_config |= PWM_CTL_MINFLTPER; // 使能最小故障周期(需另配置PWM0MINFLTPER寄存器) pwm0ctl_config &= ~PWM_CTL_FLTSRC; // 使用默认FAULT0输入 // 2. 更新模式:所有关键参数(LOAD, CMPA, CMPB, GEN动作)均设置为全局同步更新。 // 假设这些位的宏定义如下(具体名称需查手册): pwm0ctl_config |= PWM_CTL_LOADUPD_GLOBAL; // LOAD全局同步 pwm0ctl_config |= PWM_CTL_CMPAUPD_GLOBAL; // CMPA全局同步 pwm0ctl_config |= PWM_CTL_CMPBUPD_GLOBAL; // CMPB全局同步 pwm0ctl_config |= PWM_CTL_GENAUPD_GLOBAL; // GENA全局同步 pwm0ctl_config |= PWM_CTL_GENBUPD_GLOBAL; // GENB全局同步 // 死区相关更新模式也设为全局同步 pwm0ctl_config |= PWM_CTL_DBCTLUPD_GLOBAL; pwm0ctl_config |= PWM_CTL_DBRISEUPD_GLOBAL; pwm0ctl_config |= PWM_CTL_DBFALLUPD_GLOBAL; // 3. 工作模式:中心对齐,调试时继续运行。 pwm0ctl_config |= PWM_CTL_MODE; // 中心对齐模式 pwm0ctl_config |= PWM_CTL_DEBUG; // 调试模式计数器继续运行 // 4. 先不使能发生器(ENABLE=0),等所有参数(LOAD, CMP等)配置完再使能。 // pwm0ctl_config &= ~PWM_CTL_ENABLE; HWREG(PWM0_BASE + PWM_O_0_CTL) = pwm0ctl_config; // ... 后续配置PWM0LOAD, PWM0CMPA, PWM0CMPB, PWM0GENA, PWM0GENB等寄存器 ... // 所有参数配置完毕后,再使能发生器(注意:使能输出的时机由PWMENUPD和PWMENABLE控制,这里是使能发生器本身)。 HWREG(PWM0_BASE + PWM_O_0_CTL) |= PWM_CTL_ENABLE;

3.5 PWM中断和触发使能寄存器(PWMnINTEN):事件驱动的枢纽

PWMnINTEN寄存器位于偏移地址0x044(PWM0INTEN)等,用于控制PWM发生器内部事件是否产生中断(给CPU)或触发脉冲(给ADC)。

中断使能位(位0-5):

  • INTCNTZERO,INTCNTLOAD,INTCMPAU,INTCMPAD,INTCMPBU,INTCMPBD: 分别使能计数器归零、等于装载值、等于CMPA(递增时)、等于CMPA(递减时)、等于CMPB(递增时)、等于CMPB(递减时)这些事件产生原始中断。中断状态可在PWMnRIS中读取,并通过PWMnISC清除。

触发使能位(位8-13):

  • TRCNTZERO,TRCNTLOAD,TRCMPAU,TRCMPAD,TRCMPBU,TRCMPBD: 分别使能上述事件产生ADC触发脉冲。这对于同步采样至关重要。

实战配置示例(在中心对齐PWM的峰值/谷点触发ADC采样):在电机FOC控制中,我们通常在PWM周期的中心点(计数器为0)和峰值点(计数器等于LOAD值)采样相电流,以避开开关噪声。

// 配置PWM发生器0的中断和触发使能 uint32_t pwm0inten_config = 0; // 1. 使能“计数器归零”事件产生中断和ADC触发。 pwm0inten_config |= PWM_INTEN_INTCNTZERO; // 计数器为0时产生中断 pwm0inten_config |= PWM_INTEN_TRCNTZERO; // 计数器为0时触发ADC // 2. 使能“计数器等于装载值”事件产生中断和ADC触发。 pwm0inten_config |= PWM_INTEN_INTCNTLOAD; // 计数器等于LOAD时产生中断 pwm0inten_config |= PWM_INTEN_TRCNTLOAD; // 计数器等于LOAD时触发ADC // 对于中心对齐模式,计数器会先增到LOAD再减到0。 // 因此,每个PWM周期会产生两次事件:一次在LOAD(峰值),一次在0(谷值)。 // 我们可以选择在其中一个事件触发ADC,另一个事件触发中断进行处理。 // 或者,都触发ADC,在ADC转换完成中断中处理数据。 HWREG(PWM0_BASE + PWM_O_0_INTEN) = pwm0inten_config; // 3. 在PWM中断服务函数(ISR)中处理 void PWM0_Handler(void) { uint32_t int_status = HWREG(PWM0_BASE + PWM_O_0_RIS); // 读取原始中断状态 if (int_status & PWM_RIS_INTCNTZERO) { // 计数器归零中断 // 可以在此处读取ADC采样结果(如果ADC触发在LOAD点,转换此时已完成) processCurrentSamples(); // ... 其他处理 HWREG(PWM0_BASE + PWM_O_0_ISC) = PWM_RIS_INTCNTZERO; // 清除中断 } if (int_status & PWM_RIS_INTCNTLOAD) { // 计数器等于装载值中断 // 可以在此处启动一些计算或准备下一个周期的数据 // ... HWREG(PWM0_BASE + PWM_O_0_ISC) = PWM_RIS_INTCNTLOAD; // 清除中断 } // ... 处理其他中断源 }

核心技巧: 合理分配中断和触发源可以优化系统响应。一种高效的模式是:设置TRCNTLOAD触发ADC开始采样(在PWM峰值点,开关状态稳定,电流可测),设置INTCNTZERO产生中断。在计数器归零中断服务程序中,ADC转换早已完成,可以安全地读取ADC结果并执行FOC算法,更新下一个PWM周期的比较值。由于比较值更新模式设置为全局同步,新值将在下一个PWM周期开始时生效,实现了算法与硬件的完美同步。

4. 高级应用与故障调试实录

理解了单个寄存器的功能后,将它们组合起来解决复杂问题才是终极目标。下面分享两个实战中遇到的典型场景及其解决方案。

4.1 场景一:构建带故障保护的三相电机同步启动/停止系统

需求: 驱动三相无刷电机,要求6路PWM(上下管)严格同步启停,具备硬件过流保护(故障信号锁存),故障时所有PWM输出立即置为安全状态(低电平)。

配置步骤:

  1. 引脚与时钟初始化: 配置系统时钟,使能PWM模块时钟,将GPIO引脚复用为PWM功能。
  2. 故障安全值预设: 初始化PWMFAULTVAL寄存器,将所有6路PWM输出对应的位设为0(故障时输出低电平)。
  3. PWM发生器基本配置
    • 配置PWMnCTLMODE=1(中心对齐),DEBUG=1LATCH=1(故障锁存),MINFLTPER=1(使能故障滤波,并配置PWMnMINFLTPER寄存器设置滤波时间),FLTSRC=0(使用外部FAULT0引脚)。
    • 配置PWMnCTL中的LOADUPDCMPAUPDCMPBUPDGENAUPDGENBUPD为全局同步模式。
    • 配置PWMnLOAD设定PWM频率,配置PWMnCMPA/PWMnCMPB设定初始占空比(通常为0),��置PWMnGENA/PWMnGENB设定输出动作模式。
  4. 输出使能同步配置: 配置PWMENUPD寄存器,将6路PWM输出的ENUPD字段全部设为全局同步模式(0x3)。
  5. 故障输入配置: 配置PWMFAULT寄存器,使能FAULT0(或其他你使用的故障源)对所用PWM发生器的控制。配置PWMnFLTSRC(如果需要)来映射故障源。
  6. 同步启动
    • PWMENABLE寄存器中对应6路PWM的使能位置1(此时输出仍未改变,因为更新模式是全局同步)。
    • PWMCTL寄存器写入全局同步更新命令。
    • 所有PWM发生器会在下一个同步的计数器归零时刻,同时输出PWM波形。
  7. 故障处理
    • 过流发生时,FAULT0引脚拉低(假设低有效)。
    • PWMSTATUS.FAULT0FAULT1(如果映射了)立即置1。
    • 由于PWMnCTL.LATCH=1,故障状态被锁存。
    • 锁存的故障导致对应发生器的PWM输出立即变为PWMFAULTVAL中预设的安全值(低电平),电机停止。
    • 在软件中,轮询或通过中断检测PWMnRIS中的故障中断标志,进入故障处理程序,进行故障记录、系统状态保存等操作,并清除故障锁存(通过写PWMnISC寄存器)。

4.2 场景二:实现高精度同步ADC采样的电流环控制

需求: 在电机控制中,需要在PWM周期的特定时刻(避开开关噪声)同步采样两相电流,并快速计算更新下一周期的PWM占空比。

配置步骤:

  1. PWM时基与中断配置
    • 如3.5节示例,配置PWMnINTEN,使能TRCNTLOAD触发ADC采样序列,使能INTCNTZERO产生CPU中断。
    • 配置ADC模块,设置采样序列的触发源为PWM触发。
  2. 时序设计
    • 中心对齐PWM。计数器从0递增到LOAD(峰值),再递减回0(谷值)。
    • 设置TRCNTLOAD在计数器等于LOAD时触发ADC。此时PWM输出处于“峰值”状态,对于常见的低边采样电路,此时下桥臂导通,电流流过采样电阻,是采样的最佳时机。
    • ADC转换需要时间。设置INTCNTZERO在计数器归零时产生中断。在理想情况下,ADC转换应在计数器递减到0之前完成。计算好PWM周期、ADC采样转换时间,确保在INTCNTZERO中断服务程序中,ADC结果寄存器已经准备好。
  3. 中断服务程序(ISR)流程
    • PWM0_Handler中,检查PWM_RIS_INTCNTZERO标志。
    • 读取ADC采样结果寄存器,获取两相电流值。
    • 执行FOC或其它电流控制算法,计算得到新的电压矢量对应的占空比。
    • 将新的占空比换算为PWMnCMPA/PWMnCMPB寄存器的值,并写入对应的影子寄存器(由于CMPAUPD等设置为全局同步,写入不会立即生效)。
    • 清除PWM_RIS_INTCNTZERO中断标志。
  4. 同步更新
    • 在主循环或一个更低优先级的任务中,定期(例如每几个PWM周期)或根据控制周期,向PWMCTL寄存器发起一次全局同步更新请求。
    • 所有PWM发生器会在下一个同步点,同时将影子寄存器中的新比较值加载到工作寄存器,从而更新PWM占空比。这保证了多相PWM占空比变化的严格同步,避免了因更新时刻不同步导致的转矩脉动。

4.3 常见问题排查与调试技巧

  1. PWM无输出?

    • 检查清单
      • 系统时钟和PWM模块时钟是否使能?(SYSCTL_RCGCPWM
      • GPIO引脚是否正确配置为PWM功能?(GPIO_AFSEL,GPIO_PCTL
      • PWM发生器是否使能?(PWMnCTL.ENABLE = 1
      • PWM输出是否使能到引脚?(PWMENABLE.PWMnEN = 1
      • 如果使用了同步更新模式,是否发出了全局同步更新命令?(写PWMCTL.UPDATE位)
      • PWMnLOAD寄存器是否配置了非零值?
      • PWMnCMPA寄存器值是否小于PWMnLOAD值?(否则占空比100%或0%可能看起来像没输出)
      • 是否发生了故障?检查PWMSTATUSPWMFAULTVAL
  2. 故障保护不生效?

    • 检查清单
      • 故障输入引脚配置是否正确?(上下拉、输入类型)
      • PWMnCTL.FLTSRC设置是否正确?如果使用外部引脚,应设为0。
      • PWMFAULT寄存器中对应的故障源是否使能?
      • PWMFAULTVAL寄存器中对应PWM输出的故障值是否设置正确?
      • PWMnCTL.LATCH位是否设置?如果故障是短脉冲,非锁存模式可能捕捉不到。
      • 故障输入的电平极性是否符合预期?(有效电平是高还是低?)
  3. ADC触发不同步或采样时刻不准?

    • 检查清单
      • 确认PWM触发事件(如TRCNTLOAD)是否使能。
      • 确认ADC采样序列的触发源配置为正确的PWM发生器触发。
      • 检查PWM计数器的模式(递减/中心对齐)与预期的触发点是否匹配。
      • 使用示波器同时观察PWM波形和ADC采样保持(如果引脚可用)或一个由ADC转换结束触发的GPIO翻转信号,直观判断触发延时。
      • 考虑ADC采样转换时间。如果从触发到转换完成的时间超过半个PWM周期,在计数器归零中断中读取ADC结果可能尚未就绪。需要调整触发点或降低PWM频率。
  4. 多路PWM输出不同步,有微小错位?

    • 检查清单
      • 确保所有相关PWM发生器的LOADUPDCMPAUPDGENAUPD以及PWMENUPD都设置为全局同步模式。
      • 确保在修改了需要同步的参数(LOAD, CMP, ENABLE)后,只进行一次全局同步更新请求(写PWMCTL.UPDATE)。
      • 检查所有PWM发生器是否使用相同的时钟源和分频配置。
      • 在示波器上使用高分辨率模式观察多路PWM的上升沿,确认错位是固定的还是随机的。固定错位可能是软件配置顺序导致,随机错位可能是噪声或时序问题。

调试利器: 充分利用Tiva微控制器的**软件调试触发(Software Trigger)**功能。你可以通过写PWMnSWT寄存器来手动产生一个ADC触发脉冲,而不依赖PWM计数器。这在调试ADC采样链路时非常有用,可以隔离PWM时序问题。