从16位到24位的“无中生有”:硬核拆解DABL7606采集卡的DMA高速读取与过采样黑科技
前言
大家好,我是ZLinear的硬件工程师。
在之前的系列博文中,我们从模拟前端的零漂移放大器,一直拆解到ADC芯片的序列器与SPI时序。后台有做工控和上位机开发的读者问了一个非常“底层”的问题:
“张工,你们的DABL7606采集卡标称分辨率是‘16bit/24bit双模式’,这我就不懂了。ADC芯片的物理分辨率是固定的,16位怎么摇身一变就成24位了?另外,8通道同步采样时,那么大的数据吞吐量,单片机是怎么做到一个字节不丢地传到上位机的?”
这个问题直击数据采集卡的“心脏”!物理分辨率靠芯片,有效分辨率靠算法;数据不丢靠DMA,实时上传靠多线程。
今天,我们继续“无公式、纯工程”的风格,翻开《数据采集卡DABL-7606用户手册》和《7606代码分析》文档,硬核拆解DABL7606底层的AD7606驱动逻辑、SPI+DMA零开销读取机制,以及那个让人惊叹的“16位扩展到24位”过采样黑科技。
一、核心采集函数:CONVST引脚的“跷跷板”游戏
AD7606这颗芯片要做到8通道同步采样,内部其实有8个独立的采样保持器(S/H)。要让它们同时“咔嚓”拍下快照,全靠CONVST(转换启动)引脚的一个脉冲。
底层驱动代码中,核心采集函数非常精简,但其时序要求极其严苛:
void ad7606_startConvert(void) { // 1. 拉高CONVST引脚 HAL_GPIO_WritePin(AD_CONVST_GPIO_Port, AD_CONVST_Pin, GPIO_PIN_SET); // 2. 延时 ≥40ns (168MHz主频下约7个空操作周期) __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP(); // 3. 拉低CONVST引脚,触发内部采样保持 HAL_GPIO_WritePin(AD_CONVST_GPIO_Port, AD_CONVST_Pin, GPIO_PIN_RESET); }工程拆解:
- 为什么是40ns?Datasheet规定CONVST高电平脉宽必须大于40ns,168MHz的STM32执行一条NOP大约需要6ns,7条NOP刚好留出安全余量。
- 拉低瞬间发生什么?8个通道的采样保持开关同时断开,输入电压被冻结在保持电容上。随后芯片内部的MUX依次把这8个通道的电压送到ADC核心进行逐次逼近比较。
- BUSY信号去哪了?转换开始时BUSY会拉高,大约3.2μs后转换完成,BUSY自动拉低。我们在BUSY的下降沿触发外部中断,进入下一步的DMA读取。
二、DMA高速数据读取:让CPU“躺平”的秘密
8通道×16位 = 16字节。如果用CPU软SPI一位一位去读,不仅要占用大量CPU时间,还极易因中断抢占导致丢数据。DABL7606的方案是:EXTI外部中断 + SPI DMA。
在外部中断服务程序(EXTI2_IRQHandler)中,只有一句核心代码:
// 通过SPI1的DMA自动读取8通道×16位 = 16字节数据 HAL_SPI_Receive_DMA(&hspi1, (uint8_t*)ad7606Data, 8);工程拆解:
- 零CPU开销:DMA(直接存储器访问)控制器接管了SPI外设到内存(SRAM)的数据搬运工作。CPU在发出这条指令后就可以去干别的事了(比如跑通信协议栈),完全不需要参与每一个字节的读取。
- 时间就是生命:这是整个系统中时间要求最严格的ISR(中断服务程序)。在100KSPS的采样率下,每10μs就会来一次中断,必须在下一个采样周期到来前完成16字节的读取,DMA是唯一的解法。
- 数据格式:读回来的数据存入
int16_t ad7606Data[8]数组,范围是±32768,对应±满量程电压(±5V或±10V)。
三、16位到24位的“无中生有”:过采样黑科技
重头戏来了。AD7606物理上是16位ADC,怎么在软件上变成24位?答案就在《7606代码分析》文档中总结的:256点累加不除,有效位数 ENOB ≈ 19-20位。
这到底是怎么做到的?
1. 理论基础:噪声也可以是“朋友”
根据信号处理理论,每增加4倍过采样率,分辨率可以提升1位(信噪比提升6dB)。如果我们对信号进行256倍过采样($4^4=256$),理论上就可以多出4位分辨率,从16位变成20位!
2. 工程实现:256点滑动平均与累加
在DABL7606的固件中,实现方式非常巧妙:
- 滑动平均滤波:对连续256个采样点求平均值。这一步把高频噪声削平了,信噪比提升了约24dB。
- 精度扩展(累加不除):正常平均是“累加后除以256”(右移8位)。但如果我们不除呢?16位的数据累加256次,最大会变成 $16位 + 8位 = 24位$!
这就是“16bit变24bit”的核心魔法。我们用一个更大的uint32_t容器去装这个累加值,保留了那些原本会被移位移掉的“小数位”(次 LSB信息)。
3. 代价是什么?
天下没有免费的午餐。256点过采样的代价是有效采样率下降。
- AD7606硬件最高能跑200KSPS,如果做256倍过采样,实际输出的有效24位数据率会降到 $200K / 256 \approx 781.25Hz$。
- 这就是为什么手册里写“24位模式采样速率:10Hz”的原因——为了极致的精度,我们牺牲了速度。对于温度、压力、应变等缓变信号,这招简直完美。
四、数据洪流的安全坝:SRAM/Flash/FRAM三级存储
有了高速的DMA和聪明的过采样算法,数据源源不断地产生。如果上位机突然卡顿或者网线断了,数据怎么办?DABL7606设计了一套“三级存储”架构:
| 存储介质 | 容量/类型 | 核心作用 | 读写特点 |
|---|---|---|---|
| SRAM | 8MB | 实时波形缓存、连续记录仪 | 速度极快,断电丢失,用于DMA双缓冲 |
| FLASH | 32MB | 长期离线历史数据记录 | 容量大,断电保存,按页擦写 |
| FRAM | 铁电存储 | 设备参数、标定系数、掉电保护 | 无限次擦写,按字节读写,像RAM一样快的ROM |
在RTOS(RT-Thread)的调度下,系统会优先把DMA搬来的数据塞进SRAM的环形队列。一旦SRAM快满了,后台线程会把数据搬进Flash长久保存。而FRAM则时刻保存着当前的量程、校准系数、IP地址等关键参数,确保哪怕突然断电,下次上机依然记得“我是谁”。
五、不仅能“采”,还能“发”:DDS与PWM的联动
DABL7606不只是一个被动记录员,它还能主动输出控制信号。
在ADC中断服务程序中,有这样一句注释:
// 方式2: 也可在此处直接触发DDS DAC更新// ddsDac_tim_task(); // ADC数据就绪 → 更新DAC输出
这就是所谓的闭环控制。系统不仅通过ADC采集传感器的反馈值,还通过内部的DDS(直接数字频率合成)算法,配合10位PWM RC低通滤波器DAC,实时输出4通道0-5V的模拟控制电压。
相位累加器+查表法的DDS合成,让频率分辨率小于0.1Hz。这意味着你可以用这块卡,不仅采集电机转速,还能直接输出一个极其平滑的低频正弦波去驱动执行机构。
六、总结:硬件是骨架,算法是灵魂
| 技术点 | 实现方式 | 性能指标 |
|---|---|---|
| 高速ADC采集 | SPI1 + DMA + 外部中断 | 100KSPS, 8通道同步,CPU零开销 |
| 过采样滤波 | 256点滑动平均 | 信噪比提升 ~24dB |
| 24位精度扩展 | 256点累加不除 | 有效位数 ENOB ≈ 19-20位 |
| 非易失存储 | FRAM + Flash分层 | 参数掉电保存, 数据长期记录 |
| 校准系统 | 两点线性插值 + 系数修正 | 精度可达 0.1% FSR |
写到这里,我希望大家明白一件事:一块优秀的工业数据采集卡,绝不是把几颗芯片拼在一起那么简单。它是硬件架构(CONVST时序、DMA流)、软件算法(过采样扩展、DDS合成)和系统设计(RTOS调度、三级存储)的完美融合。
16位到24位的跨越,不是魔术,是对底层数据流的极致把控。ZLinear把这套从底层驱动到过采样算法的代码全部开源,就是希望你在做高精度采集系统时,不再只停留在“调库”的阶段,而是真正看懂数据在芯片之间是如何流淌的。
如果你在实现过采样算法时遇到了数据抖动,或者对DMA双缓冲的切换有疑问,欢迎在评论区留言交流。我们一起把数据采集这门手艺,练到极致!