TMS320F28003x ADC高级功能解析:SOC优先级、突发模式与后处理块实战

1. 项目概述与核心价值

在电机控制、数字电源或者任何需要高精度实时反馈的嵌入式系统里,ADC(模数转换器)的角色,远不止是“把电压变成数字”那么简单。它更像是整个数字控制系统的“感官神经末梢”,其采样时机、转换速度、数据准确性和处理延迟,直接决定了控制环路能否稳定、精准地运行。很多工程师在项目初期,往往只关注ADC的分辨率(比如12位)和采样率,却在实际调试中,被诸如“采样序列冲突导致数据错位”、“中断响应不及时错过关键数据”、“软件后处理开销过大拉低环路带宽”等问题搞得焦头烂额。

TMS320F28003x系列微控制器作为TI C2000平台的主力,其ADC模块的设计深度,恰恰是为了解决这些深层次的工程痛点。它不仅仅提供了一个转换引擎,更内置了一套精密的“调度系统”和“预处理流水线”。突发模式(Burst Mode)SOC(Start-of-Conversion)优先级机制,让你能像交通指挥官一样,在多个模拟信号源同时“请求”采样时,决定谁先谁后,谁可以“插队”,从而确保关键信号的实时性。而后处理块(PPB)则像是一个紧挨着ADC输出端的“智能协处理器”,能在数据进入CPU或DMA之前,自动完成偏移校正、误差计算、越限比较甚至零交越检测,将原本需要数十个CPU周期才能完成的软件算法,转化为硬件零延迟操作。

这篇文章,我就结合手册中的核心图示和寄存器描述,拆解这两个常被忽略但至关重要的高级功能。我会带你走过从配置思路、寄存器操作到实际调试的完整路径,分享那些在数据手册字里行间不易察觉的“坑”和技巧。无论你是在设计一台伺服驱动器,还是一个高功率因数校正电源,理解这些机制,都能让你从“ADC能用”进阶到“ADC用得精妙”。

2. SOC优先级与突发模式:构建确定性的采样序列

在复杂的控制系统中,我们常常需要采样多个模拟量。例如,在一个三相电机控制中,你需要同时(或按特定相位)采样三相电流和直流母线电压。如果所有SOC都采用简单的轮询(Round-Robin)方式,当高优先级事件(如过流保护)触发采样时,它必须排队等待,这就会引入不可控的延迟。F28003x的ADC通过可配置的SOC优先级和突发模式,提供了解决这一问题的硬件方案。

2.1 SOC优先级机制解析

F28003x的ADC模块拥有16个SOC(SOC0-SOC15)配置寄存器。每个SOC都可以独立配置其触发源(TRIGSEL)、采样通道(CHSEL)和采样窗口时间(ACQPS)。关键在于,每个SOC还可以被单独配置为“高优先级”。

优先级仲裁逻辑:当多个SOC的触发条件同时满足时,ADC的仲裁逻辑如下:

  1. 高优先级SOC:所有被设置为高优先级的SOC,其触发会立即中断当前的轮询指针(RRPOINTER),优先进行转换。高优先级SOC之间,编号小的拥有更高的优先级(即SOC0 > SOC1 > ... > SOC15)。
  2. 轮询(Round-Robin)优先级SOC:未被设置为高优先级的SOC,按照轮询指针的顺序依次服务。轮询指针指向下一个待服务的轮询SOC。

这个机制的核心价值在于确定性。你可以将关键的保护信号(如电流保护)对应的SOC设置为高优先级,并分配较小的SOC编号。这样,无论ADC当前正在处理哪个轮询序列的转换,一旦保护信号触发,都能立即响应,最大程度地缩短故障检测到响应的延迟。

2.2 突发模式(Burst Mode)深度剖析

突发模式是优先级机制的一个强力补充,它专为需要连续、快速采样同一通道或一组通道的场景优化。其核心思想是:当一个特定的“突发触发信号”(BURSTTRIG)到来时,ADC不是只执行一个SOC,而是连续执行BURSTSIZE个SOC转换。

配置要点与工作流程

  1. 使能与配置:通过设置ADCCTL1.BURSTEN=1来使能突发模式。ADCCTL1.BURSTSIZE字段决定了每次突发触发时,连续执行的SOC数量(1-16)。
  2. 触发源:突发模式拥有独立的触发选择寄存器ADCBURSTTRIGSEL。通常,我们可以将其配置为与某个ePWM模块的SOC信号同步,用于在PWM周期的特定点启动一组密集采样。
  3. 与优先级协同工作:这是最精妙的部分。如图16-6所示,突发触发会检查当前的轮询指针,并从指针位置开始,连续执行BURSTSIZE轮询优先级的SOC。高优先级SOC可以打断正在进行的突发序列

让我们结合手册图16-6的例子(SOCPRIORITY=4, BURSTEN=1, BURSTSIZE=1)来还原一下这个动态过程:

  • 初始状态(A):复位后,轮询指针RRPOINTER=16(指向SOC0)。假设SOC4被配置为高优先级。
  • 步骤ABURSTTRIG触发信号到达。ADC检查指针,发现SOC4是轮询队列中的第一个(但SOC4是高优先级,不参与轮询?这里图示有微妙之处)。实际上,此例中SOC4和SOC5被“设置并立即转换”。我的理解是,此配置下,突发触发会直接转换RRPOINTER指向的SOC及其后一个SOC(因为BURSTSIZE=1,但可能涉及内部队列)。随后,RRPOINTER更新为5。
  • 步骤BBURSTTRIG和SOC1的触发同时到达。SOC1是高优先级,因此它立即中断当前流程,其配置的通道被转换。同时,SOC6和SOC7(当前轮询队列的前两个)被“设置”但处于等待状态。
  • 步骤C:高优先级SOC1转换完成后,ADC继续处理刚才被挂起的轮询SOC,即SOC6和SOC7,按顺序进行转换。
  • 步骤D/E:转换完成后,RRPOINTER更新,等待下一次触发。

实操心得:突发模式的典型应用场景在相电流采样中,我们常需要在PWM波形的“谷底”或“峰顶”附近进行采样以避开开关噪声。使用突发模式,你可以用一个ePWM触发信号,连续采样三相电流(SOC0, SOC1, SOC2)。即使此时有高优先级的母线电压过压检测(SOC3)触发,它也能打断电流采样序列,确保保护功能绝对优先。完成后,电流采样序列会从被打断处继续或根据RRPOINTER重新开始,这取决于你的具体配置和需求。这种硬件级的调度,比用软件管理序列要可靠和高效得多。

2.3 寄存器配置实战与避坑指南

理解了原理,配置就清晰了。以下是配置一个高优先级SOC(用于过流保护)和一个突发模式序列(用于三相电流采样)的代码示例和关键点。

// 假设使用 ADCA // 1. 配置高优先级SOC(例如SOC0,用于快速过流保护) AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // 采样ADCINA0(电流信号) AdcaRegs.ADCSOC0CTL.bit.ACQPS = 63; // 设置足够的采样窗口时间,根据外部RC电路调整 AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 1; // 触发源选择,例如ePWM1的SOCA AdcaRegs.ADCSOC0CTL.bit.SOCPRIORITY = 1; // 设置为高优先级!这是关键。 // 2. 配置用于突发模式的轮询SOC(例如SOC1, SOC2, SOC3 用于三相电流) AdcaRegs.ADCSOC1CTL.bit.CHSEL = 1; // ADCINA1 AdcaRegs.ADCSOC1CTL.bit.ACQPS = 19; // 采样窗口 AdcaRegs.ADCSOC1CTL.bit.TRIGSEL = 10; // 触发源选择为“无”或一个不常用的,因为将由突发触发控制 AdcaRegs.ADCSOC1CTL.bit.SOCPRIORITY = 0; // 必须为轮询优先级 AdcaRegs.ADCSOC2CTL.bit.CHSEL = 2; // ADCINA2 AdcaRegs.ADCSOC2CTL.bit.ACQPS = 19; AdcaRegs.ADCSOC2CTL.bit.TRIGSEL = 10; // 同上 AdcaRegs.ADCSOC2CTL.bit.SOCPRIORITY = 0; AdcaRegs.ADCSOC3CTL.bit.CHSEL = 3; // ADCINA3 AdcaRegs.ADCSOC3CTL.bit.ACQPS = 19; AdcaRegs.ADCSOC3CTL.bit.TRIGSEL = 10; AdcaRegs.ADCSOC3CTL.bit.SOCPRIORITY = 0; // 3. 配置突发模式 AdcaRegs.ADCCTL1.bit.BURSTEN = 1; // 使能突发模式 AdcaRegs.ADCCTL1.bit.BURSTSIZE = 2; // 突发大小为3?不,这里设置为2,表示连续执行3个?注意:BURSTSIZE=0表示1个,1表示2个,以此类推。通常BURSTSIZE = 连续SOC数 - 1。 // 假设我们想连续采样SOC1,2,3,则BURSTSIZE应设为2。 AdcaRegs.ADCBURSTTRIGSEL.bit.TRIGSEL = 8; // 设置突发触发源,例如ePWM2的SOCA // 4. 初始化轮询指针(可选,通常复位后从SOC0开始) AdcaRegs.ADCSOCFRC1.all = 0; // 确保没有软件强制触发 // 轮询指针由硬件自动管理,通常无需软件初始化,除非需要特定起始点。

关键注意事项与避坑指南

  1. BURSTSIZE的定义:这是一个极易混淆的点。寄存器字段BURSTSIZE的值N,代表一次突发触发会连续执行N+1个SOC转换。如果你需要连续采样3个通道,应设置BURSTSIZE=2
  2. 触发源冲突:被配置为突发序列的SOC(如上述SOC1/2/3),其自身的TRIGSEL最好设置为一个不会发生的触发源(如保留值)。否则,当它的独立触发源和BURSTTRIG同时或交错到来时,会产生不可预期的行为,可能导致序列混乱。最佳实践是让突发序列的SOC完全由BURSTTRIG控制。
  3. 高优先级的代价:高优先级SOC虽然响应快,但频繁打断轮询序列会导致轮询序列的完成时间不确定。在规划采样时序时,必须考虑最坏情况下的延迟。
  4. 指针状态查看:在复杂应用中,调试时可以通过读取ADCSOCPRIORITYCTL寄存器中的RRPOINTER位域,来了解当前轮询指针的位置,这对于分析序列执行异常非常有帮助。

3. 后处理块(PPB):将软件算法卸载到硬件

ADC转换完成,我们拿到原始数字码值,这只是第一步。在实际应用中,我们几乎总是需要对这些原始值进行后续处理:减去一个固定的偏置电压、计算与设定值的误差、判断是否超过安全限、检测信号是否过零等。如果在主循环或中断服务程序(ISR)中用软件做这些,会消耗宝贵的CPU时间,并增加“采样-处理-输出”的总延迟。F28003x的PPB功能,就是为了消除这部分开销而生的。

3.1 PPB架构与核心功能

每个ADC模块有4个独立的PPB(PPB1-PPB4)。每个PPB可以绑定到16个ADC结果寄存器(ADCRESULT0-15)中的任意一个。这意味着,你可以将一个特定的采样通道(SOC)的结果,同时送给多个PPB进行不同的处理。

PPB的核心功能链如图16-8所示,主要包括:

  1. 偏移校正(Offset Correction):直接对ADCRESULT进行加/减一个12位校准值OFFCAL,结果仍存回ADCRESULT注意:此操作是饱和运算,结果限制在0-4095(12位模式)之间。
  2. 误差计算/双极性转换(Error Calculation/Bipolar Conversion):从ADCRESULT中减去一个参考值OFFREF,结果存入独立的ADCPPBxRESULT寄存器(32位,有符号扩展)。还可以使能TWOSCOMPEN位来对结果取补码,方便生成双极性信号。
  3. 限值检测与零交越检测(Limit & Zero-Crossing Detection):将ADCPPBxRESULT与用户设定的高限LIMITHI、低限LIMITLO比较,或检测其符号变化(零交越)。当事件发生时,可以自动置位事件标志,并可配置为直接触发PWM跳变(Trip)和/或产生ADC事件中断。
  4. 采样延迟捕获(Sample Delay Capture):这是一个非常强大的诊断功能。它可以测量从SOC触发信号发出,到该SOC实际开始采样的时间差(以SYSCLK周期为单位)。这对于检测多个异步触发源导致的采样冲突至关重要。

3.2 偏移校正与误差计算实战

假设我们在ADCINA0通道上连接了一个电流传感器,其输出存在50个LSB的固定偏置(零点漂移)。我们希望移除这个偏置,并计算与目标值2048(中点)的误差。

// 配置 SOC0 采样 ADCINA0 AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = ...; // 配置触发源 AdcaRegs.ADCSOC0CTL.bit.ACQPS = ...; // 配置 PPB1 绑定到 SOC0 的结果寄存器 (ADCRESULT0),并进行偏移校正 AdcaRegs.ADCPPB1CONFIG.bit.CONFIG = 0; // 指向 SOC0 的结果寄存器 // 假设我们测量得到偏置为 +50 LSB。为了校正,我们需要减去50。 // 但注意:OFFCAL是直接加到ADCRESULT上的。如果原始值偏大,我们需要一个负的OFFCAL来校正。 // 然而,OFFCAL是无符号数。因此,我们通常使用误差计算功能来做减法,偏移校正更适用于固定补偿。 // 这里演示偏移校正:如果传感器输出偏小,我们需要加一个正值。 AdcaRegs.ADCPPB1OFFCAL.bit.OFFCAL = 50; // 增加50个LSB // 经过PPB1处理后,ADCRESULT0 = 原始值 + 50。 // 配置 PPB2 也绑定到 SOC0,进行误差计算(更常用) AdcaRegs.ADCPPB2CONFIG.bit.CONFIG = 0; // 同样指向 SOC0 AdcaRegs.ADCPPB2OFFREF.bit.OFFREF = 2048; // 目标值,假设为2048 (1.65V @ 3.3V VREF) // 经过PPB2处理后,ADCPPB2RESULT = (ADCRESULT0) - 2048。 // 这是一个有符号的32位数。如果原始值大于2048,结果为正值;小于2048,结果为负值。 // 这个结果可以直接用于PID等控制算法的误差输入,无需软件再计算。

重要提示:手册中特别指出,如果多个PPB指向同一个SOC,那么偏移校正(OFFCAL)实际生效的值,来自编号最大的PPB。例如,PPB1和PPB4都指向SOC0,且都设置了OFFCAL,则只有PPB4的OFFCAL会生效。这是一个潜在的坑,容易导致意料之外的覆盖。因此,建议一个SOC只用一个PPB做偏移校正,或者使用误差计算功能来替代。

3.3 限值检测与自动保护联动

这是PPB最出彩的功能之一,能极大提升系统的安全性和响应速度。例如,我们需要在电流超过某个阈值时,立即关闭PWM输出(硬件斩波)。

// 继续使用 PPB2 的结果 (ADCPPB2RESULT) 进行限值检测 // 假设 ADCPPB2RESULT = 电流采样值 - 2048。 // 我们设定电流正方向上限对应误差为 +500 LSB,下限为 -500 LSB。 AdcaRegs.ADCPPB2TRIPHI.bit.LIMITHI = 500; // 高限 AdcaRegs.ADCPPB2TRIPLO.bit.LIMITLO = -500; // 低限(注意:寄存器字段可能是有符号的,需查看手册确认) // 配置事件触发PWM跳变 AdcaRegs.ADCEVTSEL.bit.PPB2TRIPHI = 1; // 允许PPB2高限事件触发PWM跳变 AdcaRegs.ADCEVTSEL.bit.PPB2TRIPLO = 1; // 允许PPB2低限事件触发PWM跳变 // 具体映射到哪个PWM的Trip Zone,需要配置PWM模块的TZSEL寄存器,将ADC事件作为触发源之一。 // 配置事件产生中断(可选,用于记录或复杂处理) AdcaRegs.ADCEVTINTSEL.bit.PPB2TRIPHI = 1; // 允许PPB2高限事件产生中断 AdcaRegs.ADCEVTINTSEL.bit.PPB2TRIPLO = 1; // 允许PPB2低限事件产生中断 // 使能PPB的比较功能(如果需要零交越检测,也在此使能) // 通常限值检测是自动的,但需要确保PPB配置正确指向了SOC。

工作流程

  1. ADC完成SOC0转换,结果经PPB2计算得到ADCPPB2RESULT
  2. 硬件自动比较ADCPPB2RESULTLIMITHILIMITLO
  3. 如果超限,硬件在同一个SYSCLK周期内置位ADCEVTSTAT.PPB2TRIPHIPPB2TRIPLO标志。
  4. 同时,如果事件选择使能,一个硬件跳��信号会直接发送到指定的PWM模块,无需CPU干预,PWM输出立即进入预设的安全状态(如高阻、强制低)。
  5. 如果中断使能,CPU会进入ADC事件中断服务程序,可以读取ADCEVTSTAT寄存器来判断是哪个PPB的哪个事件触发了中断,并进行日志记录或复杂恢复操作。

实操心得:硬件保护 vs 软件保护在过流、过压等关键保护中,必须使用PPB的硬件跳变功能。因为软件中断响应,即使优化得再好,也有至少几十到上百个时钟周期的延迟。而硬件跳变路径是并行的,延迟极短(通常在几十纳秒级别),能有效防止功率器件在故障期间损坏。软件中断应作为“二级保护”或用于故障记录和系统状态管理。

3.4 采样延迟捕获:诊断采样冲突的利器

在多个控制环路(如速度环、电流环)异步触发ADC采样时,可能会发生触发冲突,导致某个环路的采样被延迟,从而引入额外的相位滞后或误差。PPB的延迟捕获功能可以量化这个延迟。

// 使能 PPB3 的延迟捕获功能,并绑定到 SOC5 AdcaRegs.ADCPPB3CONFIG.bit.CONFIG = 5; // 指向 SOC5 // 在需要的时候,读取延迟时间戳 uint16_t sample_delay; sample_delay = AdcaRegs.ADCPPB3STAMP.bit.DLYSTAMP; // 单位为 SYSCLK 周期数 // 计算实际延迟时间 (单位:秒) float delay_time_us = (float)sample_delay / (float)SYSCLK_FREQ_MHZ; // 假设频率单位为MHz,结果即为微秒数

原理:ADC内部有一个基于SYSCLK的12位自由运行计数器FREECOUNT。当SOC的触发信号到来时,计数器值被锁存到REQSTAMP。当该SOC真正开始采样时,用当前的FREECOUNT减去REQSTAMP,差值存入DLYSTAMP

关键注意事项

  1. DLYSTAMP是12位寄存器,最大值为4095。如果触发到实际采样的延迟超过4096个SYSCLK周期,计数器会翻转,导致计算结果错误。因此,此功能不适用于采样间隔非常长的应用
  2. 手册明确指出,如果SOC是由软件触发(ADCSOCFRC1)的,则延迟捕获功能不工作。因为软件触发无法记录一个精确的“触发时刻”硬件事件。延迟捕获仅对硬件触发源(如ePWM, GPIO, 定时器)有效。
  3. 这个功能是诊断性的。你可以在调试阶段,将关键SOC绑定到一个PPB并读取延迟值,来验证你的触发设计是否避免了冲突,或者评估最坏情况下的延迟。在产品代码中,通常可以关闭此功能以节省资源。

4. 中断机制与高级时序控制

ADC转换完成的通知机制,直接关系到数据读取的及时性和系统效率。F28003x提供了灵活且可配置的中断机制,允许你在数据就绪的“恰好”时刻进行处理。

4.1 EOC、中断标志与溢出处理

每个SOC转换完成都会产生一个EOC(转换结束)脉冲。这个脉冲可以映射到4个ADC中断(ADCINT1-4)中的任意一个。通过配置ADCINTSELxNy寄存器,你可以决定哪个SOC的EOC去触发哪个ADCINT。

关键寄存器与流程

  • ADCINTFLG:中断标志寄存器。当EOC脉冲到达且满足中断选择条件时,对应的标志位被置1。
  • ADCINTFLGCLR:写1清除相应的中断标志。
  • ADCINTOVF:中断溢出标志寄存器。如果EOC试图置位一个已经为1ADCINTFLG位,则对应的溢出标志置1。这表示你错过了一次中断(CPU未及时处理)。

中断服务程序(ISR)的标准模板必须包含溢出检查

__interrupt void adcA1_ISR(void) { // 1. 读取ADC结果数据 adcResult0 = AdcaResultRegs.ADCRESULT0; adcResult1 = AdcaResultRegs.ADCRESULT1; // ... // 2. 清除ADC中断标志(向ADCINTFLGCLR对应位写1) AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // 3. 【关键步骤】检查并处理溢出 if (AdcaRegs.ADCINTOVF.bit.ADCINT1 == 1) { // 发生了溢出,意味着至少有一次转换完成事件被丢失 AdcaRegs.ADCINTOVFCLR.bit.ADCINT1 = 1; // 清除溢出标志 AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // 再次清除中断标志,确保状态干净 // 这里可以增加错误处理,如置位错误标志、增加计数器等。 systemErrorFlags |= ADC_OVERFLOW_ERROR; } // 4. 确认中断已处理,并返回 AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // 有些工程师习惯再清一次,确保无误 PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // 应答PIE中断,允许同组其他中断 }

为什么必须检查溢出?在高速采样或中断服务程序执行时间过长时,可能发生前一次中断还未处理完,后一次转换又完成了。如果不检查溢出,你会丢失数据,且可能因为中断标志一直未被有效清除,导致后续中断无法再进入。上述代码中,在清除标志后检查溢出,如果发现溢出,就再次清除标志,这是一种恢复中断通道的稳健做法。

4.2 早期中断模式与可配置延迟

这是优化实时性的一个高级特性。默认情况下,中断标志在转换完全结束(EOC)时才置位。从EOC到CPU开始读取结果,中间有中断响应延迟。早期中断模式允许你在转换结束之前就进入中断服务程序。

配置逻辑

  1. 设置ADCCTL1.INTPULSEPOS = 0,使中断脉冲在采样保持阶段结束后立即产生(即图16-12中的tINT提前)。
  2. 通过ADCINTCYCLE.DELAY字段,可以精细地配置这个“提前”的中断,具体延迟多少个SYSCLK周期后再置位中断标志。

应用场景:假设你的ADC转换需要20个SYSCLK周期,而中断服务程序开头有一些与ADC结果无关的固定开销(比如保存上下文、读取其他状态)。你可以设置DELAY=15,这样在转换完成前5个周期就进入中断。当ISR执行完固定开销代码,刚好到达读取ADC结果的那条指令时,数据正好锁存到结果寄存器(tLAT时刻之后),实现了“零等待”读取。

// 配置早期中断模式,并设置延迟 AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 0; // 0: 早期中断模式 (在S+H结束时产生脉冲) AdcaRegs.ADCINTCYCLE.bit.DELAY = 15; // 延迟15个SYSCLK周期后置位中断标志 // 计算和验证:你需要根据 tSH, tLAT 和 ISR 执行到读取结果指令的周期数,来调整DELAY值。 // tLAT 的值取决于ADCCLK分频(PRESCALE),参见手册表16-9。 // 例如,PRESCALE=0时,tLAT=11个SYSCLK周期。如果你希望数据刚好就绪时读取, // 那么从S+H结束到数据就绪是11周期。假设ISR开头需要10个周期才执行到读取指令, // 那么DELAY可以设为1 (11-10),让中断在S+H结束后1个周期触发。

注意事项:使用早期中断模式需要非常精确的时序计算。如果DELAY设置过小,在ISR中读取ADC结果时数据可能还未就绪(读到的是旧数据)。如果DELAY设置过大,则失去了提前进入中断的意义。务必结合PRESCALEACQPS计算tLAT,并通过示波器或仿真仔细验证。一个稳妥的方法是,先使用默认的晚期中断模式(INTPULSEPOS=1)让系统跑通,再进行此项优化。

5. 常见问题排查与调试技巧实录

即使理解了所有原理和配置,在实际硬件调试中,ADC问题依然是最常见的挑战之一。下面是我在多个项目中总结的一些典型问题及其排查思路。

5.1 问题一:采样值不准,噪声大或跳动异常

  • 现象:ADC读数不稳定,与预期电压值偏差大,或存在规律的毛刺。
  • 排查步骤
    1. 检查硬件电路:这是首要步骤。测量ADC输入引脚的实际电压,确保在采样窗口内是稳定的。检查输入端的RC滤波电路,电阻电容值是否合适。采样窗口时间ACQPS必须足够长,让采样电容充电到输入电压的误差范围内。ACQPS的计算公式为:所需时间 =(ACQPS + 1) * T_SYSCLK。必须大于外部电路的时间常数(τ = R_source * C_hold)的若干倍(通常5倍以上可达到99%以上精度)。
    2. 检查参考电压:测量VREFHIVREFLO引脚电压是否稳定、干净。这是ADC的基准,其噪声会��接反映在所有结果上。
    3. 检查电源和地:确保模拟电源VDDA和数字电源VDD的隔离良好,模拟地VSSA和数字地之间使用单点连接。电源纹波过大是导致噪声的常见原因。
    4. 检查配置:确认ADCPWDNZ位已置1(ADC已上电)。确认ADCBGPWDADCREFPWD位(如果存在)也已正确上电。检查PRESCALE分频是否过高,导致ADCCLK太慢,但通常这不是主要问题。
    5. 使用PPB偏移校正:如果是一个固定的偏置,可以尝试用PPB的OFFCAL功能进行补偿,但这只是治标,仍需找到偏置产生的根本原因(通常是硬件或参考电压问题)。

5.2 问题二:中断无法进入或进入过于频繁

  • 现象:配置了ADC中断,但程序从未进入对应的ISR;或者相反,疯狂进入中断。
  • 排查步骤
    1. 确认PIE和CPU级中断使能:这是新手最常犯的错误。不仅要使能ADC模块自身的中断(ADCINTSELxNy.INTxE=1),还要使能PIE模块中对应的组和中断线(PIEIERx.y=1),最后要使能CPU级的总中断(EINT;IER |= M_INTx;)。
    2. 检查中断标志清除:在ISR中,是否清除了ADCINTFLG标志?是否清除了PIE应答位(PIEACK)?如果忘记清除PIEACK,同组其他中断将被阻塞。
    3. 检查溢出标志:如果中断标志清除不当导致溢出,可能会破坏中断逻辑。按照4.1节的ISR模板,加入溢出检查和恢复。
    4. 验证触发源:ADC中断是由SOC的EOC触发的。首先确保SOC能被正确触发。你可以先使用查询模式(轮询ADCINTFLG),确认ADC转换确实能完成并置位标志。
    5. 早期中断模式配置错误:如果使用了早期中断模式且DELAY设置不当,可能导致中断在数据就绪前触发,在ISR中读不到新数据,但标志已被清除,造成“中断进了但没数据”的假象。

5.3 问题三:多ADC同步采样时序错位

  • 现象:使用多个ADC(如ADCA和ADCB)进行同步采样,但读回的数据在时间上存在偏移。
  • 排查步骤
    1. 严格遵守同步配置规则:如手册16.13节所述,要实现同步,所有ADC的SOC配置(TRIGSEL,ACQPS)必须完全相同。优先级控制(SOCPRIORITY)、突发模式(BURSTEN,BURSTSIZE)和突发触发(BURSTTRIGSEL)也必须完全一致
    2. 避免软件触发:手册明确指出,软件触发无法保证多个ADC同时启动,因此绝对不能将需要同步的SOC配置为软件触发。应使用同一个硬件触发源(如同一个ePWM的SOC信号)。
    3. 检查时钟源:确保所有ADC的时钟源(SYSCLK)和分频(PRESCALE)一致。
    4. 使用PPB延迟捕获功能诊断:这是最直接的诊断工具。为ADCA和ADCB需要同步的SOC分别配置PPB延迟捕获。在触发后读取两者的DLYSTAMP。如果值差异很大(比如超过几个SYSCLK周期),说明触发或启动不同步。理想情况下,差值应为0或一个非常固定的微小值(与布线延迟有关)。

5.4 问题四:PPB限值检测或零交越检测不动作

  • 现象:配置了PPB的限值比较和PWM跳变,但实际信号超限时PWM没有反应。
  • 排查步骤
    1. 确认PPB配置绑定ADCPPBxCONFIG.CONFIG是否指向了正确的SOC结果寄存器?
    2. 确认比较值符号和范围LIMITHILIMITLO寄存器是16位有符号整数吗?你设置的值是否在ADCPPBxRESULT(32位有符号)的合理范围内?例如,ADCPPBxRESULT是电流误差,范围可能在-2000到+2000之间,那么LIMITHI应设为正数(如500),LIMITLO应设为负数(如-500)。
    3. 检查事件通路使能ADCEVTSEL.PPBxTRIPHI/LO是否置1,允许事件通向PWM?ADCEVTINTSEL是用于中断的,与PWM跳变无关。
    4. 检查PWM模块配置:这是关键!PPB事件只是产生一个跳变信号。你必须在对应的ePWM模块中,通过TZSEL寄存器,将这个ADC事件(例如ADCEVT1)选择为Trip源之一。然后配置TZCTL寄存器,指定当此Trip事件发生时,PWM输出应进入何种状态(高阻、强制高、强制低)。
    5. 使用事件标志调试:即使PWM没动作,也可以先检查ADCEVTSTAT.PPBxTRIPHI/LO标志位是否在超限时被置1。这可以帮你定位问题是出在ADC PPB比较环节,还是PWM的Trip配置环节。

调试ADC是一个系统工程,需要硬件、软件和寄存器配置三方结合。最有效的工具是仿真器和示波器。通过CCS的实时模式,可以观察ADC结果寄存器的变化;通过示波器,可以测量实际采样时刻与PWM波形的相对关系,以及中断响应时间。养成分步验证的习惯:先让ADC在轮询模式下工作,读出正确的值;再启用中断;最后再叠加PPB、突发模式等高级功能。