ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ADC采样精度的几个隐形杀手

ADC采样精度的几个隐形杀手

前阵子手上有个项目,板子用的是 imx6ull,外挂一颗 12 位的 ADC(型号就不点名了,SPI 接口,最高 1Msps),要采一路 0~5V 的传感器信号,做温度监控。按理说 12 位,参考电压 3.3V,理论分辨率 3.3/4096 ≈ 0.8mV,算下来精度挺够用的。

结果实测出来的数据,跳动得厉害。同一个稳定输入,采 100 个点,最大值和最小值能差出 40 多个 LSB,换算成电压差不多 30 多 mV。这还只是静态输入,动起来更没法看。

我一开始以为是传感器本身噪声大,换了个稳压源直接灌电压,还是跳。又怀疑是 SPI 时序问题,拿逻辑分析仪抓波形,时序干干净净。折腾了小半天,才意识到问题不在"采",而在"采之前"和"采之后"。

今天就把我踩过的这几个坑捋一遍,都是那种不显眼、但真能把精度吃掉的隐形杀手。

一、相关知识点

先把这个 ADC 的基本情况说清楚,后面才好展开。

这颗 ADC 是逐次逼近型(SAR),12 位,内部采样保持电容大概几 pF 量级,输入阻抗不算高。数据手册里写了一句很关键的话:建议源阻抗小于 1kΩ。这句话我当时扫了一眼就过去了,后来才知道这是第一个坑的根源。

再一个概念是有效位数(ENOB)。12 位是标称分辨率,但实际能用的位数往往要打折。ENOB 才是你真正能信的数。一个 12 位 ADC,如果 ENOB 只有 9 位,那后 3 位基本就是噪声,跳来跳去很正常。

还有参考电压。很多人默认 VREF 就是电源电压,稳得很。其实 VREF 上的任何纹波、噪声,会 1:1 地反映到转换结果里。VREF 抖 1mV,输出就跟着抖。

最后是数字滤波。采样值不是采完就能用的,尤其低频信号,过采样 + 平均是最便宜有效的降噪手段。

二、解决过程

1、先查源阻抗

我回到原理图,看传感器到 ADC 输入之间串了什么。结果发现中间串了个 10kΩ 的电阻做限流保护,还并了个 100nF 电容到地。

这就坏了。10kΩ 远大于手册建议的 1kΩ。SAR ADC 采样瞬间,内部采样电容要在很短时间内充到输入电压,源阻抗太大,充电不充分,采到的值就偏低,而且每次偏低程度还不一样——这就是跳动的来源之一。

处理办法有两个:一是降低源阻抗,二是加缓冲运放。我先把 10kΩ 换成 1kΩ,实际测试还是不行呀,跳动是小了点,但还有 20 多个 LSB。折腾了大半天才发现,问题不止这一个——那个 100nF 电容和 1kΩ 电阻构成了 RC,时间常数 100μs,而我的采样率是 10ksps,间隔 100μs,电容根本来不及跟上信号变化,反而在动态时拖后腿。把电容改成 1nF 之后,静态跳动降到 10 个 LSB 以内。

2、查参考电压

源阻抗搞定后,还剩 10 个 LSB 左右的跳动。我拿示波器(AC 耦合,20mV/div)量 VREF 引脚,果然看到一条毛刺,峰峰值大概 15mV,频率跟 SPI 时钟对得上。

原因是我图省事,VREF 直接接的 3.3V 数字电源,跟 MCU、SPI 共用。SPI 一通信,电源上就有开关噪声,VREF 跟着抖。

改法:VREF 单独走一路 LDO,输出并 10μF 钽电容 + 100nF 陶瓷电容,就近放。改完再量,VREF 纹波降到 2mV 以内,采样跳动降到 3~4 个 LSB。

这里插一句,很多人喜欢在 VREF 上并大电容,觉得越大越稳。其实要看 LDO 的环路稳定性,有些 LDO 对输出电容的 ESR 有要求,乱并反而会振。我这次是照着 LDO 手册推荐的容值来的,没敢乱来。

3、软件上做平均滤波

硬件改完,静态已经不错了。但实际工况下还是有零星跳点,尤其是电机一启动,干扰就上来了。

软件上加了个简单的中位值平均滤波:连续采 16 个点,去掉最大最小各 2 个,剩下 12 个求平均。代码大概这样:

#defineN16staticintadc_filter(intraw[N]){inti,j,tmp,sum=0;/* 冒泡排序,N 小无所谓 */for(i=0;i<N-1;i++)for(j=0;j<N-1-i;j++)if(raw[j]>raw[j+1]){tmp=raw[j];raw[j]=raw[j+1];raw[j+1]=tmp;}for(i=2;i<N-2;i++)sum+=raw[i];returnsum/(N-4);}

实测输出:

滤波前: 2048 2051 2045 2053 2047 2050 2044 2052 ... 滤波后: 2048 2048 2049 2048 2048 2048 2049 2048 ...

跳动从 ±5 LSB 压到 ±1 LSB。代价是响应变慢,16 个点按 10ksps 算,延迟 1.6ms。对温度这种慢变量完全无所谓,但如果你采的是快速信号,这个滤波就得慎用,或者换成滑动平均。

4、顺手查了下地

最后还发现一个细节:ADC 的模拟地和数字地,我在板子上是单点连的,但连的位置离 ADC 有点远,中间走了段细线。把它改到 ADC 芯片正下方用 0 欧电阻单点连接,又好了那么一点点。

这一步收益不大,但属于"该做对"的事,顺手做了。

三、结果和遗留

三处改完,最终静态跳动控制在 ±2 LSB 以内,动态(电机启停瞬间)最大 ±5 LSB。按 3.3V/4096 折算,大概 ±1.6mV,对这个温度监控场景够用了。

遗留问题也有:我这套改动是在现有板子上飞线验证的,正式版还得改 PCB。另外那个 1nF 采样电容的取值,跟采样率和源阻抗强相关,换颗 ADC 就得重新算,不能照抄。

参考资料主要是这颗 ADC 的数据手册(重点看"Source Impedance"和"Reference Input"两节),还有 TI 那篇讲 SAR ADC 前端设计的应用笔记,网上搜"SAR ADC front-end design"就能找到。感谢写这些文档的工程师,真是省了我不少事。

我这方面也就学了点皮毛,上面这些结论都是在自己板子上实测出来的,换个平台不一定完全适用。有踩过类似坑的朋友,欢迎留言交流,说不定你那个坑我还没遇到呢。


如果这篇对你有用,请扫码关注。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进