实战 | 睿擎派 + AD7606:FlexBus + DMA 高速数据采集实战,200kSPS 8通道同步采样

描述

在工业数据采集、电力监控、振动分析等场景中,高速、多通道、同步采样 是核心需求。传统 MCU 方案往往面临 CPU 占用高、数据吞吐不足的瓶颈。

今天分享一个基于睿擎派 RC3506 的完整方案——利用 FlexBus 并行总线 驱动 AD7606 ADC,配合 DMA 数据搬运,实现 8通道高速同步采样,CPU 几乎零介入。


 

效果先看

通过串口将采集数据发送至 VOFA+ 上位机,波形实时显示:

dma

8通道同步采样波形展示(通道1-4: ±5V,通道5-8: ±10V)


 

为什么选这个方案?

 

AD7606 简介

AD7606 是 ADI 推出的一款多通道同步采样 ADC,堪称工业数据采集的"瑞士军刀":

特性

参数

通道数

8通道同步采样

分辨率

16位

采样率

最高 200kSPS(无过采样)

输入范围

±10V 或 ±5V(可选)

接口

并行/串行可选

数据格式

16位补码

典型应用场景:

电力系统监测(谐波分析、电能质量)

工业自动化(PLC、伺服控制信号采集)

振动分析(多轴加速度传感器)

声学检测(多通道麦克风阵列)


 

为什么需要 FlexBus + DMA?

传统的 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 处理


 

硬件连接

硬件清单

dma


 


 

连接示意


 

连接示意

dma


 

扩展板即将上架淘宝店,敬请期待!
 


 

关键信号说明:

CONVST A/B:启动转换信号,同时触发 8 通道同步采样

BUSY:转换进行中指示,转换完成后拉低

CS + RD:读取数据控制信号

OS0-OS2:过采样倍率配置(200kSPS ~ 3.125kSPS)

RANGE:输入范围选择(±5V 或 ±10V)


 

软件架构

整个驱动分为三层:

dma

采样流程

dma


 

核心驱动解析

1. 设备结构体
 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

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 目标配置};


 

2. 硬件定时器触发采样

采样时机由硬件定时器精确控制,避免了软件延时带来的抖动:
 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

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

最高精度

3. BUSY 中断处理

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);    }}


 

4. DMA 数据传输

采样线程检测到 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);            }        }    }}


 

5. DMA 配置
 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

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;}


 

应用层示例

Shell 命令
 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

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

VOFA+ 数据协议

使用 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 通道波形


 

注意事项

1. Cache 一致性

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);


 

2. 信号完整性

FlexBus 并行总线速率较高,务必注意:

● 使用短而等长的排线

● 相邻数据线之间保持地线隔离

● 确保参考地平面完整

3. 输入保护

AD7606 的 ±10V 输入范围已内置保护二极管,但:

● 严禁输入超过 ±25V

● 热插拔时务必断电操作


 

扩展应用

1. 电力谐波分析

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

// 采集一个周期的电压信号(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);

2. 多点温度采集

配合热电偶或 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,硬件扩展板也即将发布,敬请期待

dma


 

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分