尧图精选

STM32 SAI接口巧接AD7768:实现高速多通道ADC同步采集

🕒 发布时间:2026/10/2 3:21:48 📁 来源:尧图网络
把STM32的SAI接口拿去做高速ADC采集估计不少人一听就觉得不靠谱——这不是音频接口吗但当你手里正好有一颗AD7768、前面又需要连续同步采样多个通道时SAI的TDM模式其实能当半个SPI用。这篇文章就把我实际调试的方案、SAI和AD7768的配合技巧以及后来PCB布局踩过的坑一起写出来给打算走这条非常规路线的朋友做个参考。AD7768是ADI家一颗24位高速同步采样ADC8通道版本常用于电力录波、振动监测、声学阵列这些对“同步性”要求极高的场景。它自带Σ-Δ调制器单通道采样率能跑到256kSPS多通道之间则靠内部数字滤波器和同步时钟保证相位关系。这类芯片传统接法是挂在SPI或者并行总线上SPI接线简单但读取压力大并行接口速度快但占引脚。而STM32的SAI接口如果你只把它当音频外设就太亏了——它本质上是一条可配置性极强的同步串口支持TDM时隙、帧同步、DMA和FIFO用来接收ADC的连续数据流其实非常合适。1. 为什么放着SPI不用偏要折腾SAI接ADC1.1 SAI接口的真实身份SAI全称是Serial Audio Interface属于STM32的音频专用外设但它的底层架构就是一个带帧同步的移位寄存器。它支持I2S、左对齐、右对齐、DSP/PCM以及TDM多时隙模式每个数据帧里可以塞多个通道的数据并且有独立的位时钟SCK、帧同步信号FS和数据线SD。这套机制跟很多高精度ADC的串行输出天然对得上因为ADC这边也是“一个帧同步 一串连续数据位”二者只是叫法不同。你可以把SAI理解成一台“多声道打包机”原本是给音频左右声道分流用的打开TDM模式后就可以把8个通道、16个通道的数据按时隙一帧一帧搬出来。AD7768输出的8路数据长什么样一个转换周期结束后8个通道的结果按固定顺序在数据线上依次移出下一次转换周期再由同步信号标记帧头。这跟音频中的多声道I2S数据流几乎是同构的所以SAI能接并不是巧合而是协议层面的契合。1.2 AD7768值得用SAI接的三个理由第一多通道连续数据流。AD7768只要启动转换就会持续不断地输出8个通道的采样结果。如果只靠普通SPI去读你得不停拉CS、发读命令、收数据时间紧张容易丢帧。SAI没有“命令”概念启动DMA后就是被动或主动地按帧接收数据一口一口吐特别适合这种流式场景。第二DMA配合起来非常舒服。STM32的SAI外设带了自己的FIFO支持DMA突发传输。CPU只需要在DMA半满、全满中断里做搬运或者处理完全不用管每一位的时序。对于ADC采集来说降低CPU占用就意味着你还有余力跑算法或者维持其他实时任务。第三时钟资源上的“白嫖”优势。SAI的时钟源挂在PLLI2S或音频PLL上可以生成49.152MHz、24.576MHz这类音频标准频率。这些频率不仅是音频采样时钟的整数倍也能匹配很多Σ-Δ ADC要求的MCLK范围而且音频级晶振本身抖动做得比较好。等于你用一组音频时钟体系顺手把高速ADC的采样时钟问题也解决了。1.3 最容易被忽略的坑SAI帧长上限这个坑我踩过之后才明白网上很多文章都在吹“SAI可以接ADC”但很少有人提帧长限制。STM32很多系列的SAI一个数据帧的位长度Frame Length上限是128bit这是参考手册里FRL字段决定的。AD7768在24位字长、8通道全开的情况下一个转换周期要输出8×24192bit直接超过SAI一帧的容量所以不能想当然地把所有通道塞进一个SAI帧里。实际可行的做法有三个把AD7768配成4通道输出每通道24bit4×2496bitSAI一帧轻松装下这是我最推荐的方式。把AD7768输出字长改成16bit8×16128bit刚好卡在SAI上限适合对分辨率要求不太苛刻但通道数必须拉满的场景。如果你的应用必须8通道24bit全精度那就别硬用SAI了老实换并行接口方案或者用两片4通道ADC交叉采集。我在这篇文章里演示的配置是4通道24bit模式既保留了AD7768的完整动态范围又能保证SAI的帧结构完全匹配。2. 连接方案选型谁当主机谁当从机2.1 我先说结论推荐AD7768当主机SAI当从机SAI和AD7768之间有两种主从接法别一上来就选错。很多人习惯性想让STM32当主机用SAI产生SCK和FS去“读”ADC但AD7768的高速数据流不是SPI那种一问一答的机制你主动给时钟时必须把帧起始信号对齐到ADC内部转换完成瞬间这个对齐在高速率下非常折磨人稍微有一点延迟就会导致帧头错位数据通道路由混乱。我实际调试选的是AD7768做串行主机SAI做从机接收。AD7768在Master模式下自己产生SCLK和帧同步信号SYNC_OUT数据沿由ADC内部时序控制天然跟转换结果对齐。STM32这边只需要把SAI配置成从机接收模式外部给什么时钟就用什么时钟外部给什么帧同步就按什么帧对齐省去了边沿反复调试的麻烦。两种主从模式的取舍我整理成了一张表方便你对号入座对比项SAI主机 AD7768从机AD7768主机 SAI从机推荐时钟来源STM32音频PLL产生SCLKAD7768由MCLK分频产生SCLK帧同步来源STM32产生FSAD7768产生SYNC_OUT帧对齐难度需要手动对齐ADC转换完成时刻天然对齐无需干预多板同步能力强可统一外部时钟较弱需要额外的同步机制调试复杂程度高低2.2 引脚映射与电平转换引脚映射比较简单主要就是三根线加地。我这里以STM32的SAI_A子块为例SAI_A_SDPA4这类引脚接到AD7768的SDO数据输出方向是ADC到MCU。SAI_A_SCKPA2这类引脚接到AD7768的SCLK这时候SCLK由ADC产生作为SAI的位时钟输入。SAI_A_FSPA3这类引脚接到AD7768的SYNC_OUT作为SAI的帧同步输入。另外把AD7768的DRDY接到STM32的一个普通GPIO或者EXTI引脚上方便在DMA启动时做软同步后面排查问题也会用到。电平匹配这块要单独说。AD7768的数字IO供电IOVDD决定了它输出高电平的门限如果你的MCU是3.3V供电AD7768的IOVDD也配成3.3V那就可以直连。如果因为低功耗或其他原因把IOVDD设成了1.8V那SDO的1.8V输出进STM32的3.3V IO风险不小中间串一个电平转换芯片或者至少加一个电阻分压网络不要图省事。2.3 供电与复位时序AD7768的电源引脚分得比较细模拟供电AVDD1、AVDD2数字供电DVDDIO供电IOVDD。我第一次画板子时把所有电源都扔给了一颗DC-DC结果底噪直接爆表后来改成模拟电源用LDO单独供电数字和模拟之间用磁珠做单点连接情况立刻好了。高速ADC对电源噪声非常敏感电源没做好后面软件再怎么调都救不回来。复位时序也要注意。AD7768上电后需要等电源稳定再给RESET引脚一个低脉冲之后等待至少几十个MCLK周期让内部振荡器稳定然后才能通过SPI写入配置寄存器。如果上电后就急着写配置寄存器可能写入失败而且这种故障是偶发的非常难排查。我现在的做法是在初始化函数里加固定延时写完配置后再回读一次确认寄存器内容无误才继续启动转换。3. SAI接收AD7768数据的实操配置3.1 AD7768初始化顺序AD7768的控制接口仍然是SPI跟数据输出接口不是一套所以初始化时SPI是必不可少的。配置顺序建议按这个流程来复位AD7768等待稳定。写MCLK分频寄存器确定输出数据速率ODR。这个分频值要根据你实际的MCLK频率和目标采样率来计算手册里有现成的表格直接查。配置数据输出格式选择串行主机模式使能SYNC_OUT输出。设置字长和通道使能。如果做4通道模式要明确是只用前4个输入通道还是任意4个然后关闭其余通道。配置SPI读数据时是否需要在每个通道之间插入无效位这一步要跟SAI的时隙设置统一起来。我用伪代码大致写一下void AD7768_Init(void) { AD7768_Reset(); // 拉低RESET再释放 delay_ms(10); // 等待内部稳定 AD7768_WriteRegister(REG_DEVICE_CONFIG, 0x04); // 使能SPI配置 AD7768_WriteRegister(REG_ADC_CONFIG, 0x10); // 设置菊花链/TDM模式 AD7768_WriteRegister(REG_DIN_CONFIG, 0x00); // 4通道24bit字长 AD7768_WriteRegister(REG_SPI_CTRL, 0x04); // Master模式SYNC_OUT使能 AD7768_WriteRegister(REG_DATA_CTRL, 0x08); // 启动连续转换 }这只是示意不同批次的AD7768寄存器地址和位定义可能有差异建议打开最新版数据手册对照。我踩过的坑是写完寄存器后没有回读验证结果某个位没写成功采集数据一直是乱的白白花了一天时间。3.2 CubeMX里SAI的关键参数用STM32CubeMX配置SAI时参数比较多我一个个说哪些是关键项。首先生成项目时选SAI_A模式选“Slave Receiver”也就是从机接收。同步方式选“External”表示SCK和FS都由外部输入。然后在Parameter Settings里做如下配置Audio ModeSlave ReceiverProtocolTDMFrame Length96这是4通道×24bit的结果如果选用8×16bit就填128Active Frame Length1代表FS高电平持续一个SCK周期Frame Sync Polarity根据AD7768的SYNC_OUT极性来定一般配Active HighData Size24Slot Number4Slot Size24Clock Strobing先选Rising Edge如果最后发现采样数据全是乱的再改成Falling Edge试DMA添加SAI_A_RX模式选Circular数据宽度按32位这里有个细节Slot Size设置成24bit时SAI会按24位为一个时隙去切分数据。但如果你的AD7768在TDM输出时每个通道之间还有额外的填充位就需要把Slot Size设成32bitData Size仍保持24bit这样多余的空闲位会被忽略。两种方式我都测过区别主要在DMA缓冲里的数据对齐方式。3.3 DMA双缓冲与中断处理代码配置完SAI后启动DMA接收的代码大致如下#define FRAME_COUNT 256 static uint32_t rx_buf[2][FRAME_COUNT * 4]; // 双缓冲每帧4个通道 HAL_SAI_Receive_DMA(hsai_BlockA, (uint8_t *)rx_buf, FRAME_COUNT * 4 * 2);注意DMA传输长度要跟缓冲大小严格对应。SAI每次接收一个32位字内部可能包含24位有效数据DMA在Circular模式下会自动循环填充半满和全满中断交替触发。对应的回调函数里不要做复杂运算只设置标志位然后在主循环里处理数据volatile uint8_t dma_flag 0; void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) { if (hsai-Instance SAI1_Block_A) { dma_flag 1; // 前半段缓冲就绪 } } void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) { if (hsai-Instance SAI1_Block_A) { dma_flag 2; // 后半段缓冲就绪 } }主循环里根据标志位去解析rx_buf[0]或rx_buf[1]。双缓冲的意义在于DMA还在往另一边写数据的时候CPU就可以处理当前这一半形成流水线不会丢数据。3.4 数据解析与校准从DMA缓冲里拿出来的原始数据通常是SAI按接收寄存器原始格式排布的需要做符号扩展和通道提取。AD7768输出的是24位有符号数如果SAI的Data Size设成24DMA里的每个元素可能是左对齐或右对齐处理方式不一样。我习惯把SAI的Slot Size设成32位Data Size设成24位接收到的数据在32位容器里靠左对齐也就是有效24位占bit[31:8]低8位是填充位。解析时先右移8位再做24位符号扩展int32_t ad7768_to_signed(uint32_t raw) { return ((int32_t)(raw 8)) 8; }这样拿到的是完整24位有符号数满量程范围是-8388608到8388607。如果发现所有数据都落在一个很小的区间内先别怀疑传感器大概率是符号扩展写错了高字节被当成0处理。校准我建议做“零点漂移”和“增益”两步。零点漂移就是把ADC输入端短接到GND或者共模电压采集一段时间取平均值作为偏移量记录下来。增益校准则是输入一个已知标准电压算出实际码值跟理想码值的比值后续每个点都按这个比例修正。对于AD7768这种高分辨率ADC不做校准直接看原始数据会感觉底噪特别大其实一部分是静态误差。4. PCB布局指南数字接口可以骚模拟通路不能飘4.1 层叠与地平面的第一原则SAI接口本身的数字走线并不难画难的是AD7768周边的模拟电路。几十位的高速数字信号在板上狂奔如果地平面被切开回流路径一绕噪声就全进了模拟输入。层叠设计上四层板建议这样安排顶层放置AD7768、模拟前端放大器、去耦电容SAI相关走线尽量放到外围区域不要穿过ADC正下方。第二层完整地平面这一层绝对不能分割它是所有信号的回流通道。第三层电源平面AVDD、DVDD、IOVDD各自划分区域用磁珠或0欧电阻连接注意相邻层的分割不要重叠。底层模拟输入走线和基准电压走线优先保证短而直。最核心的原则是地平面保持完整不要为了“模拟地”和“数字地”的强迫症把底层挖开一条大沟。正确的做法是分区布局而不是分割地平面。ADC的数字接口和模拟输入各占一侧所有跨区的信号线尽量集中在同一个小区域避免一整排高速线来回穿越。4.2 规避时钟抖动与电源噪声的3个PCB布局要点这部分值得单独拎出来说因为我吃过不少亏。ADC性能好不好除了芯片本身PCB布局直接决定你最后能拿到多少有效位。第一时钟线必须包地处理。AD7768的MCLK和SCLK都是高速边沿信号它们如果跟模拟输入线平行走线就会通过耦合电容把时钟边沿的抖动带进模拟通路。我的做法是MCLK、SCLK两边各留3倍线宽以上距离高优先级信号线两侧再打一圈接地过孔形成“地墙”屏蔽。时钟走线最好走内层如果必须走外层就不要过孔换层一条直线拉过去。第二电源去耦要分级布局。AD7768的AVDD1、AVDD2、DVDD、IOVDD每个电源引脚旁边都必须有0.1uF的MLCC这个电容要尽可能靠近引脚过孔到电容的回路不要绕远然后稍远一点再放1uF和10uF的大电容。小电容负责高频噪声大电容负责低频波动。模拟电源和数字电源之间用磁珠连接磁珠的作用是让高频信号不要互相串扰但不能把整个地平面隔开。第三基准电压源是被忽视的重灾区。AD7768的VREF引脚对参考电压的纯净度要求很高基准芯片到ADC的VREF引脚之间要走粗短走线两边包地负载电容要放在ADC引脚附近。基准芯片不要放在ADC旁边的大功率器件附近否则温度漂移会让基准电压缓慢变化你最终看到的采集波形会带有一个非常缓慢的“呼吸感”。4.3 晶振、MCLK与SCLK走线MCLK这颗时钟是整个ADC采样时序的心跳抖动直接影响信噪比。晶振布置原则是“尽量靠近AD7768的MCLK引脚”负载电容靠近晶振的XIN/XOUT脚晶振底下不要走任何信号线。我之前画板子时偷懒把晶振放在板子另一侧MCLK绕了大半个板子过来结果FFT底噪抬高了差不多10dB后来移动位置后恢复。这个经验非常直观时钟线长度每增加一厘米潜在的耦合风险就高一分。SCLK走线也要注意完整回流。SCLK从AD7768的SCLK引脚输出到STM32的SAI_SCK输入如果这条线跨过了电源分割槽回流电流要绕远路信号沿会变差严重时SAI采样边沿会不稳定。尽量保证SCLK与它下方的地平面平行不要换层。如果实在要换层在换层过孔旁边加一个接地过孔给回流电流一个“跳板”。4.4 AD7768模拟输入与基准部分AD7768是Σ-Δ架构ADC输入阻抗不是恒定的前端一般需要RC滤波网络来抑制高频混叠。这几个电阻电容的布局很有讲究电阻要靠近信号源方向电容要靠近ADC输入引脚电容的地必须回到ADC下方的地平面不能扯到别的地方去。差分输入的话正负输入线要做到等长、等距、紧耦合这样共模噪声才能被差分结构抑制掉。我最初画差分输入时两条线分得比较开结果工频噪声拾得很多后来改成紧耦合的一对线底噪明显下降。基准引脚的去耦电容容量可以参考手册建议我通常用2.2uF加0.1uF组合电容地也单独打到ADC下方不要跟数字电源的过孔混在一起。需要注意焊盘散热问题。AD7768这种大引脚数的ADC底部通常有大焊盘散热焊盘焊接时如果焊盘上的过孔开得太大焊锡会被吸到背面去导致虚焊。我在钢网开孔时会把过孔错开让焊锡不完全流走。这个问题看似跟采集无关但虚焊会导致特定通道的数据偶发跳变排查起来非常痛苦。5. 实测问题排查帧错位、数据毛刺、温漂5.1 通道错位或掉样最常见的现象是采集到的4个通道数据里通道1的数据跑到了通道2的位置或者偶尔跳一个点。这个问题大概率是帧同步没对齐。先拿示波器抓SAI_FS和SCLK之间的相位关系确认FS的脉冲宽度是否被SAI正确识别。如果在FS前后刚好有数据位变化SAI可能会把上一帧的最后一位当成新帧的第一个时隙需要调整SAI的Frame Sync Offset也就是FS到来之后延迟多少个SCK再开始采样有效数据。另外DRDY和SYNC_OUT如果分别接到两个引脚容易在初始化时产生一帧的时间差。我用DRDY触发外部中断在中断里启动DMA确保采集从一帧的完整边界开始。还有一个土办法在数据流里找特征值。假设通道1接入已知的稳定直流电压那么解码时只要扫描一段数据找到连续几个帧内数值相同的那个时隙就能确定通道1的真实位置然后把通道索引固定下来。5.2 高字节固定为零或符号位处理错误如果你发现采集的数据全部是正数或者最大值总是卡在0x7FFFFF附近多半是符号扩展写错了。AD7768是24位有符号数最高位是符号位如果数据在32位里是右对齐的而你把它当32位无符号数直接读就会得到一个大正数。先把填充位清零判断原始数据最高位再做符号扩展。另一个容易忽略的是AD7768本身也支持数据输出右对齐/左对齐这取决于配置寄存器里某个位。软件层我能给的检查思路是给某个通道输入一个接近满量程的负电压采集原始码值看它的十六进制是不是0x800000开头。如果是0x000000开头说明对齐方式配反了去检查SAI的Data Size / Slot Size组合以及AD7768的数据格式寄存器。5.3 电源噪声导致底噪抬高采集波形看起来“毛刺”不规律FFT之后发现整个底噪抬高不是某根单频尖峰这就是典型的电源噪声耦合而不是时钟问题。先检查模拟电源纹波用示波器看AVDD引脚如果纹波超过几毫伏就已经很大了必须换LDO或者加强滤波。再看看MCLK的边沿是否干净如果有振铃或者斜率过缓说明晶振负载电容匹配不对。我自己遇到过一次很隐蔽的情况ADC底噪时好时坏用手摸板子或者靠近机箱就变化。后来发现是ADC底下的地平面和螺丝孔没有连接好机箱地电位浮动导致回流路径不稳定。处理方式是让ADC地平面通过多点过孔连接到整个系统地同时机箱地要单点接入形成星型连接。5.4 快速排查清单症状优先检查点验证手段通道错位FS极性/Offset、DMA启动时机示波器测FS与SCLK相位特征通道法对齐数据全正/全满是上限符号扩展、数据对齐方式输入负压看原始码是否为0x800000底噪抬高电源纹波、地回流、MCLK抖动FFT频谱对比、LDO供电前后对比偶发跳变焊接虚焊、电源接触不良热风吹板子模拟温升观察跳变概率高采样率时丢帧DMA缓冲不足、中断争用提高DMA缓冲深度降低中断频率每次排查这类问题我都习惯保留一张“同一批次板卡”的对照结果。很多软硬件问题不是绝对性的而是批次性差异比如某块板子电源走线偏长导致底噪高另一块板子却正常。单独看一块板子很容易查半天多块板子一起横向对比问题定位会快很多。我现在的稳定做法是用AD7768的4通道24bit模式配SAI从机接收硬件PCB严格按照“完整地平面模拟电源LDO时钟包地基准低噪声”四个原则来画软件上靠DMA双缓冲和帧特征扫描保底。这套方案在8路以内、采样率不超过128kSPS的项目里已经跑了好几个迭代稳定性非常不错。但我也得说句实话如果你手头项目就是8通道24bit全速不妥协SAI这条路还是别硬挤并行接口或两片4通道ADC交叉会更靠谱。整件事最大的价值其实是让你重新认识SAI这个“音频外设”的边界和玩法下一次遇到类似的多通道流式数据你会有第二张牌可以打。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →