在工业数据采集、电力监控、振动分析等场景中,高速、多通道、同步采样 是核心需求。传统 MCU 方案往往面临 CPU 占用高、数据吞吐不足的瓶颈。
今天分享一个基于睿擎派 RC3506 的完整方案——利用 FlexBus 并行总线 驱动 AD7606 ADC,配合 DMA 数据搬运,实现 8通道高速同步采样,CPU 几乎零介入。
通过串口将采集数据发送至 VOFA+ 上位机,波形实时显示:

8通道同步采样波形展示(通道1-4: ±5V,通道5-8: ±10V)
AD7606 是 ADI 推出的一款多通道同步采样 ADC,堪称工业数据采集的"瑞士军刀":
特性 | 参数 |
通道数 | 8通道同步采样 |
分辨率 | 16位 |
采样率 | 最高 200kSPS(无过采样) |
输入范围 | ±10V 或 ±5V(可选) |
接口 | 并行/串行可选 |
数据格式 | 16位补码 |
典型应用场景:
电力系统监测(谐波分析、电能质量)
工业自动化(PLC、伺服控制信号采集)
振动分析(多轴加速度传感器)
声学检测(多通道麦克风阵列)
传统的 ADC 采集方式存在两大痛点:
1. CPU 轮询等待:CPU 不断查询 BUSY 信号,采集期间无法处理其他任务
2. 数据搬运耗时:每个采样点都需要 CPU 执行多次 IO 操作,占用大量 CPU 周期
以 200kSPS 采样率为例:
每秒采样次数:200,000 次
每帧数据量:8通道 × 2字节 = 16字节
数据传输率:200,000 × 16 = 3.2MB/s
如果全靠 CPU 轮询和拷贝,负载会非常高。而 FlexBus + DMA 方案:
DMA 自动搬运:数据从 FlexBus 直接传输到内存,CPU 零介入
硬件定时器触发:采样时机由硬件定时器精确控制,抖动极小
中断通知:一帧数据采集完成后,通过事件机制通知 CPU 处理


扩展板即将上架淘宝店,敬请期待!
关键信号说明:
CONVST A/B:启动转换信号,同时触发 8 通道同步采样
BUSY:转换进行中指示,转换完成后拉低
CS + RD:读取数据控制信号
OS0-OS2:过采样倍率配置(200kSPS ~ 3.125kSPS)
RANGE:输入范围选择(±5V 或 ±10V)
整个驱动分为三层:

采样流程

struct ad7606_device{ struct rt_adc_device adc_dev; // 继承 ADC 设备 rt_adc_device_t fb_dev; // FlexBus ADC 句柄 struct rt_device *dev; // 平台设备 struct rt_dma_chan *dma_chan; // DMA 通道
// GPIO 引脚定义 rt_uint32_t cs_pin, rd_pin, rst_pin; rt_uint32_t busy_pin, range_pin; rt_uint32_t cva_pin, cvb_pin; rt_uint32_t os0_pin, os1_pin, os2_pin;
// 配置参数 rt_uint32_t oversampling; // 过采样倍率 rt_uint32_t range; // 输入范围
// 采样状态 rt_sem_t data_sem; // 数据就绪信号量 rt_thread_t sample_tid; // 采样线程 volatile rt_bool_t data_ready; // 数据就绪标志
// DMA 配置 rt_bool_t dma_enable; rt_uint16_t *dma_data; // DMA 源缓冲区 struct rt_adc_dma_cfg dma_cfg; // DMA 目标配置};
采样时机由硬件定时器精确控制,避免了软件延时带来的抖动:
static rt_err_t ad7606_hwtimer_timeout(rt_device_t dev, rt_size_t size){ struct ad7606_device *ad_dev = (struct ad7606_device *)dev->user_data;
if (ad_dev && ad_dev->enabled) { // 拉低 CONVST A/B,启动同步采样 rt_pin_write(ad_dev->cva_pin, PIN_LOW); rt_pin_write(ad_dev->cvb_pin, PIN_LOW); rt_hw_us_delay(1); // 脉宽至少 1μs rt_pin_write(ad_dev->cva_pin, PIN_HIGH); rt_pin_write(ad_dev->cvb_pin, PIN_HIGH); } return RT_EOK;}
采样频率配置(通过设备树或源码设置):
过采样 | 实际采样率 | 说明 |
无 | 200kSPS | 最高速,适合高速信号 |
×2 | 100kSPS | 2倍过采样,降低噪声 |
×4 | 50kSPS | 4倍过采样 |
×8 | 25kSPS | 8倍过采样 |
×16 | 12.5kSPS | 16倍过采样 |
×32 | 6.25kSPS | 32倍过采样 |
×64 | 3.125kSPS | 最高精度 |
BUSY 信号下降沿触发中断,表示一次转换完成:
static void ad7606_busy_isr(void *args){ struct ad7606_device *ad_dev = (struct ad7606_device *)args;
if (ad_dev && ad_dev->enabled) { // 释放信号量,唤醒采样线程读取数据 rt_sem_release(ad_dev->data_sem); }}
采样线程检测到 BUSY 信号后,读取数据并通过 DMA 传输:
static void ad7606_sample_entry(void *parameter){ // ... 初始化代码 ...
while (ad_dev->sample_run) { // 等待 BUSY 中断释放信号量 if (rt_sem_take(ad_dev->data_sem, timeout) == RT_EOK) { // 读取 8 通道数据 for (int i = 0; i < AD7606_MAX_CHANNELS; i++) { rt_pin_write(ad_dev->cs_pin, PIN_LOW); rt_pin_write(ad_dev->rd_pin, PIN_LOW); ad_dev->data[i] = (rt_uint16_t)rt_adc_read(ad_dev->fb_dev, i); rt_pin_write(ad_dev->rd_pin, PIN_HIGH); rt_pin_write(ad_dev->cs_pin, PIN_HIGH);
// 写入 DMA 缓冲区 if (ad_dev->dma_enable && ad_dev->dma_data) { ad_dev->dma_data[dma_index++] = ad_dev->data[i]; } }
// DMA 传输触发 if (ad_dev->dma_enable && dma_index == 0) { // 刷新 CPU Cache(确保 DMA 看到最新数据) rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, ad_dev->dma_data, buffer_len);
// 配置并启动 DMA ret = rt_dma_prep_memcpy(dma_chan, src, dst, buffer_len); rt_dma_chan_start(dma_chan);
// 等待 DMA 完成 rt_event_recv(dma_event, EVENT_DMA_DONE, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, timeout, RT_NULL);
// 无效化目标 Cache(确保 CPU 读取到正确数据) rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, dst_addr, buffer_len); } } }}
case RT_ADC_CMD_DMA_START:{ // 请求 DMA 通道 ad_dev->dma_chan = rt_dma_chan_request(ad_dev->dev, RT_NULL);
// 创建事件用于 DMA 完成通知 _ad7606_dma_event = rt_event_create("ad7606_event", RT_IPC_FLAG_FIFO);
// 分配 DMA 源缓冲区 ad_dev->dma_data = (rt_uint16_t *)rt_calloc(1, buf_len);
// 配置 DMA(内存到内存拷贝模式) struct rt_dma_slave_config dma_cfg = { .direction = RT_DMA_MEM_TO_MEM, .src_addr = (rt_ubase_t)ad_dev->dma_data, .dst_addr = (rt_ubase_t)adc_dma_cfg->dst_addr, }; rt_dma_chan_config(ad_dev->dma_chan, &dma_cfg);
ad_dev->dma_enable = RT_TRUE; break;}
int adc_vol_show(int argc, char *argv[]){ // 启动采集线程 _adc_thread = rt_thread_create("adc_vol", _adc_vol_show_thread, RT_NULL, 2048, 16, 10); rt_thread_startup(_adc_thread);}MSH_CMD_EXPORT(adc_vol_show, ad7606 voltage read sample);
AD7606 输出 16 位补码格式,需要转换为实际电压值:
// 16 位补码转电压值(±5V 量程)voltage = (raw_val * 5000) / 32767; // 单位:mV
使用 FireWater 引擎,每行数据格式:
ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8\r\n
例如:
2.500,-1.234,0.000,3.456,-5.123,10.000,0.000,0.000\r\n
msh />adc_vol_showadc_vol_show is running
预期结果:
串口 3 输出数据流
VOFA+ 显示 8 通道波形
RK3506 采用 Cortex-A7 内核,带有 L1/L2 Cache。DMA 传输前后必须处理 Cache:
// DMA 传输前:刷新源缓冲区,确保数据写入主存rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, src, len); // DMA 传输后:无效化目标缓冲区,强制从主存读取rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, dst, len);
FlexBus 并行总线速率较高,务必注意:
● 使用短而等长的排线
● 相邻数据线之间保持地线隔离
● 确保参考地平面完整
AD7606 的 ±10V 输入范围已内置保护二极管,但:
● 严禁输入超过 ±25V
● 热插拔时务必断电操作
// 采集一个周期的电压信号(50Hz)#define SAMPLE_RATE 10000 // 每通道 10kSPS#define SAMPLE_CYCLE 200 // 50Hz 一个周期需要 200 个点 for (int i = 0; i < SAMPLE_CYCLE; i++) { voltage[i] = read_adc_channel(0); // 读取电压通道} // FFT 变换得到各次谐波分量fft_analyze(voltage, SAMPLE_CYCLE);
配合热电偶或 RTD 传感器,可实现高精度温度监控:
// 8 通道温度采集(需外接多路模拟开关)#define THERMOCOUPLE_GAIN 1000 // 热电偶放大倍数for (int i = 0; i < 8; i++) { temp[i] = (voltage[i] / THERMOCOUPLE_GAIN) / 0.041; // K 型热电偶}
FlexBus + AD7606 + DMA 方案为嵌入式平台提供了企业级数据采集能力:
200kSPS 高速采样,满足大多数工业应用需求
8 通道同步采样,无相位延迟
DMA 数据搬运,CPU 几乎零介入
硬件定时器触发,采样精度高、抖动小
可配置过采样,灵活平衡速度与精度
完整示例代码已集成到睿擎v2605版本SDK,硬件扩展板也即将发布,敬请期待!

全部0条评论
快来发表一下你的评论吧 !