1. 项目概述:从“序列器”到“SOC”的思维转变
如果你是从C2000的早期型号(比如F280x系列)或者从其他厂商的MCU转过来的工程师,第一次接触Type 3 ADC时,可能会有点懵。我们习惯了“序列器”(Sequencer)的概念:配置一个转换序列,设置好通道顺序和触发源,然后ADC就按部就班地跑。但Type 3 ADC彻底抛弃了这个模式,转而采用了一种更灵活、也更需要重新理解的架构:SOC(Start-Of-Conversion)。
你可以把SOC理解为一个“转换任务”的完整配置单元。一个SOC,就定义了一次完整的ADC转换:用什么信号触发(Trigger)?采哪个通道(Channel)?采样窗口开多久(Acquisition Window,即ACQPS)?Type 3 ADC一口气给了你16个这样的“任务卡”(SOC0-SOC15),每张卡你都可以独立填写。这就像你有一个16人的团队,每个人(SOC)都可以独立接活,活干完了结果就放到对应的“成果箱”(ADCRESULT寄存器)里,箱子编号(0-15)和人员编号(SOCx)是一一对应的。
这种设计的核心价值在于解耦与灵活性。在电机控制中,你可能需要用一个PWM周期事件同时触发三相电流的采样(要求同步性),同时又需要用一个定时器每隔一段时间去采样母线电压和温度(要求周期性)。在传统的序列器模式下,你需要精心编排一个复杂的序列,可能还要用到多个排序器。而在SOC模式下,你只需要配置:
- SOC0, SOC1, SOC2:触发源设为ePWM1的SOCA,通道分别设为电流A、B、C相,用于同步采样。
- SOC3, SOC4:触发源设为CPU Timer 0,通道分别设为母线电压和温度传感器。
各个任务互不干扰,触发来了就各自执行,优先级机制(轮询或高优先级)会帮你调度。这大大简化了多触发源、多速率采样的系统设计。接下来,我们就深入这个“任务卡”系统的内部,看看怎么把它用好。
2. SOC核心机制深度解析
2.1 SOC配置三要素:触发、通道与采样窗口
每个SOC的配置都集中在ADCSOCxCTL这个寄存器里,它定义了转换任务的三大核心要素。
1. 触发源(TRIGSEL)这是任务的“启动按钮”。Type 3 ADC的触发源非常丰富:
- 软件触发(S/W):直接写
ADCSOCFRC1寄存器的对应位,立即启动一次转换。常用于单次、非周期性的采样,比如上电自检。 - ePWM1-4的SOCA/SOCB:这是电机和数字电源控制中最常用的触发源。你可以将ADC采样点精确地锁定在PWM波形的特定时刻(例如,PWM计数器为0时或周期匹配时),这对于获取电流在PWM周期内的准确值至关重要,能有效避免开关噪声。
- GPIO XINT2:通过一个外部引脚信号来触发,适合响应外部事件,比如过流保护信号或同步信号。
- CPU Timer 0/1/2:用于产生固定频率的采样,适合温度、电压等慢变信号的监控。
- ADCINT1/2:这是一个“回环”触发,允许一次ADC转换完成的中断信号去触发下一次转换,可以实现连续不断的自动采样流,在需要高频、连续采样的应用(如振动分析)中很有用。
2. 通道选择(CHSEL)这个4位字段告诉ADC该去采集哪个引脚上的信号。对于顺序采样模式(默认),CHSEL的4位直接对应16个可能的输入通道(例如,0对应ADCINA0,1对应ADCINA1,8对应ADCINB0等)。这里有一个关键陷阱:当使用外部参考电压模式(ADCCTL1.ADCREFSEL = 1)时,ADCINA0引脚被复用为外部高参考电压VREFHI的输入引脚,此时它不能再作为普通的模拟输入通道使用。如果你的设计需要用到外部精密参考源,务必在硬件设计时就避开ADCINA0作为信号输入。
3. 采样窗口(ACQPS)这是最容易被忽视,却又对精度影响最大的参数。它定义了采样保持(S+H)开关闭合、对内部采样电容Ch进行充电的时间长度,单位是ADC时钟周期。ACQPS写入的值是采样周期数减1。例如,ACQPS=6,表示采样窗口持续7个ADC时钟周期。
为什么采样窗口如此重要?ADC的输入端不是一个理想的“电压表”,它内部有一个采样开关和电容(
Ch,典型值1.6pF),外部信号源有输出阻抗(Rs)和可能存在的寄生电容(Cs)。这构成了一个RC充电电路。如果采样窗口时间太短,采样电容上的电压还没来得及充到信号电压的真实值,转换就开始了,结果就会产生建立误差,直接导致转换结果不准确。这个误差在直流或低频信号中表现为偏移,在高频信号中则会造成幅值衰减和相位失真。
手册给出了最小ACQPS值为6(即7个周期)。但绝对不要无脑用最小值!你必须根据你的前端电路特性来计算所需的ACQPS。一个快速的经验法则是:对于由运放直接驱动的低阻抗信号(Rs < 几百欧姆),ACQPS=6(7个周期)通常是安全的。但对于直接来自高阻抗传感器(如热电偶、某些压力传感器)或经过大电阻分压的信号,必须加大ACQPS值,否则精度会惨不忍睹。
2.2 优先级与调度:轮询与高优先级模式
当多个SOC的触发信号同时到来,或者前一个转换还没结束新的触发又来了,ADC怎么处理?这就涉及到优先级机制。
1. 轮询(Round-Robin)模式这是默认模式,也是最公平的模式。你可以想象一个圆环,上面依次坐着SOC0到SOC15。有一个指针(RRPOINTER)指向上一次完成转换的SOC。当多个SOC标志位被置起时,优先级最高的就是指针指向位置的下一个SOC。例如,如果RRPOINTER=7(上次是SOC7干活),那么接下来SOC8优先级最高,然后是SOC9... SOC15,再绕回SOC0... SOC7。
这种模式保证了所有被触发的SOC任务最终都能得到执行,不会出现某个低编号SOC一直霸占ADC的情况。它非常适合多个异步、低优先级任务共存的场景。
2. 高优先级(High Priority)模式通过配置ADCSOCPRIORITYCTL寄存器的SOCPRIORITY字段,你可以将SOC0到SOC(N-1)设置为高优先级。例如,SOCPRIORITY = 4,意味着SOC0,1,2,3为高优先级,其中SOC0最高,SOC1次之,以此类推。
高优先级SOC拥有“插队”权。只要它被触发,就会在当前正在进行的任何转换完成后立即插入执行,中断正常的轮询队列。执行完后,轮询指针恢复到被中断的位置继续。如果两个高优先级SOC同时被触发,编号小的优先。
实操心得:中断服务程序(ISR)中的采样触发在电机控制FOC算法中,电流采样通常在PWM周期中点触发,并在ADC转换完成中断(EOC)中读取结果进行计算。这里有一个经典坑点:如果你在ADC中断ISR中,通过软件触发(
ADCSOCFRC1)去启动另一组用于监控的SOC(比如温度),并且这组SOC被设置为高优先级,那么它可能会打断下一周期PWM触发的、用于电流控制的SOC。导致电流采样时序错乱,引发控制环路震荡。安全的做法是:将用于实时控制的、由硬件(如ePWM)触发的SOC设置为高优先级;将用于后台监控的、由软件触发的SOC设置为轮询模式,或者确保软件触发发生在非关键时序窗口。
2.3 ONESHOT单次转换模式
ADCCTL1.ONESHOT位提供了一种特殊的单次转换模式。当此模式使能时,只有当前轮询指针(RRPOINTER)指向的下一个被触发的SOC会被执行一次,之后ADC就会停下来,等待你清除ONESHOT模式或进行其他操作。
这个模式有什么用?它非常适合低功耗场景下���单次测量。比如,在电池供电的设备中,CPU和大部分外设都在休眠,只留一个低速时钟和ADC。你可以配置一个SOC由GPIO或定时器触发,并开启ONESHOT模式。当触发事件(比如按键按下或定时时间到)发生时,ADC只执行一次预设的转换,产生中断唤醒CPU读取数据,然后CPU可以继续休眠。这避免了ADC连续转换产生的不必要功耗。
需要注意的是,在同步采样模式下,由于一次触发会完成一对(A和B通道)转换,ONESHOT模式下指针会一次前进2,而不是1。
3. 顺序采样与同步采样的工程抉择
3.1 顺序采样模式:通用与灵活
顺序采样是默认模式,也是最直观的模式。每个SOC独立地采样一个通道(A组或B组均可),一个接一个地转换。它的配置简单,通道选择自由,16个SOC可以任意映射到16个输入通道。
然而,手册第6.5节揭示了一个重要的硬件细节:即使在顺序采样模式下,ADC内部的双采样保持电路(S/H-A和S/H-B)也是同时连接到对应引脚对的!假设SOC0采样ADCINB3,在SOC0的采样窗口期间,S/H-A会连接到ADCINA3,S/H-B连接到ADCINB3,但最终只转换B通道的结果。
这意味着什么?如果你的ADCINA3引脚连接的是一个高输出阻抗或带有大电容滤波的慢速信号,那么在SOC0采样期间,S/H-A电容会对ADCINA3进行充电。如果SOC0的ACQPS时间不够长,这个充电过程可能没完成。紧接着,如果另一个SOC(比如SOC8)要采样ADCINA3,它面对的将是一个没有充分建立到正确电压的采样电容,从而导致转换误差。这就是所谓的通道间串扰,在信号源阻抗较高时尤为明显。
避坑指南:处理慢速信号对于连接在慢速信号(如NTC热敏电阻分压电路)上的通道,有以下几个对策:
- 增大ACQPS:给予足够的采样电容充电时间。
- 硬件缓冲:在信号进入ADC引脚前,增加一个电压跟随器(运放),提供低输出阻抗。
- 软件策略:安排采样顺序,让对同一个慢速通道的两次采样间隔足够长(例如,隔开多个其他通道的采样),让采样电容有足够的时间通过外部电路恢复。
- 使用同步采样对中的空闲通道:如果可能,将慢速信号安排在A通道,并确保其对应的B通道在软件配置中不被使用(或连接到一个稳定的电压),这样可以减少B通道电容引入的不确定性。
3.2 同步采样模式:为控制而生
同步采样是Type 3 ADC的亮点功能,专为需要严格同时刻采集多路信号的应用设计,最典型的就是三相电机控制中的相电流采样。
配置方法: 同步采样以SOC对为单位启用。通过设置ADCSAMPLEMODE寄存器中的SIMULENx位(x=0~7),可以将SOC(2x)和SOC(2x+1)配对。例如,设置SIMULEN0=1,则SOC0和SOC1结成一对。
工作流程: 当这对SOC中的任意一个(通常是偶数SOC)被触发时:
- 同时采样:ADC内部的S/H-A和S/H-B电容同时连接到一对A和B通道上。通道号由被触发SOC的
CHSEL字段的低3位决定(有效值0-7)。例如,SOC0的CHSEL=2,则同时采样ADCINA2和ADCINB2。 - 顺序转换:采样结束后,ADC先转换A通道(ADCINA2)的值,存入偶数结果寄存器(ADCRESULT0);然后转换B通道(ADCINB2)的值,存入奇数结果寄存器(ADCRESULT1)。
- 中断信号:会分别产生EOC0和EOC1信号,其产生时刻(转换开始或结束)由
ADCCTL1.INTPULSEPOS位控制。
核心优势与注意事项:
- 消除相位差:对于电机控制,三相电流必须在同一时刻采样,才能准确计算矢量角度。同步采样从硬件上保证了这一点,这是顺序采样无法比拟的。
- 结果寄存器固定映射:A通道结果永远在偶数寄存器(ADCRESULT0, 2, 4...),B通道在奇数寄存器(ADCRESULT1, 3, 5...)。在编程读取时需要特别注意。
- 通常只配置偶数SOC:一般只需配置SOC0(触发、通道),并使能SIMULEN0。SOC1可以保持禁用或用于其他目的。如果SOC1也被配置为触发,那么它也会启动一次同步采样,这通常不是我们想要的,容易造成混乱。
- 通道对限制:同步采样只能采样固定的A-B通道对(如A0-B0, A1-B1, ..., A7-B7)。硬件设计时,需要同步采样的信号必须规划到对应的引脚对上。
4. ACQPS参数计算:从理论到实践的精确校准
ACQPS的设置绝非拍脑袋决定,它直接关系到ADC的精度。手册提供了针对高带宽和低带宽信号的两套计算方法,我们来深入理解并实践。
4.1 高带宽信号场景(如运放缓冲后的电流、电压信号)
高带宽信号通常指由运放等低阻抗源驱动、需要快速采样的信号,例如电机相电流经过运放调理后的信号。
计算步骤与实例: 假设我们有一个电机相电流采样电路,经过运放后,输出阻抗Rs=56Ω,运放输出端到ADC引脚有少量寄生电容Cs=2.2nF(可能来自PCB走线和滤波电容)。ADC时钟fADCCLK=30MHz。我们要求建立误差小于1/4 LSB(对于12位ADC,即1/16384)。
已知ADC模型参数(通常来自数据手册):
Ron(采样开关电阻)= 3400 ΩCh(采样电容)= 1.6 pFCp(引脚寄生电容)= 5 pF
第一步:计算RC时间常数τ公式:τ = (Rs + Ron) * Ch + Rs * (Cs + Cp)代入:τ = (56 + 3400) * 1.6e-12 + 56 * (2.2e-9 + 5e-12)计算:τ ≈ (3456*1.6e-12) + (56*2.205e-9) ≈ 5.53e-9 + 123.5e-9 = 129 ns
第二步:计算所需的时间常数倍数k公式:k = ln(2^n / settling_error) - ln((Cs + Cp) / Ch)代入:k = ln(4096 / 0.25) - ln((2.2e-9 + 5e-12) / 1.6e-12)计算:k = ln(16384) - ln(2.205e-9 / 1.6e-12) ≈ 9.70 - ln(1378) ≈ 9.70 - 7.23 = 2.47
第三步:计算最小采样保持时间 t_S+H公式:t_S+H = k * τ计算:t_S+H = 2.47 * 129 ns ≈ 318.6 ns
第四步:计算ACQPS值并向上取整公式:ACQPS_min = (t_S+H * f_ADCCLK) - 1计算:ACQPS_min = (318.6e-9 * 30e6) - 1 = 9.56 - 1 = 8.56向上取整:ACQPS = 9
这意味着,我们需要将ACQPS字段至少设置为9,对应的采样窗口为10个ADC时钟周期(因为ACQPS=9代表10个周期)。实际采样时间t_sample = 10 * (1/30MHz) ≈ 333.3 ns,略大于计算值,满足要求。
重要提示:这个计算是基于简化的一阶RC模型。在实际的高精度应用中,尤其是信号带宽接近或超过ADC采样速率奈奎斯特频率时,必须使用SPICE工具(如TI的TINA-TI)进行仿真,将运放模型、PCB寄生参数和ADC输入模型一起仿真,观察采样电容上的电压建立波形,这是最可靠的方法。
4.2 低带宽信号场景(如温度传感器)
低带宽信号通常指输出阻抗高、变化缓慢的信号,例如热敏电阻分压网络。对于这类信号,我们通常会在ADC输入端并联一个较大的电容Cs(例如10nF~100nF)来充当电荷库,减少对采样瞬间电荷的需求。
设计思路: 我们不是直接计算ACQPS,而是先根据精度要求设计外部RC网络,再计算所需的ACQPS。
设计实例: 假设我们有一个NTC热敏电阻电路,希望每秒采样一次(t_recovery = 1s),建立误差小于1/4 LSB。我们选择Cs = 33nF(一个常见的容值),并希望其在1秒的恢复时间内能充电到接近满量程的nτ=2个时间常数(查表6-2,对应约16%的跌落误差,叠加1/4 LSB建立误差,总误差约0.29 LSB,可接受)。
第一步:根据建立误差确定Cs是否足够大公式:Cs >= Ch * (2^n / settling_error)计算:Cs >= 1.6pF * (4096 / 0.25) = 1.6pF * 16384 ≈ 26.2nF我们选择的33nF > 26.2nF,满足建立误差要求。
第二步:根据恢复时间和nτ计算最大允许的Rs公式:Rs <= t_recovery / (nτ * Cs)计算:Rs <= 1s / (2 * 33e-9 F) ≈ 15.15 MΩ热敏电阻在常温下的阻抗通常在10kΩ量级,远小于此值,因此恢复时间完全足够。
第三步:计算采样所需的ACQPS此时,采样电容Ch主要从大电容Cs充电,源阻抗的影响可以忽略。时间常数主要由Ron和Ch决定:τ = Ron * Ch = 3400 * 1.6e-12 = 5.44 nsk = ln(2^n / settling_error) = ln(16384) ≈ 9.70t_S+H = k * τ ≈ 9.70 * 5.44 ns ≈ 52.8 nsACQPS_min = (52.8e-9 * 30e6) - 1 ≈ 1.58 - 1 = 0.58向上取整:ACQPS = 1(对应2个周期)
计算结果显示,对于这类有大缓冲电容的慢信号,理论上很短的采样窗口(ACQPS=1)就够了。但在实践中,出于抗噪声和稳健性考虑,我通常会设置一个更大的值,比如ACQPS=6(7个周期)或更高。这为PCB上的寄生电感、电阻留出了余量,确保在各种环境下都能稳定采样。
5. 工程实践:从零配置一个电机控制ADC采样系统
让我们以一个典型的永磁同步电机(PMSM)FOC控制为例,配置ADC模块。需求如下:
- 同步采样三相电流(Ia, Ib, Ic)。假设Ia接ADCINA2,Ib接ADCINB2,Ic接ADCINA1(注:通常需要两个同步采样对,这里假设硬件设计允许此映射)。
- 由ePWM1的周期匹配事件(CNT=0)触发同步采样。
- 顺序采样母线电压(Vbus,接ADCINA3)和芯片温度,由CPU Timer0每1ms触发一次。
- 电流采样为高优先级,电压和温度采样为轮询模式。
5.1 硬件与时钟初始化
首先,必须完成ADC模块的上电和时钟使能,这是很多新手容易遗漏导致ADC不工作的第一步。
// 假设系统时钟 SYSCLKOUT = 120MHz // 1. 使能ADC外设时钟 (在PCLKCR0寄存器中) EALLOW; SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1; // 使能ADC模块时钟 EDIS; // 2. 延时,等待ADC模块上电稳定(参考数据手册具体时间,通常需要几个us) DELAY_US(50); // 自定义微秒延时函数 // 3. 配置ADC时钟分频 (ADCCTL2) EALLOW; AdcaRegs.ADCCTL2.bit.CLKDIV2EN = 0; // 使用默认的 /2 分频模式 // ADCCLK = SYSCLKOUT / (2 * (ADCCLKDiv+1)) AdcaRegs.ADCCTL2.bit.ADCCLKPS = 0; // 内核时钟分频器 = /1 // 此时 ADCCLK = 120MHz / (2*1) = 60MHz // 注意:ADCCLK不能超过器件支持的最大频率(如60MHz),请查阅具体型号数据手册 EDIS;5.2 配置SOC任务卡
接下来,我们按照需求配置4个SOC。
void ConfigureADCSOCs(void) { EALLOW; // --- 配置SOC0和SOC1用于同步采样三相电流中的两相 --- // 使能SOC0和SOC1的同步采样模式 (SOC0-SOC1为一对) AdcaRegs.ADCSAMPLEMODE.bit.SIMULEN0 = 1; // SOC0: 触发源为 ePWM1 SOCA (TRIGSEL=5), 通道为 ADCINA2/ADCINB2 对 (CHSEL=2) // 假设我们需要较快的采样,ACQPS设为6 (7个周期 @60MHz ≈ 117ns) // 寄存器值计算: ACQPS=6, CHSEL=2, TRIGSEL=5 // 位域: [15:10] ACQPS=6, [9:6] CHSEL=2, [5:0] TRIGSEL=5 // 二进制: 000110 0010 000101 -> 0x1845 AdcaRegs.ADCSOC0CTL.bit.ACQPS = 6; // 采样窗口 = 7个周期 AdcaRegs.ADCSOC0CTL.bit.CHSEL = 2; // 通道对 A2/B2 AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // ePWM1 SOCA // SOC1: 在同步模式下,SOC1的配置通常被忽略,但为了清晰,可以将其TRIGSEL设为不触发(如0) // 或者将其用于其他非同步触发(不推荐,易混淆)。这里设为软件触发且低优先级。 AdcaRegs.ADCSOC1CTL.bit.TRIGSEL = 0; // 软件触发,实际由SOC0触发同步对 // --- 配置SOC2用于采样第三相电流 (顺序采样) --- // SOC2: 触发源同样为 ePWM1 SOCA, 通道为 ADCINA1, ACQPS与SOC0一致 // 寄存器值: ACQPS=6, CHSEL=1, TRIGSEL=5 -> 0x1845? 不对,CHSEL不同。 // 计算: 000110 0001 000101 -> 0x1845? 仔细看: ACQPS=6(000110), CHSEL=1(0001), TRIGSEL=5(000101) // 组合: 000110 0001 000101 = 0001 1000 0100 0101 = 0x1845 (巧合,和SOC0一样?检查CHSEL位) // CHSEL是4位[9:6],1=0001。所以SOC0是(2=0010),SOC2是(1=0001)。值不同。 // SOC0: ACQPS=6(000110), CHSEL=2(0010), TRIGSEL=5(000101) -> 000110 0010 000101 = 0x1885 // SOC2: ACQPS=6(000110), CHSEL=1(0001), TRIGSEL=5(000101) -> 000110 0001 000101 = 0x1845 AdcaRegs.ADCSOC2CTL.bit.ACQPS = 6; AdcaRegs.ADCSOC2CTL.bit.CHSEL = 1; // 通道 ADCINA1 AdcaRegs.ADCSOC2CTL.bit.TRIGSEL = 5; // ePWM1 SOCA // --- 配置SOC3用于采样母线电压 --- // SOC3: 触发源为 CPU Timer 0 (TRIGSEL=10), 通道为 ADCINA3, ACQPS需要根据前端电路计算,假设为较大值15 AdcaRegs.ADCSOC3CTL.bit.ACQPS = 25; // 采样窗口 = 26个周期 @60MHz ≈ 433ns AdcaRegs.ADCSOC3CTL.bit.CHSEL = 3; // 通道 ADCINA3 AdcaRegs.ADCSOC3CTL.bit.TRIGSEL = 10; // CPU Timer 0 // --- 配置SOC4用于采样内部温度传感器 --- // 温度传感器通道是固定的,需要通过ADCCTL1.TEMPCONV位选择,而不是CHSEL。 // 首先,使能温度传感器转换 AdcaRegs.ADCCTL1.bit.TEMPCONV = 1; // 使能温度传感器作为输入源 // SOC4: 触发源为 CPU Timer 0, 通道选择任意(但会被温度传感器覆盖),ACQPS可稍大 // 注意:当TEMPCONV=1时,所有SOC的CHSEL都会被忽略,ADC内部固定连接温度传感器。 // 但为了代码清晰,我们仍然设置一个CHSEL。 AdcaRegs.ADCSOC4CTL.bit.ACQPS = 25; AdcaRegs.ADCSOC4CTL.bit.CHSEL = 0; // 实际无效,会被温度传感器覆盖 AdcaRegs.ADCSOC4CTL.bit.TRIGSEL = 10; // CPU Timer 0 // --- 设置优先级 --- // 将用于实时电流控制的SOC0-SOC2设置为高优先级 (SOCPRIORITY=3, 即SOC0,1,2为高优先级) AdcaRegs.ADCSOCPRIORITYCTL.bit.SOCPRIORITY = 3; // --- 配置中断 --- // 我们希望电流采样完成后(SOC0, SOC1, SOC2都完成)产生一个中断。 // 由于SOC0和SOC1是同步对,会产生EOC0和EOC1。SOC2产生EOC2。 // 我们可以配置ADCINT1在EOC2时触发(因为它是最后一个)。 AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // 使能ADCINT1 AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 0; // 单次模式,每次EOC2触发后需重新使能 AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 2; // 选择EOC2作为ADCINT1的触发源 // 注意:同步采样时,EOC0和EOC1也会产生。如果需要,可以配置ADCINT2响应它们。 EDIS; }5.3 配置ePWM触发与中断服务程序
配置ePWM1在计数器为零时产生SOCA触发信号。
void ConfigureEPWMForADCTrigger(void) { EALLOW; // 假设ePWM1时钟已使能 // 配置时基模块 EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // 增减计数模式,用于中心对称PWM EPwm1Regs.TBPRD = 1000; // PWM周期值,根据开关频率设定 EPwm1Regs.TBCTR = 0; // 配置事件触发 (ET) 模块,在TBCTR=0时产生SOCA信号 EPwm1Regs.ETSEL.bit.SOCAEN = 1; // 使能SOCA EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTR_ZERO; // SOCA在计数器为0时触发 EPwm1Regs.ETPS.bit.SOCAPRD = ET_1ST; // 每个选定事件都产生一次SOCA EDIS; }在ADC中断服务程序中读取结果并进行处理。
__interrupt void adcA1ISR(void) { int16_t ia_raw, ib_raw, ic_raw; float ia, ib, ic; // 读取三相电流ADC结果 // SOC0 (同步A相) -> ADCRESULT0 // SOC1 (同步B相) -> ADCRESULT1 // SOC2 (顺序C相) -> ADCRESULT2 ia_raw = AdcaResultRegs.ADCRESULT0; ib_raw = AdcaResultRegs.ADCRESULT1; ic_raw = AdcaResultRegs.ADCRESULT2; // 将12位原始值转换为实际电流值(假设3.3V满量程,电流传感器比例系数已定) // 例如:原始值0-4095对应 -I_max �� +I_max ia = ((float)ia_raw - 2047.5) / 2047.5 * I_max; // I_max为传感器量程 ib = ((float)ib_raw - 2047.5) / 2047.5 * I_max; ic = ((float)ic_raw - 2047.5) / 2047.5 * I_max; // 执行FOC算法中的Clarke变换、Park变换等... // Clarke_Transform(ia, ib, ic, &ialpha, &ibeta); // Park_Transform(ialpha, ibeta, theta, &id, &iq); // ... 后续控制计算 // 清除ADCINT1标志位,并重新使能中断(因为之前配置为单次模式) AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // 重新使能 // 如果需要,清除PIE中断标志 PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; }5.4 上电、校准与启动序列
在main函数初始化中,必须遵循正确的ADC上电序列。
void InitADC(void) { // 1. 使能时钟 (见5.1节) // 2. 延时等待稳定 DELAY_US(50); EALLOW; // 3. 释放ADC复位 (如果之前被复位) AdcaRegs.ADCCTL1.bit.RESET = 0; // 4. 给ADC模拟电路上电 AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // 5. 延时,等待模拟部分稳定(数据手册要求,通常>1ms) EDIS; DELAY_US(1000); // 等待1ms EALLOW; // 6. 启动ADC基准源(如果使用内部基准) AdcaRegs.ADCCTL1.bit.ADCBGPWD = 1; // 使能带隙基准 AdcaRegs.ADCCTL1.bit.ADCREFPWD = 1; // 使能参考缓冲器 // 7. 延时,等待基准稳定(数据手册要求,通常>5ms) EDIS; DELAY_US(5000); // 等待5ms EALLOW; // 8. 执行ADC自校准(如果器件支持且需要) // 注意:不是所有C2000型号的Type 3 ADC都有片上校准功能,请查阅具体参考指南。 // 如果有,通常是通过写特定的校准寄存器或执行校准序列。 // 例如:AdcaRegs.ADCCTL1.bit.ADCENABLE = 1; // 使能ADC数字部分 // 然后执行校准流程... // 这里省略具体校准代码,请参考器件手册。 // 9. 配置SOC、触发、中断等(见5.2节) EDIS; // 10. 最后,使能ADC数字部分,准备接收触发 EALLOW; AdcaRegs.ADCCTL1.bit.ADCENABLE = 1; EDIS; // 11. 配置并启动ePWM和定时器触发源 ConfigureEPWMForADCTrigger(); // ... 配置CPU Timer0 }6. 常见问题排查与调试技巧
即使按照手册配置,ADC仍然可能出问题。以下是一些常见坑点和排查方法。
问题1:ADC完全没有转换,结果寄存器一直是0或固定值。
- 检查清单:
- 时钟与电源:确认
PCLKCR0.ADCENCLK已使能;确认ADCCTL1.ADCPWDNZ、ADCBGPWD、ADCREFPWD已置1,并留足了稳定时间(毫秒级)。 - ADC使能:确认
ADCCTL1.ADCENABLE已置1。 - 触发源:确认ePWM或定时器已正确配置并运行,用示波器测量对应的SOCA输出信号(如果引脚复用)或查看相关寄存器标志位。
- SOC配置:双击检查
ADCSOCxCTL寄存器的值,确保TRIGSEL、CHSEL、ACQPS设置正确。特别是TRIGSEL,一个数字写错就会指向错误的触发源。 - 结果寄存器地址:确保你读取的是正确的结果寄存器组(
AdcaResultRegsfor ADC-A)。C2000多ADC模块时容易混淆。
- 时钟与电源:确认
问题2:ADC转换结果波动大,噪声高。
- 检查清单:
- ACQPS太小:这是最常见原因。用示波器测量ADC输入引脚在采样时刻的波形。如果信号在采样窗口内有明显跳动或未稳定,就需要增大ACQPS。参考第4节重新计算。
- 电源噪声:确保模拟电源
VDDA和数字电源VDD干净,且地平面连接良好。在VDDA和VSSA之间靠近芯片引脚处放置一个10uF钽电容并联一个100nF陶瓷电容。 - 参考电压噪声:如果使用内部参考,确保
VREFHI/LO引脚(如果引出)有足够的去耦电容。如果使用外部参考,选择低噪声的基准源。 - 信号源阻抗过高:如前所述,高阻抗信号需要更长的ACQPS或前端缓冲。测量信号源在采样频率下的输出阻抗。
- PCB布局问题:模拟信号走线应远离数字信号线、时钟线和大电流路径。使用地平面屏蔽。
问题3:同步采样时,两路结果出现固定的偏移或比例误差。
- 检查清单:
- 通道匹配误差:ADC内部的A、B两个采样保持电路存在固有的偏移和增益误差。对于要求极高的应用,需要进行校准。可以在A、B通道输入相同的已知直流电压(如1.65V),分别读取结果,计算各自的偏移和增益校正系数,在软件中补偿。
- 采样窗口同步性:理论上硬件是同时采样的,但确保SOC配置正确(
SIMULENx已使能),且由同一个触发源触发。 - 外部电路不对称:检查连接到A、B通道对的外部电路(如电流采样电阻、运放、RC滤波)的元件参数是否一致。微小的电阻、电容差异会导致不同的建立时间。
问题4:高优先级SOC打断了关键的轮询采样序列。
- 现象:后台监控的ADC采样(如温度)偶尔会丢失数据,或者实时控制环路出现偶发性波动。
- 分析:如果高优先级的SOC(如用于保护的过流检测)触发频繁,它会不断打断轮询队列,导致低优先级的SOC(如温度采样)迟迟得不到执行。
- 解决:重新评估优先级分配。并非所有实时性要求高的SOC都需要设为高优先级。只有那些必须立即响应、否则会导致系统故障的触发(如紧急保护)才设为高优先级。对于周期性的控制采样(如电流),如果其触发周期固定且间隔足够处理完,使用轮询模式可能更稳定。或者,可以考虑使用两个独立的ADC模块(如果芯片支持)来隔离关键任务和非关键任务。
调试技巧:使用寄存器实时监控
在调试时,充分利用CCS的寄存器查看窗口:
ADCSOCFLG1寄存器:查看哪些SOC的标志位被置起(等待转换或正在转换)。ADCSOCPRIORITYCTL寄存器:查看当前的轮询指针(RRPOINTER)值,理解调度顺序。ADCINTOVF寄存器:如果ADC中断过于频繁而来不及处理,这里会有溢出标志。ADCCTL1寄存器:检查ADC使能、复位、电源状态位。
通过将这些寄存器窗口常开,结合断点和变量观察,可以清晰地看到ADC内部的状态流转,是排查复杂配置问题的利器。