☰
STM32 SAI接口驱动AD7768实现高速多通道同步采集的实战指南
2026/10/3 3:44:15 网站建设 项目流程

STM32的SAI接口,在很多工程师印象里就是用来接音频编解码器的:I2S、TDM、PCM,无非是给麦克风、喇叭、数字功放之类的音频设备服务。说实话,我第一次在项目里把SAI拿出去驱动AD7768这种8通道24位高速ADC时,身边同事的第一反应都是“这玩意能行?”结果不仅行,而且相当稳。SAI的TDM模式、主时钟输出能力、帧同步信号产生逻辑,用来驱动需要DCLK、FS、MCLK三根时钟的Σ-Δ型ADC,简直是天生一对。

这篇文章就把我踩过的坑、算过的参数、画过的板子一次性梳理清楚。整个方案的核心思路是:STM32的SAI接口在TDM发送模式下,既能作为位时钟和帧同步的master产生采样时钟,又能输出ADC转换结果所需的DCLK和FS时序,再配合DMA将AD7768多通道转换数据搬进内存,从而实现超过普通SPI采样率上限的高速多通道同步采集。文章会覆盖SAI与AD7768的时序匹配、时钟频率计算、寄存器配置思路,以及一套实用的PCB布局指南,适合正在用STM32做多通道数据采集、振动分析、电力监测、高速同步采样的工程师参考。

1. 方案选型:为什么是SAI而不是SPI或FSMC

被问得最多的问题就是:“AD7768不是有SPI接口吗,为什么不直接用SPI?”这个问题的答案藏在AD7768的SPI模式和转换速率里。SPI模式确实是AD7768的功能之一,但那个SPI模式是为了配置寄存器、读取低速转换结果用的,一旦你要跑满256kSPS输出、8通道同时转换,SPI的SCLK就得上百兆了。而且SPI模式的数据格式是低位在前,你还需要额外处理bit序。真到了高速采集场景,AD7768更推荐使用并行接口或者专用的DCLK/FS接口模式,SAI在这里扮演的正是那个“专用的DCLK/FS产生器”的角色。

1.1 SAI接口的隐藏能力

SAI接口全称Serial Audio Interface,看起来是给音频准备的,但它的底层逻辑比I2S更通用。STM32的SAI模块支持两类独立子协议块,每个块都可以配置为发送或接收方向。重点是它支持时分复用TDM模式,帧长度、时隙数、时隙宽度、帧同步信号极性、帧同步信号长度全部可配置。这意味着你可以把它当成一个通用的串行时序发生器:只要BCLK、FS、SD信号的时序关系符合ADC的接口要求,SAI根本不管数据是音频还是ADC采样值。

还有一个容易被忽略的能力是SAI支持主时钟MCLK输出。AD7768需要一个干净的MCLK作为调制器时钟,很多人在用定时器或者PWM产生这个时钟,结果抖动大、相位噪声高,直接影响ADC的信噪比。SAI的MCLK输出直接从MCU内部PLL分频链来,抖动特性远好于GPIO翻转。实测下来,用SAI的MCLK给AD7768喂24.576MHz,比用普通定时器输出稳定得多,SNR明显上一个台阶。

1.2 和SPI、FSMC方案的真实对比

拿SPI直接驱动高速ADC,最大的瓶颈在于SPI的SCLK上限。STM32H7的SPI时钟可以跑到100MHz上下,理论上能支撑高速传输,但SPI模式是单向主从架构,ADC需要靠外部时间触发或持续转换,你没有专用的帧同步信号来对齐通道。AD7768在SPI模式下虽然也有DRDY引脚可以指示数据就绪,但用SPI做8通道持续采集时,中断频率极高,CPU占用率飙升,DMA虽然能缓解,但SPI对帧边界的控制还是弱了一些。

FSMC/并行接口方案的问题在于引脚占用:8通道24位数据就得几十根线,PCB布线压力很大,而且STM32的FSMC总线频率在多通道并行模式下对信号完整性要求极高,普通两层板很难处理。SAI把数据有效负载压缩在一条SD线上,外加BCLK、FS、MCLK三条时钟线,一共四根线就把8通道24位数据拿回来了,布线难度大幅下降,还能用DMA自动搬运,CPU几乎不参与。

2. AD7768的接口时序与SAI的匹配原理

要真正把SAI用好,先要吃透AD7768的时序要求。AD7768是一款8通道同步采样Σ-Δ型ADC,每通道可配置输出速率从32kSPS到256kSPS,分辨率24位,动态范围很高。它有一颗MCLK输入,内部根据抽取滤波器输出转换结果,再通过DCLK和FS把数据搬到外部控制器。

2.1 AD7768的三种接口模式

AD7768的接口大致分为并行、SPI、和“灵活”模式。并行模式速度最快但引脚多,SPI模式适用于低速率配置和读取,真正的灵活模式使用DCLK作为位时钟,FS作为帧同步,SD作为串行数据。这个灵活模式和SAI的TDM发送模式天然匹配。

灵活模式下,DCLK由AD7768自己输出,还是由外部控制器提供,取决于数据方向配置。实际上,要让外部控制器主动产生DCLK去读数据也是可行的。只要SAI的BCLK作为DCLK输入给AD7768,FS作为帧同步告诉ADC“现在开始输出第一通道的数据”,AD7768就会按时序把数据推到SD线上,SAI再用接收或发送回路把数据抓回来。这里最容易绕晕的地方是:SAI既能发送也能接收,AD7768的数据从哪根线进STM32,就看你配置SAI的哪个方向。

2.2 SAI作为时钟Master的工作逻辑

SAI作为Master时,它自己产生BCLK和FS。AD7768在外部控制器提供DCLK和FS的情况下,会把转换结果串行输出。所以你看到的线路连接是:

  • SAI_MCLK → AD7768的MCLK(主时钟,提供调制器采样频率)
  • SAI_BCLK → AD7768的DCLK(位时钟,驱动数据移位输出)
  • SAI_FS → AD7768的FS(帧同步,标志一个完整的转换帧开始)
  • AD7768的SD → STM32的SAI_SD(数据返回MCU)

这个连接逻辑和音频编解码器一模一样。SAI Master输出BCLK、FS,音频DAC把数据放到SD线上;现在只是把音频DAC换成了AD7768,把解码数据换成了ADC转换结果。这也是为什么我说SAI“超越音频”:它的时序能力完全覆盖了高速ADC的需求,只是很多人没往这个方向想。

2.3 帧格式与时隙配置的关键参数

AD7768的FS信号代表一帧数据的边界,一帧通常包含所有通道的数据。假设系统配置为8通道、24位输出,那么一帧的数据长度就是8×24=192个bit。SAI的TDM模式允许你把一个帧分成若干个slot,每个slot就是一条通道的数据。

  • 帧长度:即SAI的Frame length,应配置为8个slot×32bit=256bit(推荐这样配置,方便SPDIF/TDM对齐,也避免slot边界处理麻烦),也可以配置为192bit,但很多MCU对帧长度的对齐有要求,256bit更稳。
  • Slot数量:8,对应8通道
  • Slot大小:24~32均可,我建议用32bit slot,多余8bit填充0,这样DMA接收数据时每个通道天然对齐到32bit,处理起来省事。

AD7768的数据是24位左对齐还是右对齐,要看你从哪一端看。如果你把SAI的slot size设为32,并且把AD7768的数据从高位开始送出去,那么32位数据中的高24位就是有效数据,低8位为0,软件里直接右移8位就拿到原始ADC值。如果AD7768配置成低位在前,就需要在硬件上做翻转,或者通过AD7768的位序寄存器改成MSB优先。我强烈建议在AD7768侧将输出配置为MSB优先,然后在SAI侧按高24位读取,这样省掉大量的bit重排运算。

3. 时钟频率计算与SAI寄存器配置实操

这一节直接给出可以套用的计算过程和配置参考。我用STM32H743作为示例,主时钟HSE为25MHz,系统时钟跑480MHz,PLL1可以输出多路时钟。你需要先在CubeMX里打开SAI1的Block A,设置为Master Transmit TDM模式,注意数据其实是从ADC接收回来,但SAI产生时钟的主控逻辑用发送模式配置,接收数据可以另开一条DMA通道。

3.1 MCLK、BCLK、FS的频率计算

AD7768的MCLK推荐频率范围通常在10MHz到36.864MHz之间。我的常用配置是24.576MHz,这是音频行业的标准频率,用它做MCLK,再去分频得到DCLK和FS非常方便。举例:如果AD7768设置为每通道128倍抽取,输出速率256kSPS,那么DCLK至少要满足:8通道×24位×256k=49.152MHz。这个频率对于SAI的BCLK来说是完全可以接受的,STM32H7的SAI可以跑到50MHz以上。

具体计算:

  • MCLK = 24.576MHz
  • 帧频率FS = 256kHz(每通道输出速率)
  • 每帧位数 = 8 slot × 32bit = 256bit
  • BCLK最低需求 = 256 × 256kHz = 65.536MHz

这里出现问题了,BCLK需求比之前用24×8×256k算的49.152MHz更高,因为slot size选的是32bit。65.536MHz虽然SAI理论上能顶住,但我实际用下来建议把输出速率降到200kSPS,或者把slot压缩到24bit,也能跑得很稳。还有一种思路是把每帧数据做成两个半帧,利用双缓冲,但复杂度上来了,一般没必要。

如果你的应用采样率不需要那么高,比如每通道48kHz,那就太轻松了:MCLK还是24.576MHz,FS=48kHz,每帧256bit,BCLK只需12.288MHz,SAI完全是小菜一碟。

3.2 SAI初始化配置要点

在CubeMX里,SAI1 Block A设置:

  • Protocol:TDM
  • Frame Length:256
  • Frame Sync:Frame length设置为256bit,Frame sync active length可以设置为1bit或32bit,推荐1bit,因为AD7768的FS只是启动脉冲
  • Frame Sync Polarity:Active high或Active low根据AD7768配置来,通常Active high
  • Slot Number:8
  • Slot Size:32bit
  • Data Size:24bit

对应代码初始化时,注意SAI的FTH是FIFO阈值,DMA请求在FIFO达到阈值时触发,建议阈值设为1/4或1/2,避免FIFO溢出。DMA配置为Circular模式,数据宽度32位,外设地址为SAI1的接收数据寄存器地址,内存地址为uint32_t类型的缓冲区数组。

3.3 DMA传输与数据解析

DMA传输的缓冲区可以设计为二维数组:data[8][N],其中N为每个通道的采样点数。DMA每次收到256bit,也就是8×32bit,正好对应8个通道的一个采样点。DMA完成回调里,翻转一个标志位,主循环或RTOS任务直接读取当前缓冲区做处理。

我习惯使用双缓冲:两个DMA缓冲区,一个被ADC填,一个被算法读。这种乒乓结构能保证数据零丢失。在STM32上可以用两个DMA通道分别映射到同一个外设地址,或者用DMA的half-transfer中断来区分前半段和后半段缓冲区,逻辑上都是双缓冲,看个人习惯。

数据解析时,从32bit数据里直接右移8位拿高24位即可。如果AD7768配置为24位无符号,原码直接从采样值换算;如果是二进制补码,注意符号扩展,用int32_t接收后左移8位再右移8位,或者直接判断第23位符号位。

4. 实测中踩过的坑与排查方法

这套方案我调试了差不多一周,中间遇到的几个问题很有代表性,拿出来说下,能帮大家少走弯路。

4.1 数据全是0或者恒定值

SAI屏幕显示采集回来的数据一动不动,大概率是时钟没对齐。先查SAI的MCLK有没有输出,用示波器量引脚;再看AD7768的RESET引脚释放后,有没有等待足够的时间让内部调制器稳定。AD7768上电后需要至少几十毫秒的稳定时间,如果复位脚释放得太早,转换结果全是垃圾。

还有一个常见原因:FS极性反了。AD7768要求的帧同步极性可能与SAI默认配置不一致。把FS极性翻转一下,立刻就能看到数据波形跳动。

4.2 数据能变化但波形错乱

能采集到正弦波,但通道顺序不对,或者波形裂成两半,这多半是slot边界没对齐。AD7768输出第一通道的数据是从FS有效后的第一个DCLK下降沿开始,而SAI的slot从FS有效后的第一个BCLK上升沿开始,如果相位差了一个bit,所有数据都往左偏一位。解决办法是把SAI的BCLK极性改一下,或者把AD7768的DCLK相位配置偏移半个周期。AD7768的接口配置寄存器里有一个相位调整位,可以微调DCLK相对FS的相位,逐级试,直到波形完整。

4.3 高采样率下偶发丢数

跑256kSPS时,如果使用的DMA缓冲区太小,FIFO溢出就会丢数。加大DMA缓冲区,设置SAI的FIFO阈值为较高值,降低中断频率。另外检查DMA优先级,把SAI DMA的优先级设为最高,否则在系统总线繁忙时会延迟响应。

缓冲区大小建议至少保证能存两个完整DMA周期,比如每通道512点,8通道就是4096个uint32_t,DMA用Circular模式,这样即使主循环处理慢一点,也不会覆盖正在读的数据。

4.4 电源噪声导致SNR上不去

这是最容易翻车的地方。AD7768是高性能ADC,对模拟电源的纹波极其敏感。如果你的AVDD电源直接用了DC-DC输出而没有做后级LDO滤波,动态范围指标会明显下降。实测用AMS1117之类的LDO还不够,最好用低噪声LDO,如TPS7A4901、LT3042这类,并在输出端加一个10uF钽电容和0.1uF陶瓷电容并联。ADC的基准电压引脚(REFOUT/REFIN)附近不要走数字信号线,否则参考电压被干扰,所有通道都会出现周期性噪声。

5. PCB布局指南:让ADC性能真正落地

方案在原理上没问题,PCB布局如果把高速和模拟信号混在一起,AD7768的优势就会被直接拖垮。下面这些布局经验是我画了好几版板子后才总结出来的,每一版都有实测数据支撑。

5.1 地平面规划:不要轻易分割

很多人一看到“ADC”就想着把模拟地和数字地切开,结果用了磁珠连接,反而把回流路径搞得支离破碎。对于AD7768这种多通道同步采样ADC,我的建议是使用完整的地平面,不在芯片下方分割。AGND和DGND按照芯片引脚要求分别接到同一块完整的地平面上,通过引脚的小连接区域汇合。如果你实在需要分区,模拟区只在AD7768正下方割一小块,然后单点连接到主地平面,不要用0欧电阻跨接两条地来分隔,那样高速回流电流会绕远路,噪声反而更大。

5.2 模拟电源与数字电源的滤波策略

AD7768的AVDD1、AVDD2是模拟电源,DVDD是数字电源。PCB上建议AVDD1和AVDD2分别用独立的LC或RC滤波后接入,每路电源引脚旁放一个0.1uF陶瓷电容,靠近引脚放置,电容地端直接打过孔到地平面。DVDD可以由系统3.3V直接供,但同样需要靠近引脚的去耦电容。

如果你用了多个AD7768通道同时采集,注意每个AVDD引脚的去耦电容不要共享,一个引脚一个电容,容值可以选择0.1uF+10uF组合,大电容可以稍远一点,小电容必须在3mm以内。

5.3 晶振与时钟电路布局

AD7768对MCLK质量高度敏感,MCLK的走线要远离任何开关电源的SW节点、电感、DC-DC输出。在PCB布局时,把晶振或者时钟源放在AD7768同侧,时钟走线尽可能短,并且用地包地保护。如果MCLK由MCU的SAI输出提供,MCLK走线还要注意不要在ADC下面穿越,否则耦合到芯片内部影响性能。

还有一点:DCLK、FS这些数据接口信号走线,和MCLK保持至少3倍线宽的间距。DCLK是高速开关信号,它耦合到MCLK上,等效为MCLK上叠加一个高频纹波,直接影响调制器性能。

5.4 SAI走线的信号完整性

SAI的BCLK(DCLK)、FS、SD数据线如果走了很长的排线或跨层过孔太多,高速边沿会退化。两块板之间若要连接ADC子板和MCU主控板,建议SAI数据线使用短而直的地-信-地三线结构,信号线两侧一路铺地孔。阻抗控制在50欧姆左右即可,但更重要的是保持信号线等长,DCLK和SD线长度差不要超过5mm,否则高位数据位的建立时间不够,采样值会出现跳变。

5.5 去耦电容的位置与过孔处理

去耦电容的安装位置要强调一个“近”字:电容到电源引脚的距离,不要超过电容本身封装宽度的3倍。我见过很多板子电容放在芯片背面,这是可以接受的,但电容地端到芯片地引脚的过孔必须尽量靠近,最好直接打在焊盘旁边。如果空间允许,在每个AD7768电源引脚正下方打一个地孔,孔不要在电容和引脚之间穿过,电流路径越短,去耦效果越好。

6. 后级处理与性能验证

数据接到MCU后,别急着直接使用。我习惯先做几轮性能验证,确认整个链路没有引入额外失真。首先生成一组已知频率的正弦波输入,比如1kHz、幅度-1dBFS,采集一段数据后做FFT,看SNR、THD、SFDR指标。如果SNR和AD7768手册上的典型值差很多,先查电源和布局;如果基本接近手册值,恭喜你,这套方案已经可用了。

数字端处理我一般会做以下几步:

  • 直流偏置校准:每个通道减去大量采样平均得到的直流分量。
  • 增益校准:用一个精确的参考电压源输入,计算每个通道的实际增益系数并保存到Flash。
  • 相位校准:如果多通道之间存在相位不一致,采集同一信号后计算通道间延迟并补偿。

多通道同步采集本身是AD7768的核心卖点,通道间相位差非常小,但通道间的增益和失调会有些差异,校准后就能达到很高的一致性。

关于DMA中断和数据处理的衔接,我建议把FFT等重计算放到后台任务,中断里只做标志位置位和数据指针切换,不要在中断里做浮点运算。STM32H7有FPU,但FFT在中断里做会严重影响采样连续性,必须把计算任务挪走。

写在最后的一点实战体会

这套SAI+AD7768方案最终用在了一个多通道振动监测的项目上,8通道同步采样跑200kSPS,SD卡连续记录一周,数据没有出现一次丢帧。我想说的是,SAI接口的价值远不止音频应用,当你理解到它只是一个灵活的串行时序引擎之后,会发现很多高速外设都可以用它来驱动,尤其像AD7768这类需要多路时钟且数据帧结构固定的ADC,SAI几乎是为它量身定做的。

最后分享一个小技巧:在正式画板之前,先用MCU的SAI接一个简单的74HC595移位寄存器验证时序框架,把MCLK、BCLK、FS的波形逻辑跑通,再回头连接AD7768联调。这样可以把时钟、DMA、中断逻辑和ADC芯片本身的调试解耦,遇到问题时能快速定位到底出在MCU配置还是硬件板上,省下大量的联调时间。希望你也能用这套方案做出稳定可靠的高速多通道采集系统。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询