☰
16位ADDA回环实测:正弦幅值对不上,从信号链逐级排查是关键
2026/10/4 7:35:10 网站建设 项目流程

做 16 位 ADDA 回环实测,最常见的困惑不是“能不能通”,而是“为什么对不上”。DAC 输出一个 1 kHz 正弦,代码里查表生成的正弦幅度是 10000 码,本以为 ADC 读回来算出峰值也是 10000 码左右,结果只有 8500 码。第一反应是芯片坏了,换一片还是这样;再怀疑 SPI 读写时序有问题,把示波器接上去看波形,数据又好像没错;最后干脆在采集结果后面乘一个 0.85 的系数,现象“消失”了,可换一台设备又不对。

这不是某一个器件坏了,而是整条信号链里至少有一个环节没有对齐。16 位精度的回环测试,真正的难点不是误差本身,而是定位误差。我更建议先别急着补系数,先把 DA 侧、AD 侧、中间模拟通路拆开验证,找到偏差发生在哪一级,再决定是改硬件、改参数还是改软件。

1. 回环不一致,先别怪芯片,这是信号链问题

1.1 一次回环,叠加了三段误差

很多人把“DAC 输出、ADC 采集、比对数据”理解成一根直线:代码进去,代码出来,中间不应该有任何差异。实际上,一次回环至少经过三段独立环节,每一段都有自己的误差。

第一段是 DA 侧。DAC 芯片要把 16 位数字码转换成电压,这个电压取决于它的参考电压、输出放大器增益、失调、稳定时间。同一个型号的 DAC,不同批次、不同温度下,实际满量程电压都会有微小差异。

第二段是中间模拟通路。DAC 引脚到 ADC 引脚之间通常不只有一根导线,可能还有运放缓冲、RC 滤波、防倒灌电阻、连接器、线缆、PCB 走线。这一段的增益、带宽、阻抗、接触电阻,都会直接叠加到信号上。

第三段是 AD 侧。ADC 输入前端有采样开关和采样电容,采样保持的时间够不够,输入阻抗会不会拉低信号,参考电压是多少,输出数据格式怎么解释,都会影响最终读回来的码值。

所以回环测试真正测的不是“DAC 正常”或“ADC 正常”,而是这三段链路叠加之后的一致性。幅值对不上,意味着至少有一段不是你预期的那样。

1.2 16 位下 1 个 LSB 的物理尺寸,决定了你的容错空间

16 位系统里,一个 LSB 的“物理尺寸”非常小。以 5 V 参考电压为例,1 LSB 约等于 76.3 µV;如果参考电压是 3.3 V,1 LSB 约等于 50.4 µV。

这意味着什么?10 mV 的直流偏移,在 16 位系统里可能造成 130 多个 LSB 的误差。一个 1% 精度的参考电压,配合另一个 1% 精度的参考电压,再加上运放增益的 1% 偏差,整体幅值偏差就能到 3% 到 5%,换算成码值就是几千个 LSB。

所以,“幅值不一样”在 16 位体系里其实是常态,如果每个环节都没有经过实测确认,那才是意外。我们真正要做的是把每一段的实际误差量化出来,而不是默认芯片手册上的理想值。

1.3 为什么“凭感觉乘个系数”是最危险的做法

一批板子测试时发现幅值偏小,就在软件里乘一个 0.85 修正系数,现象立刻消失。这个操作看起来很快,但你会面临几个问题:换一批板子,参考电压偏差漂移,0.85 不再成立;环境温度变化,运放增益漂移,0.85 也不再成立;如果误差不是纯增益误差,而是包含直流偏置,单独乘系数会把偏移也放大或缩小。

更麻烦的是,一旦你习惯了补系数,就会忽略真正的根因。比如采样时间不够导致的幅值下降,它随频率变化,正弦 1 kHz 时偏小,500 Hz 时偏小程度不同,这样一个固定系数完全无法覆盖。定位根因看起来多花几个小时,实际上比后面反复换系数省时间。

2. 四个最容易翻车的环节:格式、参考、通路、时序

2.1 数据格式和极性:看起来对,其实从源头就偏了

先检查最简单、最容易被忽略的一层:数据格式。

16 位 DAC 和 ADC 的输出格式并不统一。有的芯片输出无符号二进制码,0x0000 对应 0 V,0xFFFF 对应满量程;有的则是偏移二进制,或者二进制补码,0x8000 对应 0 V。如果 DAC 是无符号单极性输出,正弦查表要围绕 0x8000 生成,负半周才不会削底;如果 DAC 是双极性输出,正弦查表要围绕 0 生成,套用单极性查表就会在负半周直接截断。

ADC 那边也一样。有些 ADC 输出偏移二进制,有些输出补码。回环比对时,如果两边数据格式不一致,最常见的结果不是幅值成比例缩小,而是直流中点整体偏移。你可能看到正弦的峰峰值差不多,但上下沿不对称,或者最小码值低到了不可能出现的区域。

还要注意字节序和左右对齐。SPI 读回来的 16 位数据,如果高低字节交换,或者左对齐右对齐没处理对,读回来的码值会是完全混乱的。这类问题用恒定码测试最容易暴露:给 DAC 写 0x8000,ADC 读回来如果也是 0x8000,说明格式基本对;如果读回来是 0x0080 之类,先查字节序和移位。

2.2 参考电压:成比例误差的最大来源

如果幅值整体偏小,而且静态码也成比例偏小,第一个要查的就是参考电压。

回环链路里存在两个参考点:DAC 的 VREF 和 ADC 的 VREF。它们共同决定数字码和物理电压之间的换算关系。理想情况下,两者应该相等,或者至少要让 ADC 端的满量程电压和 DAC 端的满量程电压匹配。

换算关系很直接:DAC 输出电压等于 DAC 码除以 65536 再乘以 DAC 参考电压,再乘以模拟通路增益。ADC 读回码等于输入电压除以 ADC 参考电压再乘以 65536。两条式子合并,ADC 回读码和 DAC 输出码之间满足:

ADC 码 = DAC 码 ×(DAC 参考电压 / ADC 参考电压)× 通路增益

如果 DAC 参考是 2.5 V,ADC 参考是 3.0 V,通路增益是 1,那么回读码就是输出码的 0.833 倍。这就是“幅值少了 16.7%”的典型来源。

排查时不要只看原理图上的标称值,要用万用表实测 DAC 参考引脚和 ADC 参考引脚的对地电压。很多板卡为了省电,参考电压经过一个开关、一个滤波电阻甚至一个二极管才到芯片,负载变化时电压会偏。还要确认两个参考是否真的同源,即使同源,走线电阻和地平面压差也可能造成几十毫伏差异,在 16 位系统里就是几百个 LSB。

2.3 模拟通路:一个 RC 就够让你的幅值“蒸发”15%

如果参考电压实测没有问题,接下来查模拟通路。

最常见的是 DAC 和 ADC 之间加了 RC 低通滤波。滤波器设计时的截止频率可能只考虑了抗混叠,没有考虑正弦频率落在幅频特性曲线上。比如 1 kHz 正弦,R 取 1 kΩ、C 取 100 nF,截止频率约 1.59 kHz,1 kHz 处理论衰减约 84%,也就是幅值直接掉 16%。这不是芯片问题,是滤波器本身的幅频特性。

然后是运放缓冲。有些板子 DAC 输出能力不够,会加一级运放做缓冲,如果运放接成了同相放大结构,增益是 1 + Rf/Rg。两个电阻用 1% 精度,增益误差最高可以到 2% 左右。看起来不多,但在 16 位回环里,这已经是上千个 LSB 的误差。

还有一个容易被忽略的点是 ADC 输入阻抗。很多 SAR 型 ADC 的输入不是高阻,而是等效为一个采样开关加一个采样电容。如果前端输出阻抗太高,采样电容在采样窗口内没有完全充满,读回来的电压就偏低。源阻抗越高、采样时间越短、信号频率越高,误差越明显。这种情况看起来像增益误差,但它不是常数,而是随频率变化。用低输出阻抗的运放做缓冲,比单纯在软件里补系数可靠得多。

2.4 采样时序和稳定时间:幅值波动常常是这里的问题

如果幅值不是稳定偏小,而是忽大忽小,或者前几个点明显不对,就要看时序。

DAC 写完 SPI 帧,输出不是瞬间稳定的。不同型号的 16 位 DAC,稳定到 1 LSB 可能需要几微秒到十几微秒。如果 DAC 更新后立刻触发 ADC 采样,ADC 抓到的可能是一条还在爬升的曲线,看起来就是幅值偏低且随机。

ADC 采样保持也有最小采样时间要求。为了追求采样率,把采样窗口压得太短,内部采样电容没充满,读回来的码会稳定偏低,而且信号频率越高越明显。在某些 ADC 里,这个问题会表现为幅值和信号频率强相关。

连续正弦回环时,还要注意 DAC 更新时刻和 ADC 采样时刻是否同步。如果两边靠软件延时错开,采样点落在正弦不同相位,用峰峰值估算幅值时,这一轮采样可能没采到真正峰值,下一轮又采到,就会造成幅值跳动。更稳妥的做法是用定时器固定触发节奏,让 ADC 采样间隔严格等间隔,这样后续的 RMS 或 FFT 计算结果才稳定。

3. 正弦幅值对不上,先按现象分类,再决定往哪查

3.1 幅值成比例偏小,静态码也跟着偏

这是最常见的一种:DAC 输出幅值 10000 码的正弦,ADC 读回来按换算系数算出来是 8500 码,而且 DAC 输出 0x4000、0x8000、0xC000 这些恒定码时,ADC 读回码和理论值的比例也同样是 0.85。

优先排查顺序:DAC 参考电压、ADC 参考电压、中间通路增益、RC 滤波器衰减。先用万用表实测两个参考电压,计算比例是否接近 0.85;再看通路里有没有串电阻、有没有滤波器;最后看 ADC 输入阻抗和采样时间是否不足。如果比例和理论计算完全吻合,基本可以断定是某个环节的增益没有达到 1。

3.2 幅值没问题,但直流中点不对

如果正弦的峰峰值和预期一致,但整体往上或往下偏,比如正弦峰值从 40000 变成了 43000,谷值从 25536 变成了 28536,峰峰值没变,只是中心漂了。

先查数据格式解释。ADC 输出偏移二进制,你按补码解释,读回来的整数会凭空多一个直流偏置。再查信号链路里有没有电平搬移电路,比如双极性信号转单极性 ADC 输入的加法电路,搬移基准电压不对,直流中点就偏。最后查 ADC 本身的失调误差,有些 ADC 的失调可以到几百个 LSB,需要用校准寄存器或软件归零。

3.3 正负半周不对称,甚至单边削顶

这种情况说明信号已经碰到某个环节的线性范围边界。

DAC 如果是单极性输出,0x0000 对应 0 V,负半周在电路上根本不存在,查表数据一旦低于 0,输出的就全是 0,波形底部被削平。反过来,如果 ADC 输入范围是 0 到 VREF,而 DAC 输出的是双极性 ±VREF,负半周直接被 ADC 前端限幅。

检查时直接打印 DAC 的码值下限和 ADC 读回码值下限。如果 DAC 码值一直大于 0,但 ADC 读数在低端饱和,说明 ADC 输入范围不够。如果 DAC 码值本身出现负数,说明查表生成或者 DAC 数据格式转换有 bug。

3.4 幅值波动、峰值忽大忽小,先怀疑噪声和计算方式

最后一种比较隐蔽:每次采集算出来的幅值都不一样,甚至同一个文件里,用不同段数据算出来的峰峰值差别很大。

优先怀疑两个方向。一是噪声:参考电压纹波、地平面噪声、电源耦合,在 16 位精度下都会显示出来。二是计算方式:用“最大值减最小值”算峰峰值,对偶发毛刺特别敏感,一个尖峰就能把峰峰值抬高几十个 LSB。正弦波如果带一点谐波或者噪声,峰峰值也不能准确代表基波幅值。

所以动态回环里,我很少直接看峰峰值,而是先去掉直流分量,再算 RMS,纯正弦下峰值等于 RMS 乘以根号 2;或者直接做 FFT,取基波频点的幅度。这样能把目标信号和噪声、谐波分开,幅值对比才有意义。

4. 推荐的四步实测流程:分侧直流、静态回环、动态回环、线性修正

4.1 第一步:DAC 输出定码,先确认 DA 自己没问题

在做任何回环之前,先把链路拆开。

给 DAC 写入几组固定码,比如 0x0000、0x4000、0x8000、0xC000、0xFFFF,用万用表在 DAC 输出引脚直接量电压。理论值很容易算:码值除以 65536,乘以实测的 DAC 参考电压。如果实测电压和理论值差得很远,问题在 DAC 配置、参考电压或 DAC 后端负载;如果电压正确,DAC 这一侧是可信的。

这一步不会太久,但能把后续排查范围缩小一半。

// 伪代码:DAC 输出恒定码,这一步只看 DA 输出电压 uint16_t codes[] = {0x0000, 0x4000, 0x8000, 0xC000, 0xFFFF}; for (int i = 0; i < 5; i++) { dac_write(codes[i]); delay_ms(50); // 等 DAC 输出稳定 // 此时用万用表测量 DAC 输出引脚电压 }

4.2 第二步:ADC 输入定压,再确认 AD 自己没问题

然后单独验证 ADC。用一个已知直流电压接到 ADC 输入引脚,或者把之前已经确认过的 DAC 输出作为信号源接进去,读取 ADC 码,和理论码值比较。理论码值等于输入电压除以实测的 ADC 参考电压,再乘以 65536。

如果 ADC 这侧单独验证也通过,那 DAC 和 ADC 各自没问题,回环对不上就一定是中间通路、时序或者数据计算方式的问题。这一步非常重要,因为它直接回答了一个关键问题:到底该修哪一边。

4.3 第三步:静态扫码,画一条“DAC 码 → ADC 码”传递曲线

把 DA 和 AD 接回真实回环路径,做静态扫描。DAC 从 0x0000 开始,按固定步进输出,每次等稳定后读一次 ADC,记录一组“输出码、回读码”。

扫完之后做线性拟合,得到两个关键参数:

  • 斜率 k:代表 DAC 参考电压、ADC 参考电压、模拟通路增益的综合影响。
  • 截距 b:代表系统里累积的直流偏移。

如果拟合残差很小,说明系统接近线性,后面用软件修正就很简单。如果残差很大,比如某些码段偏差特别明显,说明不是简单的增益偏移问题,可能要查电源纹波、参考电压稳定性或者器件本身的 INL。

# 伪代码:用线性拟合求增益和偏移 import numpy as np # out_codes: DAC 输出码 # in_codes: ADC 回读码 k, b = np.polyfit(out_codes, in_codes, 1) print(f"增益系数 k = {k:.6f}, 偏移 b = {b:.2f} LSB")

4.4 第四步:正弦动态回环,用 RMS/FFT 算幅值,而不是只看峰峰值

静态链路确认之后,再上正弦信号。

正弦查表用中点做中心,幅度不要拉满,建议 30% 到 40% 满量程,避免碰到边缘非线性区。采集一段等间隔采样数据,去掉直流均值后算 RMS,正弦峰值约等于 RMS 乘以根号 2。如果系统里有噪声和谐波,更推荐做 FFT,取基波频点的幅值,计算公式是 2 倍的频谱幅度除以采样点数。

# 伪代码:采集一段回环数据,用 RMS 和 FFT 分别计算幅值 import numpy as np # data: ADC 采集到的原始码值数组 dc = np.mean(data) ac = data - dc rms = np.sqrt(np.mean(ac ** 2)) peak_rms = rms * np.sqrt(2) # 纯正弦下的峰值 spectrum = np.fft.rfft(ac) peak_fft = 2 * np.abs(spectrum[fund_bin]) / len(data) # 基波幅值

这里要说明一下,RMS 和 FFT 计算的是交流分量的幅值,和 DAC 查表里的正弦峰值码值做对比时,两边要用同一个定义。DAC 侧输出峰值码如果是 10000,那么回读码的期望峰值也应该写成同样含义的码值,而不是直接拿电压数值和码值比。

5. 什么时候能用软件修正,什么时候必须改硬件

5.1 两点校准:增益误差和偏移误差怎么拟合

如果静态回环扫出来的传递曲线接近直线,且残差在可接受范围内,软件修正就是有效的。

最简单的做法是两点校准。选取 DAC 输出码的两个点,比如 0x2000 和 0xE000,分别读回 ADC 码值,算出斜率 k 和截距 b。之后软件里做反向换算,把目标 ADC 码转换成 DAC 应该输出的码值,再写入 DAC。

# 伪代码:软件校准时,把目标 ADC 码转成 DAC 码 dac_code = int((target_adc_code - b) / k) dac_code = max(0, min(65535, dac_code)) dac_write(dac_code)

但要注意,这个修正只在系统保持线性的前提下成立。校准时的温度、参考电压、负载情况如果和实际使用时差别很大,修正系数也要跟着变。批量生产时,最好每块板都单独校准并将系数写回非易失存储,而不是所有板卡共用一套固定系数。

5.2 软修不了的三类情况

软件修正看起来很万能,但有三类情况不建议硬修。

第一类是削顶和饱和。信号已经超出 DAC 或 ADC 的线性范围,波形被切掉了,丢失的信息无法通过乘法或加法恢复。这种情况下要调整信号幅度或电平搬移电路。

第二类是强非线性。如果静态扫出来的传递曲线弯弯曲曲,残差有几十个甚至上百个 LSB,一个线性修正公式根本不够。需要先检查参考电压是否稳定、电源纹波是否过大、PCB 地回路是否合理,而不是增加一个二次项拟合去掩盖真正的问题。

第三类是频率相关误差。ADC 采样时间不够、源阻抗太高、滤波器带宽不足,都会造成幅值随频率变化。软件里一个固定增益系数,只能让某一个频率点“看起来对了”,换一个频率又偏。这类问题必须从模拟前端或采样配置下手。

5.3 把回环测试固化成可重复的自动化流程

回环测试不应该只做一次。建议把它写成可以重复运行的脚本或者测试用例,每次硬件改版、换料、量产抽检时都跑一遍。

完整流程应包括:DAC 恒定码测试、ADC 恒定码测试、静态扫点并拟合、正弦采集并计算 RMS/FFT 幅值、输出校准系数。把每次测试结果存成文件,方便对比不同板卡、不同温度、不同批次之间的差异。这个习惯看起来多花一点时间,但在长期维护阶段能省下大量排查成本。

5.4 16 位回环长期稳定的几点工程建议

最后给几条工程层面的建议,体感会比调试代码更影响结果:

  • 参考电压要用低噪声 LDO 或者专用基准源,并做好去耦,开关电源直接给 VREF 供电在 16 位系统里很容易出问题。
  • 模拟信号走线要远离数字信号和 SPI 时钟线,地平面尽量完整,不要在模拟路径上制造大电流回路。
  • DAC 和 ADC 之间如果必须加驱动电路,用低输出阻抗的运放,保证 ADC 采样电容能快速充电。
  • SPI 时序要留足裕量,SCK 频率不要拉满芯片上限,CS 建立时间和保持时间按数据手册要求设置。
  • 正弦回环的动态测试中,DAC 更新和 ADC 采样尽量由硬件定时器触发,避免软件延时导致相位抖动。

回到最初的问题:16 位 ADDA 回环正弦幅值不一样,绝大多数情况下都不是芯片坏了,而是信号链路里某个环节没有对齐。处理顺序应该是先分侧验证直流,再静态扫点,再做动态正弦计算,最后根据拟合结果决定要不要软件修正。如果能养成这个习惯,你会发现自己不再需要猜“乘多少才对”,而是直接知道该去修哪里。

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

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

立即咨询