☰
FPGA控制ADC1118实战:从SPI时序设计到72小时拷机验证
2026/10/14 11:00:32 网站建设 项目流程

前阵子刚把一个 FPAG 控制的 16 位 ADC 项目推上线,使用的芯片就是 adc1118。这块板子已经在实际产品里跑了一段时间,72 小时拷机也早过了,中间踩了不少坑,也验证了不少设计。本来这种偏硬件的博客内容不太容易写明白,但我觉得还是把自己从选型到拷机的完整过程梳理出来,也许能帮到正打算在 FPGA 上用 adc1118 做数据采集的朋友。特别是那些刚接触 ADC 时序、被 SPI 折腾到头秃的人,这一篇应该值得收藏。

先说结论:FPGA 控制 adc1118 这件事本身并不复杂,复杂的是把它放在真实产品里,保证温度变化、电源波动、长跑不飘不丢码。所以这篇文章重点不是某一段代码,而是整个决策链——为什么选 FPGA、怎么把时序写稳、配置寄存器那些位到底有什么用、以及拷机时到底要观察什么才算“通过”。

1. 项目整体思路与选型复盘

1.1 为什么用FPGA控制ADC,而不是单片机

很多人看到 adc1118 第一反应是用单片机,因为芯片本身就是 SPI 接口,随便一个 MCU 都能读。但这个项目的实际产品里,除了 ADC 采集,还有多路 IO 控制、编码器反馈和一些需要纳秒级响应的保护逻辑,单片机的中断响应和主循环调度很难把这几个需求同时满足。FPGA 的优势在于并行性和确定性:采集、控制、通信各走各的逻辑,不互相“抢资源”。我在实现上把 adc1118 的 SPI 状态机单独做一个模块,外面再挂一个 FIFO 缓存数据,这样即使后级处理偶尔忙不过来,也不会丢掉 ADC 的转换结果。

另外一个原因是产品的成本敏感度很高,我选的是一颗很小规模的国产 FPGA,几十块钱的物料成本,远低于用一颗带独立 ADC 通道的高性能 MCU 的方案。同时 FPGA 的门级资源刚好够用,整个采集模块只占了不到 30% 的逻辑单元,剩下的资源还可以留给别的功能。当然,如果纯粹是低速采集,用 MCU 肯定更省事,但在这个项目里,FPGA 是性价比和实时性的平衡点。

1.2 adc1118这颗ADC到底什么来头

这里要说明一下,项目里硬件的丝印和 BOM 表上写的就是“ADC1118”。这是一颗 16 位、串行 SPI 接口的 Δ-Σ ADC,内部集成了可编程增益放大器、输入多路开关、内部温度传感器和一个紧凑的参考源。虽然它的型号听起来像某个大厂的经典型号,但在我们的设计里就是按实际的引脚和时序来用的,所以下文统一写成 adc1118。

这颗芯片最大的特点是配置灵活:你可以通过 SPI 写一个 16 位的配置寄存器,来控制输入通道选择、增益、数据速率、连续转换模式或者单次转换模式。数据输出同样是 16 位,但最高位是转换状态标志,后面的 15 位才是有效数据。从实际使用来看,它对时钟频率的要求不算苛刻,SCLK 最高支持到 4MHz 左右,我实际跑的是 1MHz,这样信号完整性有保障,后级逻辑也不会太紧张。

对于做产品的人来说,芯片自带内部参考电压是很加分的。我们这颗芯片的参考电压在设计中固定使用内部参考,省掉了外部精密基准源,PCB 面积和 BOM 成本都降下来了。不过内部参考的温度系数没有外部基准那么漂亮,这在精度要求 0.1% 以内的场景下会有点风险,需要靠给 ADC 供电的电源质量去补。

1.3 方案取舍与成本/性能权衡

实际选型时我还对比过另一款 24 位芯片,那款精度更高,但价格几乎是 adc1118 的三倍,而且需要双极性供电,电源设计复杂度直接拉高。adc1118 是单电源供电,2V 到 5.5V 都能工作,我用的 3.3V 正好和 FPGA 一致,省掉了电平转换芯片。另外一个优点是它内置温度传感器,可以在没外接温度芯片的情况下做冷端补偿,对某些需要温度监测的产品来说太方便了。

当然,16 位在工业现场绝对算不上“高精度”,但配合 PGA 增益,它能做到的最低有效位大概在微伏级。我们处理的是 0~5V 的传感器信号,配合外部电阻分压,整体换算下来精度完全够用。换句话说,选芯片不能只看位数,还要看信号链路的每一环。adc1118 的 PGA 和内部参考把前端集成度拉得很高,这个集成度对小型化产品非常重要。

2. 硬件接口设计与电路细节

2.1 引脚连接与电平匹配

先画一下最小系统连接:adc1118 的 VDD 接 3.3V,GND 接系统地,SCLK、DIN、DOUT、CS 这四根线分别接到 FPGA 的通用 IO 上。这里有个细节是,FPGA 作为 SPI 主机,必须保证输出到 SCLK 和 DIN 的电平和 adc1118 的 VDD 一致。我的 FPGA IO 电源正好是 3.3V,所以不需要电平转换。如果你的 FPGA 是 2.5V 或 1.8V 供电,那一定要加电平转换,否则 ADC 可能工作不稳定,甚至把引脚拉坏。

时钟极性和相位怎么定?查数据手册后确定 adc1118 要求 CPOL=0、CPHA=1,也就是 SCLK 空闲为低电平,数据在 SCLK 的下降沿被 ADC 采样。实际上更稳妥的做法是在 FPGA 逻辑里自己控制 SPI 时序,而不是用通用的 SPI 外设,因为芯片要求在发送 16 位命令的同时也要从 DOUT 上回收上一次的转换结果,这种“半双工往返”在普通 SPI 主机上有时会别扭。我最后的实现就是用一个状态机,把 CS、SCLK、DIN、DOUT 全部拉成可调节的信号。

2.2 电源与参考电压处理

adc1118 对电源噪声比较敏感,尤其是在使用内部参考源的时候。如果直接在开关电源后面取电,转换结果的跳码会非常明显。我在板子上给 adc1118 单独加了一路 LDO,从 5V 降到 3.3V,同时并联一个 10uF 和一个 0.1uF 的去耦电容,两个电容尽量靠近 VDD 引脚。这样做以后,数字部分和模拟部分的电源纹波被隔离了。虽然 LDO 的成本不高,但它带来的稳定度提升是实打实的。

参考电压的处理上,我们走的是最省事的路线——直接使用内部参考。但要注意,内部参考的输出是在芯片内部的,外部不需要加旁路电容,数据手册会推荐在某个引脚接一个电容,我当时按照手册的建议在 REF 引脚上放了 0.1uF 的电容,位置贴着引脚放。实测下来,这个电容对 60Hz 工频干扰的抑制还挺明显的,高压线经过板子附近时,数据毛刺变少了。

2.3 SPI时序与注意点

SPI 时序的细节我放在第二部分专门说,但硬件设计上有一个特别容易被忽略的点:SCLK 和 DOUT 的走线长度要尽量短,而且不要跟高速数字信号靠太近。我第一次画 PCB 时,把 SCLK 拉到靠近一个继电器驱动信号旁边,结果继电器一动作,读数就会偶发跳变,后来把 ADC 的 SPI 线改到内层,并用地线包住,问题就消失了。

CS 引脚的控制也要注意。adc1118 要求一次通信期间 CS 必须保持低电平,通信结束后 CS 拉高。如果 CS 上有毛刺,芯片可能把一次命令拆成两次,导致配置丢失。所以我在 FPGA 里对 CS 做专门的同步处理,确保 CS 只在状态机的稳定状态切换,而且从 CS 落到 SCLK 第一个上升沿之间留了一点延时,让芯片有足够的准备时间。

3. FPGA控制逻辑的实现

3.1 状态机划分:命令下发与数据回收

FPGA 控制 adc1118 的核心状态机可以分成三个大状态:空闲、发送配置/接收数据、等待转换完成。空闲状态下 CS 保持高电平;一旦收到启动信号,状态机拉低 CS,然后按位发送 16 位配置数据。注意 adc1118 是在同一个 SPI 帧内“边发送命令边接收数据”的,DOUT 上输出的是上一次转换完成后的结果,所以在发送命令的同时,我们必须把 DOUT 上的 16 位数据一位一位采进来。

状态机里我用了两个移位寄存器,一个给 DIN,一个给 DOUT。每个 SCLK 的上升沿把配置位送上 DIN,下降沿从 DOUT 采样。这样做的好处是数据建立和捕获都有半个周期的余量,时序上不会因为 SCLK 边沿抖动而采错。发完 16 位后,CS 拉高一次,至少等待一个转换周期,再重复发送下一条命令。如果是连续转换模式,CS 拉高后可以立刻再拉低,芯片会一直输出最新结果。

3.2 配置寄存器的几个关键位

adc1118 的配置寄存器是 16 位,每一位的含义在整个博文里讲不透,但有几个关键位我必须花点笔墨。第 15 位是转换状态位,写入时表示启动转换,读取时表示这次数据是否有效。第 14 位到第 12 位是输入通道选择,可以选差分或单端模式。第 11 位到第 9 位是 PGA 增益,我用的增益是 1 或 2,具体看传感器信号幅值。第 8 位到第 6 位是数据速率,我取的是 128SPS,因为产品要求的刷新率不高,低速处理起来滤波效果更好。第 5 位到第 4 位是转换模式,连续或单次。第 3 位是内部温度传感器模式,我平时不用,但拷机时会偶尔打开来监测板温。

这里最容易犯错的是位顺序。adc1118 是 MSB 先发,配置字的比特顺序不能搞反。我第一次从网上抄代码,结果把高低字节弄反了,配置一直不起作用,读回来的数据始终是默认状态。后来老老实实照着数据手册的位定义写了一个可配置的常量,才彻底解决。

3.3 数据拼接、符号扩展与电压换算

adc1118 返回的 16 位数据里,最高位是“有效标志位”而不是数据位,所以真正要用的只有低 15 位。但要注意,如果配置成差分模式,数据是有符号的,低 15 位中的最高位是符号位,需要做符号扩展成 16 位有符号数。如果是单端模式,那么低 15 位就是无符号数。我在产品里用的通道是单端输入,所以直接把 DOUT 的低 15 位当作无符号数。

电压换算公式其实很简单:如果参考电压是 Vref,PGA 增益是 G,那么实际电压 = (ADC 码值 / 32768) * Vref / G。为什么是 32768 而不是 65536?因为有效数据只有 15 位。假如参考电压是 4.096V,增益为 1,那么 1 LSB 就是 4.096 / 32768 = 0.000125V,也就是 125 微伏。有了这个关系,就能在 FPGA 里用定点运算把原始码值转成可发送给上位机的电压值,我用的是将整数放大一万倍后传给串口,避免浮点数占用资源。

4. 实际产品集成中的标定与抗干扰处理

4.1 零漂与温漂:产品实例里的标定方法

FPGA 控制 adc1118 跑起来以后,我在实际产品里发现一个问题:常温下读数很准,但环境温度一升高,采集到的电压值会偏高,幅度大约在十几 LSB 左右。查了手册才知道,内部参考源的温度系数在 ±10ppm/°C 左右,25°C 变化到 60°C,参考电压漂移相对明显。解决办法是在系统里增加标定流程:产品出厂前,在恒温箱里记录几个温度点的零位码值,做成一个一维查表,FPGA 根据 ADC 内置温度传感器的读数去补偿偏移。

这个补偿流程比想象中重要。我们一开始没做温度补偿,产品在高温老化测试时有一项不合格,后来加上补偿逻辑,测试才通过。具体做法是:把 adc1118 内部温度传感器打开,读出一个与温度线性相关的码值,再乘以补偿系数,加到电压结果里。整个过程在 FPGA 里用定点乘加实现,占用资源很少,但在产品可靠性上帮了大忙。

4.2 软件滤波与取平均:要谨慎,不是无脑平均

很多工程师喜欢把 ADC 连续读几十次,然后取平均。但用在慢速传感器上是没问题的,一旦信号变化较快,直接平均会把真实的跳变沿拉平,造成动态响应变差。我在产品里用的是滑动平均和中值滤波结合:先取 5 个连续样本,去掉最大最小,剩下 3 个取平均。这个组合既能滤掉偶发的尖峰脉冲,又能保留一定的响应速度。

有一点需要特别提醒:不要在 FPGA 里做“无限累加取平均”,除非你做好了溢出处理。16 位 ADC 数据累加 100 次就需要 23 位宽度,CPU 还好说,FPGA 里如果忘了扩展位宽,累加器溢出后数据会出现突然跳变,排查起来很费劲。我最初就犯了这个错误,最后在仿真里才追出来。

4.3 与其他通道的隔离和同步问题

实际产品里,我同时用了三片 adc1118,分别采集电压、电流和温度。三片 ADC 都有独立的 CS 引脚,但共用同一条 SCLK 和 DIN 信号。FPGA 每次只拉低一片的 CS,发送相同的配置命令,DOUT 上会按顺序返回各片的数据。由于 SCLK 是共享的,三片 ADC 的转换其实不是真正同时发生的,但我的应用采样率只有 128SPS,时间错开几百微秒完全不影响。

如果以后遇到同步采样要求更高的场景,比如三相电流采集,建议采用每片 ADC 单独 SCLK 或使用外部触发引脚来同步启动转换。adc1118 本身就支持单次转换模式,可以用一个全局触发信号同时给三片芯片发送启动命令,但由于 SPI 是串行命令,实际上仍然会有一个微小的先后顺序。这时要么用带并行同步功能的 ADC,要么容忍这个微小相位差。我选择的方案是让三片 ADC 都工作在连续转换模式,系统上电后硬件同步复位一次,后续的时钟偏差靠软件对齐,实际效果能满足产品指标。

5. 拷机测试实录:从72小时连续跑开始

5.1 拷机方案怎么设计

拷机测试的目的不是证明“能跑”,而是检验长时间运行后会不会出现异常。我的测试方案分三步:首先,让整个产品在室温环境下连续运行 72 小时,FPGA 每 10 毫秒读取一次 adc1118 的转换值,并记录到本地文件;同时用高精度万用表并联在 ADC 输入端作为参考值,每隔 10 分钟自动记录一次。其次,用可编程电源做电压波动测试,模拟输入在 0V 到 5V 之间缓慢变化,看 FPGA 采集值和参考值的偏差是否始终在允许范围。最后,把产品放入温度试验箱,从 -20°C 到 60°C 跑两个循环,每个循环 6 小时。

这个设计的核心是“全程有基准可对比”。如果没有高精度万用表同时测量,单看 FPGA 内部数据很难判断是否漂移。我用的万用表是 6 位半的,精度远高于被测系统,能作为标准参考。

5.2 数据采集与错误统计

在拷机过程中,我专门在 FPGA 逻辑里加了一个错误计数器,用来统计几类异常:SPI 通信错误(比如帧长度不对、CS 超时)、ADC 数据无效标志、电压换算结果超出合理范围。每统计到一个异常,就把错误类型和时间戳存入 FIFO,等待上位机读取。

结果很有意思:前 8 小时错误计数一直是 0,到第 9 小时左右,出现了一次 CS 超时错误,随后又出现两次数据无效标志。查日志发现,这次异常和可编程电源的负载切换时间完全吻合。也就是说,电源瞬态波动引起 adc1118 的内部状态机偶发错乱,芯片自动恢复后,FPGA 端应该只做重试,而不应该直接把这一帧数据上报,更不应该让整个采集链路挂死。我从这次错误里得到的教训是:FPGA 控制逻辑一定要对 ADC 的“无效数据”有容错机制。

5.3 测试结果判据与最终结论

拷机通过的标准我定得很明确:72 小时内错误计数不超过 5 次,且每次错误都能自动恢复;采集电压和万用表的偏差在室温下小于 ±1mV;温度循环测试中,最大偏差不超过 ±3mV;无任何死机或长时间挂起现象。实际跑下来,除了可编程电源切换时那 3 次错误,其他时间都很稳定。温度循环中,因为在标定表里做了温漂补偿,极值误差最终控制在 ±2.1mV 以内,满足设计要求。

拷机通过以后,我还做了连续 7 天的裸机压力跑测,不进上位机,只看板子上的 LED 指示是否正常。这个测试主要是验证 FPGA 配置是否会丢、ADC 是否会被“跑飞”。结果是稳定的。到这里我才敢说,这套 adc1118 的 FPGA 控制方案已经达到量产状态。

6. 常见问题排查与实战心得

6.1 读回数据全是0或全是F:排查SCLK/CS时序

如果读回来的数据全是 0 或全是 0xFFFF,大概率是 SPI 时序不对。先别怀疑芯片坏了,用示波器同时抓 SCLK、DIN、CS 和 DOUT,看 CS 拉低后 SCLK 是否正常翻转;再看你的 DIN 数据在 SCLK 上升沿时是否已经稳定。adc1118 要求主机在 SCLK 上升沿前把数据准备好,我习惯用 SCLK 下降沿更新 DIN,上升沿由 ADC 采样,这样稳定度最高。

还有个常见原因是 CS 拉高的时机不对。如果 CS 在最后一个 SCLK 上升沿之前就拉高了,芯片会认为通信被中断,DOUT 不再输出数据,所有位会变成高阻或保持原电平。我在状态机里专门验证过,必须等第 16 个 SCLK 下降沿之后再拉高 CS,并且拉高前最好把 DOUT 的数据采样完毕。

6.2 数据随机跳变:检查地回路与参考电压

出现随机跳变往往是硬件问题,第一嫌疑是地线。如果 ADC 的数字地和模拟地没有单点连接,或者连接点离芯片太远,DOUT 上的切换噪声会通过地电阻耦合到输入端。我在产品里把 adc1118 的地引脚直接连接到模拟地,并用 0 欧姆电阻与数字地单点汇合,跳变立刻减少。

第二个嫌疑是参考电压。如果用外部参考,要检查参考源是否有足够的去耦电容。如果是内部参考,就检查 VDD 的纹波,实测用开关电源直接供电时,纹波高达 30mV,读数的低 3 位会一直跳。换成 LDO 以后,纹波降到 2mV 以内,跳变明显改善。

6.3 单次触发读数是旧的:别忽略“转换状态”标志

在单次转换模式下,如果启动命令发完,立刻读数据,你会得到上一次的转换结果,也就是“旧的”数据。因为新转换还在进行中,数据寄存器还没更新。正确做法是发完启动命令后,等待数据手册上规定的转换时间(比如 128SPS 对应约 7.8ms),再发起读命令。或者,读回来的最高位是无效标志,如果为 1,说明数据还没好,需要再等一下,直接丢弃这一帧并重新发送读命令。

我见过不少同学在这里踩坑,写了整整一页代码在等“一片空白的延时”,最后发现根本问题是没有检查芯片的状态位。在 FPGA 里,我更推荐用状态机轮询:先发启动命令,然后进入等待状态,直到收到有效的转换完成标志。这样时间利用率更高,也不会因为固定的延时算错而产生偶然的读旧值。

6.4 最后提醒:PCB布局和走线不是玄学

这一部分不算是“问题”,但我觉得值一个告诫。很多嵌入式工程师习惯“先把板子跑通了再说”,可 ADC 这种模拟器件对布局非常敏感。我的建议是,adc1118 尽量靠近传感器接口,模拟输入线短而粗,SPI 信号线要遵循“地平面完整”原则,不要在它下面走线切割。另外,给 ADC 的电源单独加磁珠或 LDO,会比所有芯片共用一个电源好得多。我实测过,把 adc1118 的电源从公共 3.3V 改为 LDO 单独供电之后,原本通过数字逻辑耦合进来的高频噪声彻底消失了。这不算玄学,这就是信号完整性里最基本的电源隔离。

拷机测试再久,也不如从一开始就把硬件底子打好。FPGA 代码上的问题大多能改,但 PCB 上的缺陷往往要改板才能解决,代价大得多。

我个人在实际操作中还有一个体会:FPGA 控制 adc1118 的技术难度,真的不是那个 SPI 时序,而是怎么用示波器去观察每一根线的实际波形,以及怎么设计一个足够“脏”的拷机环境来暴露隐藏问题。如果你能在这个项目里把这两关撑过去,后面换用其他串行 ADC,基本就是换一个配置字的事。这里分享的所有细节,都是我在这块板子上亲手验证过的。希望你的 adc1118 项目,也能少走几步弯路,一次拷机通过。

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

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

立即咨询