从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寄存器里的通道号确实也能采多通道。但这样做会带来三个致命问题CPU负担暴增每次转换都要介入配置250kSPS下每秒要处理25万次中断CPU干不了别的了。通道间时间误差MCU处理中断和配置CFG的时间是不确定的导致各通道的采样时刻无法精确对齐。数据交错困难手动切换模式下如果你想同时看所有通道的“快照”几乎不可能。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章一口气给出了四种时序模式让很多初学者瞬间懵逼。我把它们整理成一张表格并给出各自的“最佳使用场景”。模式名称读数据时机写配置时机适用场景时钟要求转换时读写快速主机转换过程中转换过程中高速采样主机速度快需快速SCK14MHz转换后读写任何速度主机转换完成后采集阶段采集阶段慢速主机不限时钟速度任意速度跨越转换读写从本次采集跨到下次转换采样到转换全程中等速度灵活在采样阶段内完成即可有繁忙指示模式转换完CNV拉低SDO变低同上中断驱动需19个SCK1. ZLinear采集卡的实战选择转换后读写在我们的DABL-G511和DABM-D223采集卡固件中最常用的是转换后读写模式。原因很简单主机就是STM32F4168MHz或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 i0; i8; 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 ch0; ch8; ch) { CNV_HIGH(); // 启动当前通道的转换 delay_us(2.1); // 等待转换完成2.1μs典型值 CNV_LOW(); // 拉低CNVSDO开始输出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中最重要的一条是tENCNV变低到SDO输出MSB有效的时间。在VIO3.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如果是0SDO就会一直是低电平主机永远看不到“由高到低”的变化边沿繁忙指示就失效了。2. FPGA方案中的使用在ZLinear的DABM-D223ARMFPGA双核心中我们就是用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通信时我们统计了自己的“踩坑记录”以下三条是出现频率最高的错误1SCK空闲电平设置错误Datasheet第12.5节明确写着“如果使用SPI接口SCK在空闲时间可以是高电平或低电平这取决于时钟极性(CPOL)和相位(CPHA)的配置。一个简单的解决方案是使用CPOLCPHA0如下图所示SCK空闲时间为低电平。”我们的实测结果是推荐严格使用CPOL0CPHA0。只要空闲时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的数据和通道N1的数据弄混。解决办法在底层固件中把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模式选择CPOLCPHA0最省心时序简单不易出错写到这里我希望大家明白LHA8949-18的序列器和SPI接口不是两个独立的功能而是一个完整的自动化数据采集子系统。序列器负责“招呼”8个通道轮流站上起跑线SPI接口负责给每个跑到终点的通道“念成绩单”。整个流程一气呵成不需要CPU全程介入效率极高。ZLinear之所以把LHA8949-18的配置映射表、序列器初始化代码示例和SPI接口的时序图全部开源并写入文档就是希望你在做多通道高速采集时不需要像我当初那样拿逻辑分析仪找两小时的波形。当你配置好序列器拉高CNV看着示波器上SDO吐出一串整齐的18位数据帧时你就会理解这颗芯片“为嵌入式而生”的设计哲学。如果你在调试序列器时遇到了SCK边沿问题或者对CFG回读的32个时钟不解欢迎在评论区留言交流。我们一起把“ADC的最后一公里”打通我是 ZLinear 开源电子。我们坚信优秀的数字接口不是靠“运气”写出来的而是靠对Datasheet每一章节的敬畏和对时序图每一纳秒的较真。如果今天的序列器与SPI拆解对你有帮助欢迎点赞、收藏、关注三连我们下期再见