ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

S32K PDB触发ADC指南:原理、寄存器配置与避坑

S32K PDB触发ADC指南:原理、寄存器配置与避坑 做电机控制或者数字电源的工程师基本都绕不开一个场景PWM已经调到想要的频率和占空比但ADC采样时刻定在哪儿心里始终没底。软触发靠中断里抢时间硬触发又不清楚S32K的PDB到底怎么配。其实S32K系列里这个PDB全称Programmable Delay Block就是专门干这个的你把触发事件丢给它它延迟一段时间后精准拉起ADC硬件触发。整条链路里CPU完全不参与延迟精度由硬件计数器保证抖动比软件中断小一个量级。这篇文章我会把S32K系列PDB的内部框图拆开来讲从计数器核心讲到预触发延迟链再一路讲到PDB如何触发ADC最后给出一套寄存器级配置流程和我在实测中踩过的几个坑。无论你是在做电机控制、车载充电机、DC-DC数字电源还是任何一个要求“采样时刻和PWM边沿严格对齐”的项目这篇内容应该都能省你几个晚上。1. 为什么非要用PDB触发ADC软件定时解决不了的痛点1.1 采样时刻错了控制算法再花哨也白搭很多人调试电机控制时遇到过这种现象电流环PI参数调得没问题PWM频率也正常但电机运行起来噪音大、电流波形毛刺多。用示波器一看ADC采样值在某个特定占空比下跳动特别明显。问题往往不在算法而在采样时刻。开关器件在PWM边沿切换瞬间母线电压和相电流会出现高频振铃这个振铃会持续几百纳秒到几微秒。如果ADC正好在这个窗口里转换结果就会叠加很大的噪声。更关键的是你采集到的电流代表的是“开关边沿瞬间”的电流而不是电流环控制真正需要的“平均电流”或“中点电流”。PDB的价值就在这里它接收FTM等定时器的事件边沿然后通过硬件延迟链把ADC触发信号精确移动到开关噪声消散后的位置比如PWM周期的中点。这样一来ADC转换时刻和PWM事件之间就有了一个确定的相位关系采集到的值稳定、可复现控制算法的性能才能真正发挥出来。1.2 用定时器中断加软件延时为什么就是不行有朋友会问我不用PDB直接在FTM溢出中断里加个软件延时再启动ADC不行吗可以但效果完全不同。中断响应的延迟本身就不确定。在Cortex-M内核上从中断请求到ISR第一条指令执行中间有压栈、取向量、流水线冲刷这些环节延迟通常几个微秒。如果系统里还挂着别的中断、DMA请求、甚至总线仲裁这个延迟会进一步抖动。即使你的ISR只做一件事延时后开始ADC转换抖动也轻松超过1到2微秒。对20kHz的开关频率来说一个周期的总时间是50微秒。1微秒的抖动已经占了采样相位的百分之二反映到电流环上就是明显的噪声和调制。而且ISR里的空转延时还会增加CPU负荷。PDB之所以强是因为它把“延迟”这件事从软件挪到了硬件一个计数器在时钟沿驱动下运行延迟精度只取决于时钟源没有中断响应没有压栈开销也没有优先级抢占问题。理解了这一点你就明白为什么要专门学PDB了。1.3 PDB在S32K里的定位不只是“ADC触发器”再补充一点容易忽略的PDB的输出不只能触发ADC。在S32K上PDB同样可以触发DAC事件、产生脉冲输出Pulse-Out以及在DMA场景里做定时事件源。很多波形发生器、语音提示音、传感器激励信号都借助PDB完成精确时序。当然在电机控制应用里PDB最核心的使用方式还是触发ADC预触发组。后文所有内容都围绕这条主线展开。2. S32K PDB框图逐块拆解计数器、分频器与预触发延迟链PDB框图看起来不算复杂但里面的模块之间是有层次关系的。用一张简化的信号流图表示整个PDB大致是这样工作的外部触发源(FTM溢出、定时器通道等) │ ▼ 触发选择/预分频器(MULTPRSC) ──► 16位计数器 ──► MOD匹配 ──► PDB触发输出 │ ┌─────────┼─────────┐ ▼ ▼ ▼ 预触发0 预触发1 IDLY匹配 (DLY0) (DLY1) │ │ │ ▼ ▼ ▼ PDB中断 ADC预触发A ADC预触发B从图上可以看出PDB的“触发”不是一条线走到底而是先有一个核心计数器再分支出多个预触发通道。每个预触发通道都有自己的延迟寄存器所以你可以在同一个PDB周期里精确控制多个ADC转换的时间点。2.1 计数器核心PRSC预分频、MULT倍频和MOD模数PDB内部核心是一个16位向上计数器。计数时钟不是直接来自总线时钟而是经过两级调整预分频器PRSC和倍频器MULT。PRSC字段选择的是分频系数常见可选1、2、4、8、16、32、64、128。MULT字段在S32K上可选的倍率通常是×1、×10、×20、×40。两者串在一起后实际PDB时钟频率就是f_PDB f_BUS / PRSC分频数 / MULT倍率打个比方总线时钟40MHzPRSC选/4MULT选×1那么f_PDB就是10MHz每个计数tick是100ns。如果你需要更高的时间分辨率可以把PRSC调小如果需要更长的最大周期就把分频数调大。MOD寄存器决定了计数器数到哪里产生触发事件。16位上限是65535如果PDB时钟10MHz每tick 100ns那么最大触发间隔约6.55ms约合152Hz。如果你的PWM频率低于150Hz就需要降低f_PDB。对大多数电机控制和电源应用来说这个范围完全够用。这里要先记一个关键结论MOD DLY不是简单的加法关系MOD是周期基准DLY是相对某个触发参考点的偏移两者各管各的。后面配置实例里我会再展开。2.2 预触发通道DLY0和DLY1到底在延迟什么PDB的每个通道以通道0为例有两个预触发输出对应寄存器CHnC1和延迟寄存器CHnDLY0、CHnDLY1。预触发指的是在PDB计数器的某个参考点到来后再经过DLY个tick输出一个脉冲信号给ADC。这个参考点在软件触发和硬件触发模式下还不一样很多人在这里被绕晕。软件触发/自由运行模式PDB使能后计数器从0开始跑数到MOD时产生触发事件预触发输出从MOD匹配时刻开始延迟DLY个tick。硬件触发/重装载模式外部触发沿比如FTM溢出先把计数器清零计数器重新向上跑预触发输出从外部触发沿开始延迟DLY个tick。这两种模式的参考点不同DLY的实际意义也不同。用硬件触发模式做电机控制时你通常希望“FTM边沿到来后延迟多少微秒采样”那DLY的值就是延迟时间除以tick周期。CHnC1寄存器里还有几个重要的开关位EN使能该通道TOS选择预触发输出逻辑PExEN控制脉冲输出BBEN控制背靠背模式。BBEN是重头戏单独放在2.4节讲。2.3 IDLY中断延迟只在需要CPU介入时用寄存器IDLYInterrupt Delay控制PDB中断标志的产生时刻。你可以理解为在MOD事件之后再延迟IDLY个tickPDB就拉高中断标志触发PDB中断。实际项目里IDLY的典型用法是用一个中断在采样点稍前一点唤醒CPU让CPU做好数据读取准备或者去做一些不紧急的辅助工作。比如你打算在20kHz周期中点采样电流那可以把IDLY设为比DLY提前5到10个tickCPU在中断里准备好标志位等DMA把ADC结果搬走。需要说明的是IDLY匹配和预触发输出是两条并行路径IDLY不控制ADC触发只控制PDB中断。2.4 背靠背模式BBEN一条硬件触发连做两次转换背靠背模式是我觉得PDB最精巧的功能之一。正常情况下一次外部触发沿到来后PDB计数器被清零经过DLY0产生第一个预触发ADC开始第一次转换。转换完成后ADC的转换完成信号会回传给PDBPDB在第一个预触发的基础上自动产生第二个预触发从而启动第二次ADC转换。整个过程不需要新的外部触发事件硬件上自动衔接所以叫“背靠背”。这在需要“同一PWM周期内先后采样两个不同信号”的场景里特别好用。例如同时采相电流和母线电压或者做三相电流重构时紧挨着采两路电流能最大化保持信号一致性。配置背靠背模式时需要同时使能通道的BBEN位并且把第二个预触发的DLY1也配置好。第二个ADC转换的具体时间通常取决于ADC转换时间所以DLY1可以设得比较短让第二次转换紧跟第一次。3. PDB触发ADC的信号链路与三种典型配置光看框图还不够要把PDB、ADC、FTM三者串成完整链路你还需要知道信号是怎么从一个模块走到另一个模块的。3.1 从FTM到PDB再到ADC的完整信号通路标准接线是FTM产生PWM波形同时把溢出事件或通道事件输出到PDB的触发输入。PDB根据配置对输入事件进行处理经过预设延迟后输出预触发信号到ADC模块。ADC在硬件触发模式下收到预触发信号后自动启动一次转换不需要CPU介入。ADC转换完成后可以通过DMA把结果搬到内存也可以在背靠背模式里把完成信号回传给PDB。从S32K参考手册里你会看到PDB的触发源选择是通过TRGSEL字段配置的可选源包括FTM0溢出、FTM1通道事件、LPTMR、RTC等。具体编号每个型号略有差异用的时候要对着对应型号的参考手册看触发源映射表。我早期犯过一个错直接拿S32K144的TRGSEL映射表去套S32K312结果采样点完全不对排查了半天才发现是触发源编号对不上。3.2 模式一软件触发/单次模式适合调试和自检软件触发模式下PDB的计数器从写入PDB寄存器后由内部逻辑自行启动不需要外部事件。你只需要把PDB_SC里的SWTRIG位置1PDB计数器就会清零并从0开始跑。这种模式最大的优点是调试方便。ADC通道有没有接对DLY延迟够不够采样点是否落在预期位置都可以先用软件触发验证。我建议任何PDB新项目第一步都先把链路跑在软件触发模式用示波器确认ADC触发信号的位置再切换到硬件触发模式接上PWM。软件触发模式的缺点是所有转换起点都由软件决定无法和外部PWM边沿自动对齐所以它只适合调试和低频应用。3.3 模式二硬件外部触发加连续模式主流电机控制方案真正做电机控制时用的是硬件触发模式。以最常见的配置为例FTM处于中心对齐UP_DOWN模式产生PWM。FTM溢出事件连接到PDB触发输入。外部触发沿将PDB计数器清零。DLY0决定从PWM边沿到ADC采样点的延迟。MOD决定整个PDB周期通常和PWM周期对齐。连续模式CONT置位后PDB计数器在达到MOD后自动重新计数下个触发沿到来前保持运行。这样每个PWM周期里ADC都在同一个相对位置被触发采样点与PWM载波严格同步。有些工程师会问中心对齐模式下中点采样应该是在FTM计数达到MOD值时而不是溢出时。这个说法不完全对因为FTM溢出有两种一种是计数器从MOD回0时产生的下溢/溢出事件另一种是计数器到MOD时的匹配事件。你完全可以让FTM在计数到MID时输出一个通道事件把它作为PDB的触发源这样DLY延迟只需微调就能把ADC采样精确放在周期中点。3.4 模式三背靠背模式接两个ADC通道刚才提到背靠背模式可以用来连续做两次转换。实际配置时你需要把PDB通道的BBEN位置1。把DLY0设为第一个预触发延迟。把DLY1设为第二个预触发延迟。确保ADC模块已配置为硬件触发硬件触发模式下能同时响应预触发A和预触发B。第一次转换由预触发0拉起第二次转换由ADC的转换完成信号触发不需要额外输入事件。如果你要做“在同一PWM周期内先采样电流再采样电压”背靠背模式基本最优。3.5 时序计算示例把上面的模式落到数字上这里给一个具体计算。假设总线时钟40MHzPRSC选/4MULT选×1PDB时钟10MHztick周期100ns。PWM频率20kHz周期50us所需PDB周期也是50us。50us / 100ns 500个tick所以MOD设为499以“计数到MOD即触发”的型号为例有些型号是MOD1务必对照参考手册。想要在FTM溢出后延迟25us处采样即周期中点DLY0 250us / 100ns 250。这样PDB触发ADC的时刻就在PWM周期中点。如果发现采样点需要前移或后移只需调整DLY0单位精度就是100ns方便定位。4. 寄存器级配置实战一个“边沿触发中点采样”的例子下面直接给一个S32K1系列以S32K144为代表的寄存器级配置过程。S32K3系列底层外设相似但RTD驱动封装不同我会在后续提到差异点。4.1 配置目标假设你的系统里FTM0输出中心对齐PWM频率20kHzFFM溢出事件作为PDB的外部触发源。现在希望在每个PWM周期的中点触发ADC采集相电流。总线上40MHzPDB时钟选择10MHz。目标参数PDB输入触发源FTM0溢出事件。PDB时钟10MHz分频4。MOD499PDB触发周期50us。DLY0250FTM溢出后25us采样。ADC0配置为硬件触发模式接到PDB预触发0。4.2 模块时钟使能与复位顺序先使能PDB和ADC模块时钟这一步容易被忽略。在S32K1上模块时钟由PCCPeripheral Clock Controller控制/* 使能PDB0时钟 */ PCC-PCCn[PCC_PDB0_INDEX] | PCC_PCCn_CGC_MASK; /* 使能ADC0时钟 */ PCC-PCCn[PCC_ADC0_INDEX] | PCC_PCCn_CGC_MASK;接着把PDB关掉再配置避免运行时写入寄存器导致不确定行为PDB0-SC 0x0u; /* 先关PDB */4.3 配置PDB计数器、通道延迟并加载设置预分频器、倍频器和模数寄存器/* PRSC01对应分频4MULT00对应×1同时使能PDB */ PDB0-SC PDB_SC_PRESC(1u) | PDB_SC_MULT(0u) | PDB_SC_PDBEN_MASK; /* 周期50us对应500 tickMOD499 */ PDB0-MOD 499u;配置通道0即预触发0使能通道、选择输出、设定延迟250 tickPDB0-CH[0].C1 PDB_C1_EN_MASK | PDB_C1_TOS_MASK; PDB0-CH[0].DLY[0] 250u; /* 25us */如果你需要背靠背模式可以再把PDB_C1_BBEN_MASK加进去同时配置DLY[1]为第二个延迟PDB0-CH[0].C1 | PDB_C1_BBEN_MASK; PDB0-CH[0].DLY[1] 260u; /* 第二个预触发延迟26us */寄存器的值不是写入即生效的。S32K PDB里有一道“加载闸门”LDOK。写完MOD、DLY、IDLY这些寄存器后必须把LDOK位置1硬件才会把缓冲寄存器里的值一次性装入真正参与比较的寄存器。这样设计的目的是保证多个参数在同一个时刻原子更新避免配置到一半时计数器用了新MOD却用了旧DLY。PDB0-SC | PDB_SC_LDOK_MASK; /* 装载所有缓冲值 */如果是软件触发调试再置SWTRIGPDB0-SC | PDB_SC_SWTRIG_MASK;如果要用外部FTM触发就要设置触发源选择TRGSEL并确保连续模式CONT按需开启。典型写法是在初始化时把这两个位一并设好。4.4 配置ADC硬件触发ADC侧也需要两步配置。先把ADC触发模式从软件改为硬件ADC0-SC2 | ADC_SC2_ADTRG_MASK; /* 1硬件触发 */然后选择一个ADC通道比如ADC0_SEDC通道12具体通道号看硬件连接ADC0-SC1[0] 12u; /* 选择通道12 */在硬件触发模式下写SC1只是选择通道不会立刻启动转换真正的启动信号来自PDB预触发。这一点和软件触发写的区别很大调试时容易误以为程序卡死。4.5 用示波器验证触发链路配置代码写完先用软件触发模式把链路跑通用示波器量ADC的触发引脚或者PDB输出引脚确认每50us出现一个脉冲而且脉冲位置在FTM溢出后25us。确认后再切成硬件触发模式接上PWM。如果采样点不对优先怀疑触发源编号和DLY换算而不是ADC配置。5. 实测踩过的坑LDOK加载、背靠背失效与跨型号差异5.1 寄存器写错顺序LDOK背着锅我调试PDB时遇到过一个很隐蔽的问题代码里更新了MOD和DLY把LDOK也写了但实际计数周期还是旧的改动完全不生效。后来才意识到LDOK被拉高之后需要手动拉低或者在某些芯片版本里LDOK会在装载结束后自动清掉。如果上一次置位没有清除下一次配置时LDOK仍然处于拉高状态硬件可能直接忽略新的装载请求。保险做法是每次配置前先把LDOK位清零再写参数最后写LDOK1PDB0-SC ~PDB_SC_LDOK_MASK; /* 写MOD、DLY、IDLY */ PDB0-SC | PDB_SC_LDOK_MASK;如果你用了MCU的PDB驱动函数驱动内部一般会处理这个顺序但寄存器级编程时很容易忽略。5.2 TRGSEL触发源编号跨型号必须查手册另一个坑是触发源编号。S32K144和S32K312的PDB触发源映射表并不完全一致FTM0溢出事件在某个型号里可能对应TRGSEL4在另一个型号里对应TRGSEL6。直接套用老工程的配置结果就是PDB永远等不到有效触发ADC也永远不启动。排查这类问题的方法是用软件触发模式确认PDB和ADC本身没问题然后把TRGSEL逐一枚举观测ADC触发信号在哪一档开始出现。虽然多做几次实验但能快速锁定映射关系。5.3 S32K3系列RTD的PDB配置变化S32K3系列用RTD驱动后PDB的配置方式和S32K1的SDK有明显出入。S32K3上PDB可能按Pdb_Ip这类方式组织初始化结构体而且时钟树和总线频率分布不同。S32K3的Core频率高到160MHz甚至320MHz但PDB时钟不一定和Core时钟同频配置前要确认你的PDB实际时钟源到底是多少。我见过一个同事在S32K344上想当然认为PDB时钟是160MHz算出MOD值后所有延迟都缩水了一半。最后他就是通过先软件触发、用示波器量PDB输出脉冲的实际周期反推出真实PDB时钟才把问题解决。5.4 背靠背模式下第二个ADC不转换背靠背模式看起来简单但实际配置时有个细节第二个预触发依赖ADC转换完成信号如果你的ADC配置成了“软件触发模式”ADC转换完成后并不会回传完成信号给PDB背靠背的第二个预触发永远等不到。所以使用背靠背模式前务必确认ADC已经设置为硬件触发模式ADTRG1。ADC中断或者完成标志能够正常产生说明完成信号链路是通的。PDB通道的BBEN已经置位并且DLY1有合理值。如果第二个转换始终不出现按这个顺序排查基本能定位。5.5 用示波器确认触发点而不是靠猜最后给个实操建议PDB配置完成后用示波器同时量FTM输出、PDB输出如果引出了Pulse-Out引脚或者触发引脚和ADC采样结果三路对齐看。直接观察触发脉冲相对PWM边沿的位置比反复调算法参数高效得多。我自己做电机控制项目时习惯在PDB输出脚挂一个空闲引脚在调试阶段输出脉冲用示波器确认延迟时间对不对。等全部整定好了再把引脚释放掉。这样排查“电流波形异常”和“PDB配置错误”之间的因果关系效率很高。这套方法我从S32K144一直用到S32K3系列只要PDB和ADC链路配置正确采样波形稳定性和控制环路的收敛速度都会有很直观的提升。
返回列表