从250kSPS到8通道同步:硬核拆解ZLinear 18位SAR ADC序列器与SPI接口的底层时序

📅 2026/7/18 1:56:34 👁️ 阅读次数 📝 编程学习
从250kSPS到8通道同步:硬核拆解ZLinear 18位SAR ADC序列器与SPI接口的底层时序

zlinear开源电子

前言

大家好,我是ZLinear的硬件工程师。

在上一期博文中,我们拆解了LHA8949-18这颗18位SAR ADC的硬件参数——从内置参考源到温度传感器,从激光修调电阻到93dB动态范围。后台很多读者表示看了非常过瘾,但也有做嵌入式开发的兄弟提出了一个非常“内核级”的问题:

“张工,datasheet里的参数确实漂亮,可真正把这颗ADC用起来,最关键的是把它的序列器和SPI接口搞对。我上一周用K60和它通信,时序怎么都对不上,读回来的数据要么全是0xFF,要么跳来跳去。你们到底是怎么把8个通道的数据一个不丢地读回来的?”

这个问题问到了最核心的地方!一颗ADC的参数再好,如果数字接口时序搞不定,它就是一块废铁。今天,我们就把自己关在实验室里,拿着逻辑分析仪,硬核拆解LHA8949-18的通道序列器工作原理SPI接口的四种读写模式,并给出ZLinear采集卡中实际采用的、经过验证的底层驱动时序代码(伪代码风格,无复杂公式)。

当你搞懂序列器的“自动扫街”机制和SPI的“转换时读写”策略后,你也能像我一样,让这颗ADC乖乖吐出8个通道的干净数据。


一、序列器:为什么8通道非得用它?

先搞清楚一个问题:为什么要用内置序列器?难道不能用外部MCU在每次转换前手动切换通道吗?

从理论上讲,MCU每次在SPI事务前设置一下CFG寄存器里的通道号,确实也能采多通道。但这样做会带来三个致命问题:

  1. CPU负担暴增:每次转换都要介入配置,250kSPS下每秒要处理25万次中断,CPU干不了别的了。
  2. 通道间时间误差:MCU处理中断和配置CFG的时间是不确定的,导致各通道的采样时刻无法精确对齐。
  3. 数据交错困难:手动切换模式下,如果你想同时看所有通道的“快照”,几乎不可能。

LHA8949-18的序列器彻底解决了这些问题。Datasheet第11.3.4节明确写道:

“LHA8949-16包括一个通道序列器,可用于以IN0到IN[7:0]的方式扫描通道。确定序列的最后一个通道后,以逐个或成对方式扫描通道,包括或不包括温度传感器。”

1. 序列器的核心配置

序列器的行为完全由14位CFG寄存器控制。关键的位段在Datasheet表10中有详细说明:

  • CFG[9:7](INx):设置序列的“终点”,比如设为111表示最后一站到IN7。
  • CFG[2:1](SEQ):控制序列器的启停和扫描模式。设为2‘b11表示“扫描IN0到IN[7:0]”。
  • CFG[12:10](INCC):设定输入模式(单端、差分、伪双极性等)。

举个例子:如果你设置CFG[9:7]=111(终点IN7)、CFG[2:1]=11(启动序列器)、CFG[12:10]=111(单端参考GND),那么序列器启动后连杆如下:

IN0 → IN1 → IN2 → IN3 → IN4 → IN5 → IN6 → IN7 → (回)IN0

每次启动转换(拉高CNV),芯片自动切换到下一个通道。一轮转换结束,正好采完8个通道。然后自动回到IN0,开始下一轮。

2. 序列器模式的“隐形成本”

使用序列器时有个重要细节:第一轮循环的数据是无效的

Datasheet第12.7节图20的时序图显示:在进入序列器模式后的第一个转换周期,芯片需要有一个“启动建立时间”。所以我们的软件处理方式是:

上电后先做一轮“空转转换”,产生的数据直接丢弃,从第二轮开始才作为有效数据。这是很多初学者踩的坑——上来就读第一轮的数据,结果发现值不对。

3. 温度传感器的嵌入

LHA8949-18还有个小绝活——序列器可以内置温度传感器扫描。如果你把CFG[2:1]设为2‘b10,序列器会在扫完IN[7:0]之后,自动插入一次内部温度传感器的转换。

这意味着:你不需要额外接热敏电阻,一颗芯片就能同时完成8通道数据采集+ADC自身结温监测。这在工业长期运行中非常有价值——上位机可以根据结温对ADC的增益和失调进行实时补偿。


二、SPI接口的四种“人格”:你必须选对模式

LHA8949-18的数字接口非常简单:只有4根线——CNV(转换触发)、DIN(数据输入,配置CFG用)、SCK(时钟)、SDO(数据输出)。

但Datasheet第12章一口气给出了四种时序模式,让很多初学者瞬间懵逼。我把它们整理成一张表格,并给出各自的“最佳使用场景”。

模式名称读数据时机写配置时机适用场景时钟要求
转换时读写(快速主机)转换过程中转换过程中高速采样,主机速度快需快速SCK(>14MHz)
转换后读写(任何速度主机)转换完成后,采集阶段采集阶段慢速主机,不限时钟速度任意速度
跨越转换读写从本次采集跨到下次转换采样到转换全程中等速度,灵活在采样阶段内完成即可
有繁忙指示模式转换完CNV拉低,SDO变低同上中断驱动需19个SCK

1. ZLinear采集卡的实战选择:转换后读写

在我们的DABL-G511和DABM-D223采集卡固件中,最常用的是转换后读写模式。原因很简单:

  • 主机就是STM32F4(168MHz)或FPGA,速度足够,不需要贪那点额外的时间。
  • 时序最简单,不容易出错。转换完成后,CNV拉低,SCK开始一比特一比特地往外掏数据。掏完后,再写下一帧的配置。逻辑非常清晰。
  • 与序列器配合完美。序列器模式下,每个通道的转换都是前一个通道数据读完后立即开始下一次转换,时间利用率极高。

2. 实战代码框架:转换后读取8通道

以下是采集8通道数据的完整伪代码“骨架”,你可以在STM32或类似MCU上复用:

// 伪代码:8通道序列器模式采集函数 void adc_scan_8_channels(void) { // 第一步:配置序列器 // CFG寄存器:14位,从DIN串行写入 // CFG[12:10]=111(单端参考GND) // CFG[9:7]=111(终点IN7) // CFG[2:1]=11(序列器使能,扫IN0~IN7) // 其他位按Datasheet配置 uint16_t cfg_value = 0x3FFF; // 由工厂预置或自定义 spi_write_14bits(CS_PIN, cfg_value); // 第二步:空转一轮(丢弃) for(int i=0; i<8; i++) { CNV_HIGH(); // 启动转换 delay_us(2.1); // 等待tCONV(转换完成) CNV_LOW(); // 拉低CNV,进入读模式 uint16_t dummy = spi_read_18bits(CS_PIN); // 读18位数据,丢弃 } // 第三步:正式循环读取 while(1) { // 每个循环采集一轮8通道 for(int ch=0; ch<8; ch++) { CNV_HIGH(); // 启动当前通道的转换 delay_us(2.1); // 等待转换完成(2.1μs典型值) CNV_LOW(); // 拉低CNV,SDO开始输出MSB // 读取18位转换结果 // 当序列器模式下,CFG在第一次配置后不再需要写入 // 只需读数据即可 uint32_t raw_value = spi_read_18bits(CS_PIN); // 存储到缓冲区,等待上位机读取 adc_buffer[ch] = raw_value; } } }

3. 关键时序细节:CNV的“生命线”

真实的时序图中,CNV的上沿表示“开始转换”。而CNV的上沿还有一个重要作用:它也是SPI SDO引脚由高阻态变为有效输出的触发条件。

时序参数表(Tab.3)中,最重要的一条是tEN(CNV变低到SDO输出MSB有效的时间)。在VIO=3.3V时,这个时间是20ns左右。所以我们在CNV拉低后,至少要等20ns才能开始SCK时钟——实际工程中我们通常会延期100ns以上以保证可靠。

另一个致命细节:CNV在转换期间不能拉低得太早或太晚。

  • 太早(tDATA内):数据还没稳定就被中断,读到乱码。
  • 太晚(超过tCONV):转换结束了,芯片认为你不想读,SDO恢复高阻。

所以,CNV拉低的时机应该在tCONV之后,tDATA之内。我们的做法是:直接用定时器中断或FPGA计数器,在转换开始后精确延时2.2μs(略大于tCONV的2.1μs),然后拉低CNV开始读。


三、有繁忙指示模式:给中断驱动的“阴暗面”上把锁

在某些需要实时响应、不想轮询的场景下,可以使用有繁忙指示模式

这个模式的关键是:SDO引脚会在转换完成时自动由高阻态变为低电平,作为给主机的“忙转闲”中断信号。

Datasheet第12.6节写道:

“在EOC时刻,如果CNV为低电平,则启用繁忙指示。为了正确地生成繁忙指示,主机必须产生至少19个SCK下降沿以将SDO返回到High-Z状态。”

1. 为什么SCK需要19个下降沿?

在无繁忙指示模式下,读18位数据只需18个SCK下降沿。但在繁忙指示模式下,第19个SCK下降沿用来把SDO恢复到高阻态,这样下一帧转换开始时,CNV拉低后,SDO从高阻变为低电平的变化才能被主机正确识别为“繁忙信号”。

如果你只发18个时钟,第18位LSB如果是0,SDO就会一直是低电平,主机永远看不到“由高到低”的变化边沿,繁忙指示就失效了。

2. FPGA方案中的使用

在ZLinear的DABM-D223(ARM+FPGA双核心)中,我们就是用FPGA来实现有繁忙指示模式的。FPGA用硬件状态机控制CNV和SCK的时序,精度远高于MCU的软件延时。每当检测到SDO由高变低的边沿,就触发DMA读取。

这种做法让DABM-D223在8通道500K采样模式下,CPU的利用率几乎为零——所有时序都由FPGA硬件完成。


四、CFG回读:调试阶段的“救命稻草”

LHA8949-18的CFG寄存器支持回读(CFG[0]=RB位设为0,表示回读)。这个功能在调试阶段极其有用。

场景:你在客户现场调试,发现ADC输出数据不对,怀疑是CFG配置没写进去。如果没有回读功能,你得重新检查SPI时序波形图。而有回读功能,你只需在读取转换结果时,CNV拉低后,在SCK的第18个下降沿(LSB读完后),芯片自动开始输出CFG的内容作为后续14位数据。你的上位机就能直接看到“当前芯片内部实际配置是什么”。

注意:回读会延长读数据的时间。无回读下只需18个SCK,有回读需要32个。如果你用的是有繁忙指示模式,则需要33个SCK。


五、实战经验:避免SPI通信的三个致命错误

在调试8通道18位ADC的SPI通信时,我们统计了自己的“踩坑记录”,以下三条是出现频率最高的:

错误1:SCK空闲电平设置错误

Datasheet第12.5节明确写着:

“如果使用SPI接口,SCK在空闲时间可以是高电平或低电平,这取决于时钟极性(CPOL)和相位(CPHA)的配置。一个简单的解决方案是使用CPOL=CPHA=0,如下图所示,SCK空闲时间为低电平。”

我们的实测结果是:推荐严格使用CPOL=0,CPHA=0。只要空闲时SCK是低电平,数据在SCK的下降沿改变输出(SDO),在上升沿被主机的MISO采样(DIN)。这种模式下,你不需要处理任何特殊的时钟相位问题。

错误2:转换期间数字引脚有活动

Datasheet第12节警告说:

“如果在采样时刻附近SCK或DIN的翻转也可能会被采样。因此,在CNV上升沿之前30nS和之后的10nS时间内,建议保持数字引脚安静。”

这个警告太容易被忽略了。很多工程师在CNV上升沿附近正好在给DIN写入数据,结果SCK的边沿通过引脚串扰耦合到了ADC的内部采样电路,导致转换结果跳变。

解决办法:用中断或定时器保证在CNV拉高前30ns和拉高后10ns内,DIN和SCK没有任何电平变化。我们通常的做法是:先拉高CNV,等待50ns,再开始SCK时钟

错误3:多通道数据包组帧混乱

在序列器模式下,8通道的数据是依次输出的。但如果上位机在解析时没有严格的“帧同步”,可能把通道N的数据和通道N+1的数据弄混。

解决办法:在底层固件中,把8通道的数据打包成一个有帧头的数据帧(参考我们之前讲的_adcSendBuf结构体,帧头0x55AA,后跟通道0~7共8个值),上位机用有限状态机解析。这样可以100%避免数据错位。


六、总结:序列器+SPI是ADC的“灵魂开关”

序列器维度配置要点产生的价值
启动配置设置CFG[9:7]终点、CFG[2:1]启动、CFG[12:10]模式自动扫8通道,CPU零负担
空转丢帧上电后第一轮丢弃避免建立时间影响数据
温度嵌入CFG[2:1]=10开启额外监测ADC结温,用于补偿
SPI模式选择CPOL=CPHA=0最省心时序简单,不易出错

写到这里,我希望大家明白:LHA8949-18的序列器和SPI接口,不是两个独立的功能,而是一个完整的自动化数据采集子系统。序列器负责“招呼”8个通道轮流站上起跑线,SPI接口负责给每个跑到终点的通道“念成绩单”。整个流程一气呵成,不需要CPU全程介入,效率极高。

ZLinear之所以把LHA8949-18的配置映射表、序列器初始化代码示例和SPI接口的时序图全部开源并写入文档,就是希望你在做多通道高速采集时,不需要像我当初那样拿逻辑分析仪找两小时的波形。当你配置好序列器,拉高CNV,看着示波器上SDO吐出一串整齐的18位数据帧时,你就会理解这颗芯片“为嵌入式而生”的设计哲学。

如果你在调试序列器时遇到了SCK边沿问题,或者对CFG回读的32个时钟不解,欢迎在评论区留言交流。我们一起把“ADC的最后一公里”打通!


我是 ZLinear 开源电子。我们坚信,优秀的数字接口不是靠“运气”写出来的,而是靠对Datasheet每一章节的敬畏和对时序图每一纳秒的较真。如果今天的序列器与SPI拆解对你有帮助,欢迎点赞、收藏、关注三连,我们下期再见!