说实话,第一次拿到 GC1843 这颗 24bit 立体声差分输入 ADC 的样品时,我第一反应不是兴奋,是怀疑——超小封装、模拟差分输入、数字 I2S 输出,这么小一颗真要扛起 96kHz/24bit 的音频采集,板子设计和软件链路都得重新调教。结果折腾了小半个月,把前端电路、I2S 对接、DMA 缓冲和 24bit 数据拼接这一整条链路全部跑通之后,我才敢说:这颗芯片适合需要高保真音频采集、又不想在板卡面积上妥协的项目。如果你是做便携录音、声学测量、语音唤醒的远场采集,或者想给 MCU 方案补上 Hi-Res 音频输入能力,这篇实录应该能帮你少走不少弯路。后面所有内容都基于我实际跑过的板子和录出来的文件,不搞 Datasheet 复读。
1. 为什么放弃 MCU 内置 ADC,非要外挂这颗音频采集芯片
经常有人问我:STM32 不是自带 ADC 吗,12bit 也够用吧,为什么非要多加一颗芯片、多铺一层电路?这个问题我在做这个项目之前也问过自己。用真实需求算一笔账之后,答案就很清楚了。
1.1 12bit SAR ADC 的短板
STM32 内部那个 12bit SAR ADC,理论量化信噪比大概是 72dB,这个数字怎么来的?20 × log10(2^12),也就是 12bit 位深在理想情况下能分辨的动态范围上限。72dB 什么概念?普通 CD 也只有 96dB 的理论动态范围,现场录音里一个管弦乐团从弱奏到强奏轻松超过 90dB。换句话说,用 12bit 去采声音,小信号直接埋进量化噪声里。
更麻烦的是,内部 ADC 做音频采样时有几个天生的毛病:采样保持电容会引入电荷注入,参考电压 VREF 往往和 MCU 的数字核心共用电源域,芯片内部的地弹和开关噪声会直接耦合进模拟信号。我在一个语音远场采集项目里试过直接用 STM32 内置 ADC 采 MEMS 麦克风,录出来的 50Hz 工频噪声和数字电路辐射噪声叠在一起,后期怎么滤波都救不回来。不是说内部 ADC 没用,而是场景不对——它更适合温度、电池电压这类慢变信号的采集,加上定时器触发和 DMA 确实很好用,但要达到音频级动态范围和失真指标,还是得交给专门的 Sigma-Delta ADC。
1.2 差分输入不是玄学,是抗干扰的硬需求
GC1843 最让我心动的是立体声差分输入。很多人不理解,说麦克风输出明明是单端的,为什么要接两根线?
差分输入的价值在于共模抑制。实际设备里,扬声器的瞬态电流、电源适配器的纹波、数字总线的串扰,都会在地平面上制造电位差。如果是单端输入,这些干扰原封不动进入 ADC 的参考地,最终叠加在采样结果里。而差分输入把信号表示为 L+/L- 两条线上的电压差,两条线同时被抬升的干扰就成了共模信号,会被 ADC 前端的差分放大器直接压掉。我在手持设备上实测过同样的麦克风信号,单端输入底噪比差分输入差了大概 6~8dB,这个差距人耳是能明确感知的“沙沙声”。
代价是接线多两条,但换来的是实打实的底噪改善。你要是做长距离走线、或者设备内部有开关电源,差分输入基本是必选项。
2. 芯片规格与实际选型:看的不是位数,是整套链路
2.1 24bit 到底能装下多少动态
先说个容易误解的点:24bit 分辨率不等于芯片实际性能就一定是 24bit 那么好。ADC 的理论量化信噪比是 6.02N + 1.76dB,24bit 算下来是 144dB,但这是纯量化级的极限,现实中任何音频 ADC 都做不到——模拟前端的热噪声、时钟抖动、电源噪声会先把底噪抬高。
我拿到的 GC1843 这颗,按典型规格看,动态范围大概能做到 100dB 上下,信噪比指标也在这个量级。这个性能对应什么水平?市面上一票百元级录音笔用的主力 ADC 也就是这个档位。实际做出来的文件,24bit/96kHz 下录一段钢琴,低电平的混响尾音能清晰保留下来;同场景换 16bit/44.1kHz,尾巴上的细节就被量化噪声糊掉了。
| 位深 | 理论量化动态范围 | 实际听感场景 |
|---|---|---|
| 12bit | 约 72dB | 勉强听清语音,音乐细节丢失明显 |
| 16bit | 约 96dB | CD 标准,动态够用但低电平有底噪 |
| 24bit | 约 144dB(理论) | Hi-Res 录音,留足后期动态余量 |
选 24bit 的另一个实用理由是调制余量。录音时你不可能永远把增益调到完美,信号一旦偏小,位深不够就直接切掉了低电平细节。24bit 相当于给信号链路留了一个很大的“安全垫”。
2.2 立体声差分接口与引脚规划
GC1843 的典型信号链是这样:每个声道一对差分输入(L+/L-、R+/R-),经过内部 PGA 和 Sigma-Delta 调制器,最后由数字滤波器输出 24bit PCM,通过 I2S 或左对齐格式送给 MCU 或 DSP。芯片对外接口大致包括这些:
- AVDD/DVDD:模拟电源和数字电源,通常分开供电
- VCOM:内部共模电压输出,给输入偏置用的
- MCLK:主时钟,一般按 256fs 或 512fs 输入
- BCLK:位时钟,I2S 总线的同步信号
- LRCK:左右声道帧时钟,频率等于采样率
- SDIN/DOUT:串行 PCM 数据输出
画原理图的时候我习惯先把电源和时钟引脚规划好,再排音频输入。差分输入的两对线尽量对称走线,不要让 L+ 走顶层、L- 穿两层板再回来,这样两个人的走线电感和寄生电容完全不对称,共模抑制会被自己亲手破坏掉。
2.3 超小封装是省空间还是坑
超小封装最大的卖点是省面积,GC1843 这类 QFN 封装的占板空间比传统 DIP/SOP 小一个数量级。但小封装对你焊接、布局、调试的要求是成倍上升的。
QFN 引脚间距经常只有 0.5mm 甚至更小,手工焊接时助焊剂稍微多一点、锡量稍微大一点,就会在引脚间搭桥。中间那个大散热焊盘通常还接地,焊不好会出现两种极端:要么中间焊盘没吃上锡导致地没接牢,要么锡膏挤出来把相邻引脚短路。我的做法是样机阶段用钢网开窗 50% 的锡膏印刷,加热台 280℃ 回流之后,再用热风枪补一轮,最后拿镊子逐个引脚推一下,看有没有回弹,回弹好说明焊点扎实。如果没有钢网条件,就老老实实用 TQFP 转接板调通软件,再落 QFN 大规模量产板。
小封装还有一层隐性优势:引脚到内部 die 的距离短,寄生电感小,对 ΣΔ ADC 这种高精度模拟器件其实更友好——前提是去耦电容必须贴着引脚放,别放远。我见过有人为了布局好看把 100nF 电容放到了 2cm 之外,结果底噪整整上了 10dB。
3. 前端电路与供电设计:决定底噪的 60% 都在这里
芯片选得再好,前端电路画得稀烂也是白搭。我一开始也想偷懒,直接抄评估板,后来发现评估板的布局在两层板上根本复现不了,被迫重新设计了一遍,反而把原理吃透了。
3.1 输入耦合与直流偏置
音频输入通常是交流耦合,因为信号源往往自带直流偏置,不能直接灌进 ADC。耦合电容和芯片输入阻抗组成了一个高通滤波器,截止频率是 f = 1/(2πRC)。比如耦合电容 10μF、芯片输入阻抗 8kΩ,算下来截止频率约 2Hz,对 20Hz 以下人耳几乎听不到的超低频有点衰减,但这是可接受的。我实际用的是 10μF 加 1kΩ 串联电阻的配置,低频响应够用,还能顺便限流保护。
GC1843 内部一般会把输入偏置到 VCOM 这个半电源点位,让信号在 ADC 满量程范围内摆动。这里有个容易忽略的点:VCOM 引脚的去耦电容要足够大,我习惯放 10μF 并联 100nF,否则输入共模电压不稳,直接表现为输出直流漂移。
如果用驻极体麦克风,别忘了它自带的 JFET 需要偏置电阻供电。输入信号幅度也要提前算好——线路电平大概 1Vrms 上下,MEMS 麦克风可能只有几十 mVrms,不做增益匹配的话,24bit 也只是在采噪声。
3.2 供电与去耦的实操参数
音频 ADC 对电源噪声极其敏感,这是我在这个项目里最深的教训。AVDD 不要直接从 MCU 的 3.3V 拉,哪怕它在物理上是相邻引脚也不行,必须用低噪声 LDO 单独供电。我用的是噪声指标在几十 μV 量级的 LDO,前面加磁珠做隔离,后面按 10μF、100nF、1nF 三颗电容并联去耦。三个电容覆盖不同频段:大电解管低频纹波,100nF 管中频,1nF 管高频尖峰,这种组合是音频电路的基本盘。
DVDD 通常可以低到 1.8V,单独一路 LDO,和 AVDD 分开。数字电源噪声再小也是方波开关出来的,跟模拟电源挨在一起必出问题。如果你手头只有一组电源轨,至少要加一个磁珠把数字侧和模拟侧切开。
3.3 接地和布局教训
接地是我最想重点说的事。很多新手喜欢把模拟地和数字地割成两块,结果在高频段愣是做出了一个大天线。音频 ADC 这类混合信号器件,最稳妥的做法是统一地平面,然后在芯片位置附近把 AGND 和 DGND 用星形汇合到一点。模拟输入走线区域上方不要铺数字地、不要走 I2S 高速线,至少留出三倍线宽的间距。
我第一版板子就是在差分输入走线正下方跑了一组数字信号线,实测底噪卡在 -78dBFS 上不去。后来把数字线绕开、完整地平面补回来,同样的芯片底噪掉到 -98dBFS 左右。这个差距在音频里是非常明显的,相当于从“能听但很脏”变成“干净”。
4. STM32 对接实录:I2S 引脚、DMA 缓冲与数据拼包
芯片侧讲完了,说说和 STM32 的对接。这部分踩的坑最多的不是原理,而是寄存器配置和数据的“字节对齐”问题。
4.1 接口信号与主从模式选择
GC1843 输出的是标准 I2S,有 MCLK、BCLK、LRCK、DOUT 这几根线。主从模式我推荐让 MCU 做主机:STM32 产生 MCLK、BCLK、LRCK,ADC 作为从机只吐数据。好处是采样率完全由 MCU 时钟决定,跟后面挂的 DAC、蓝牙音频模块都好同步。反过来让 ADC 做主机也行,但采样率就受限于外部晶振,一旦时钟源不过硬,数据流会产生慢漂移。
接线就是一一对应:MCU 的 I2S 时钟引脚接芯片 MCLK/BCLK,帧同步引脚接 LRCK,接收数据引脚接芯片的 DOUT。五根线,没有握手信号,协议本身不复杂,复杂的是时钟对不对。
4.2 I2S 外设配置要点与时钟树
用 STM32F4 系列举例,I2S 外设挂在 SPI 模块上,支持 16bit、24bit、32bit 数据长度。GC1843 输出 24bit 数据,但 I2S 协议里一个声道时隙往往是 32bit,所以要把 CHLEN(通道长度)设成 32bit、DATLEN(数据长度)设成 24bit。这个组合很多教程没讲透,直接用默认 16bit 去收,数据会错位,出来的音频是高频噪声。
时钟树是重点中的重点。96kHz 采样率对应 MCLK = 256 × 96kHz = 24.576MHz,BCLK = 64 × 96kHz ≈ 6.144MHz(左右双声道、每帧 32bit)。如果 MCU 的主晶振是 8MHz,PLLI2S 无论如何也得不到干净的 24.576MHz——除出来是个无限小数,时钟抖动直接变成采样噪声。所以音频项目最省心的方案是直接放一颗 24.576MHz 的有源晶振,或者用独立的音频时钟发生器。CubeMX 虽然能强行配出近似频率,但我实测那块的底噪会明显变差。
配置接口我用 HAL 库:设置 AudioFrequency = 96000,Standard = I2S_STANDARD_PHILIPS,DataFormat = 32bit,然后开 DMA 接收。这里注意,DMA 接收长度是按 32bit 字为单位算的,别按字节算,否则缓冲区长度差四倍,溢出了你自己都找不到原因。
4.3 DMA 乒乓缓冲与 PCM 数据组装
24bit/96kHz 立体声的数据吞吐量有多大?96000 × 2 声道 × 4 字节(按 32bit 时隙)≈ 768KB/s。这点带宽对 DMAC 不是事,但对缓冲区和存储介质有要求。我采用的 DMA 是一圈 2048 个字,用半传输中断和传输完成中断做乒乓处理:上半区在处理,下半区在接收,互相不打架。
收到原始数据后要做一次“拆包”:I2S 帧里的 24bit 数据是左对齐的,也就是有效位在 32bit 的高 24 位。取数据时要先右移 8 位,再按小端序拆成三个字节存进 WAV 或者 PCM 流:
uint32_t raw; int32_t sample24; uint8_t pcm[3]; raw = rx_buffer[i]; sample24 = (raw >> 8) & 0xFFFFFF; // 取低24位有效数据 // 小端模式写入24bit PCM pcm[0] = sample24 & 0xFF; pcm[1] = (sample24 >> 8) & 0xFF; pcm[2] = (sample24 >> 16) & 0xFF;如果想直接转 16bit 存文件,也别直接砍掉低 8 位,最好先做一次抖动处理或者至少用舍入而不是截断,否则低电平信号会有明显的量化台阶感。我自己最终的录音文件是 24bit WAV 或经压缩存 FLAC,后期处理空间大得多。
5. 实测、滤波与文件处理的三级经验
软件链路跑通之后,真正的工作才开始。我从录到第一段音频到确认声音“能听”,中间折腾了三天,主要在做验证和工具链上的事。
5.1 先看波形再调参数
第一次上电别急着拿耳朵听,先录标准测试信号。我的做法是用手机或者信号发生器播放 1kHz 正弦波,音量控制在 -1dBFS 附近,录 5 秒,然后拖进 Python 或者音频软件看 FFT。主要看三样东西:1kHz 主峰是不是干净、附近有没有电源纹波的边带、底噪平台有多高。如果你用的是 CCS 这类 IDE,可以用图形查看器直接看缓冲区的原始波形,确认数据的幅值和极性是否正常。这个步骤十分钟就能发现八成问题,比如接线松动、时钟频率不对、数据全是 0 之类的低级错误。
5.2 数字滤波该做多少
热词里看到“C 语言 ADC 值滤波函数”这种搜索,估计不少朋友是从传感器 ADC 转向音频的。这里必须说清楚:音频信号链路千万不要套用传感器那套滤波逻辑。ΣΔ ADC 内部已经做了抽取滤波,输出的 PCM 是完整信号,你再套一个全局低通平均,只会把瞬态削掉,声音变得又闷又糊。
滤波在音频项目里的正确定位是针对性处理。比如 DC 偏移,用一阶 DC blocker 就够,公式是 y[n] = x[n] - x[n-1] + R × y[n-1],R 取 0.999 左右,只干掉直流不掉有效频段。再比如要去掉固定工频干扰,可以用窄带陷波器。至于那些滑动平均、中值滤波的代码,留给电池电压采样和温湿度传感器就够了,别用在音频上。
5.3 24bit/96kHz 文件的转换坑
录出来的 24bit/96kHz FLAC 文件,想转 ALAC 放移动设备里听,结果转出来要么报错、要么变成 16bit——这问题我遇到过,周围也有不少人栽了。原因大多数不是格式不支持,而是转换工具的默认采样格式是 16bit,或者没有显式指定位深。
用 ffmpeg 转的时候一定要显式指定参数:
ffmpeg -i input.flac -c:a alac -sample_fmt s32p -ar 96000 output.m4a如果还是报错,先用 ffprobe 看看源文件的实际编码格式,有些第三方录音软件会把 24bit 数据包在 32bit 容器里,metadata 写得乱七八糟,转码器解析不到正确位深就罢工了。这类问题跟芯片本身没关系,纯粹是文件格式的“地雷”。
6. 这个项目让我印象最深的三次排障
最后分享三个我实际踩过、而且花了很久才定位的问题,每一个都值得你写进 checklist。
6.1 相位接反的诡异现象
有一次录出来的声音怎么听怎么别扭——人声发虚,低频乐器几乎消失了。查遍参数、滤波、时钟全都正常,最后用示波器一对波形才发现:其中一个声道的 L+ 和 L- 接反了。进一步说,如果两个声道都反相,单声道播放时人耳基本听不出来,但左右声道的反相会给混音带来严重的相位抵消,低频直接消失。更隐蔽的情况是只有一个声道接反,听感像声音“从头顶飘出来”,毫无低频。所以原理图上一定标清 L+/L- 极性,打样前逐路核对差分线的走线,别想当然。
6.2 冷焊与虚焊的排查
小封装 QFN 的另一个坑是冷焊。某天设备上电后 I2S 数据全是 0,但寄存器配置看着全对。我拿示波器量 MCLK、BCLK 都有,LRCK 也有,唯独 DOUT 上是一片死寂。后来用万用表量 AVDD 才发现,芯片的供电引脚和焊盘之间虚接,接触电阻忽大忽小。把芯片拆下来重新植锡、加热台重焊一遍,再推引脚确认回弹,问题立刻消失。教训是 QFN 焊接不要迷信加热台一次成功,必须加目检和回弹测试。
6.3 一个晚上才发现的采样率配置错误
最隐蔽的问题出现在时钟树。当时改过一次 CubeMX 配置,重新生成工程后采样率从 96kHz 悄悄变成了 48kHz,但软件里 AudioFrequency 还写着 96000。结果录音音调整体低了八度,像磁带机慢放。排查到后半夜,拿示波器一量 LRCK 频率——正好是 48kHz,才知道 CubeMX 重新生成时把时钟分频改了。从那以后我每次改配置都会做两步验证:示波器量 LRCK 是不是等于目标采样率,以及 BCLK 是不是等于 64 倍采样率。这两根线是对的,I2S 时序就基本没错。
做音频采集这种项目,最忌的是一味堆芯片参数而忽略了整条信号链路。GC1843 确实给了 24bit 分辨率和差分输入,但录出来的底噪、声场、动态,最终还是由前端电路的每一个焊点、每一颗去耦电容、每一段走线决定的。我个人现在的习惯是:画板之前先规划电源和接地,调板时先用示波器量准时钟,最后才去关心位深和文件格式。顺序反过来,你会在噪声和错位里浪费大量时间。这半个月折腾完,我反倒觉得,做高保真采集最难的不是看懂 Datasheet,而是管住硬件每一个“看起来无关紧要”的细节。