睿擎平台 FPGA 高速通信:DSMC 总线读写实战
在工业控制和数据采集场景中,处理器与 FPGA 之间的高速数据交换是一个常见需求。传统方案通常采用SPI(速度受限,一般 < 10Mbps)或 PCIE(带宽高但引脚多、设计复杂)。有没有一种方案,既能达到 几十 MB/s 的带宽,又只需要少量引脚,设计简单?
今天分享一个基于睿擎派 RC3506的方案——利用 RK3506 芯片内置的DSMC(Double Data Rate Serial Memory Controller)总线,与 PGL22GB FPGA 实现 高速通信,完整演示从硬件连接到代码验证的全流程。
一、DSMC 是什么?
DSMC(Double Data Rate Serial Memory Controller)是瑞芯微 SoC 内部的一种高速存储与本地总线控制器,支持通过 DDR(双倍数据速率)方式与外部 PSRAM 或 LocalBus 设备(如 FPGA)进行数据通信。
DSMC 核心特性

二、硬件准备
连接方式
RC-PI-3506 开发板与 FPGA 扩展板通过 DSMC 接口连接:

睿擎派 RC3506 与 PGL22GB FPGA 扩展板连接示意
睿擎派 RC3506 开发板
三、DSMC 读写原理
3.1 内存映射
DSMC 将外部设备映射到处理器的物理地址空间,软件可以通过直接读写内存地址的方式访问 FPGA:
处理器地址空间 │ ├── 0xC0000000 ──→ DSMC CS0 区域(FPGA RAM) │ 16KB 可读写 │ └── 其他外设...
3.2 读写流程
写入流程:
1.处理器执行 writel(data, 0xC0000000 + offset)2.DSMC 控制器将数据通过 DDR 串行总线发送给 FPGA3.FPGA LocalBus 接口接收数据,写入内部 RAM
读取流程:
1.处理器执行 readl(0xC0000000 + offset)2.DSMC 控制器向 FPGA 发送读请求3.FPGA LocalBus 接口从内部 RAM 读出数据,返回给 DSMC4.DSMC 控制器将数据返回给处理器
3.3 关键约束
4字节对齐访问:RK3506 的 DSMC 读写必须 4 字节对齐,即地址必须是 4 的倍数
默认频率 12MHz:可在设备树中修改,但需确保 FPGA 侧时序匹配
8 位宽模式:当前示例使用 8 线传输,可配置为 16 线提升带宽
四、代码实战
4.1 示例代码结构
完整示例代码位于 SDK 的 02_peripheral_dsmc 目录,核心逻辑如下:
staticinttest_dsmc_read_write(void){ inti; interr_count =0; rt_uint64_tt_start, t_end; rt_uint64_twrite_cycles, read_cycles; constintWORD_NUM =4*1024; // 4K word = 16KB uintptr_tBASE_ADDR =0xC0000000; // DSMC CS0 基地址 rt_uint32_t*write_buf =rt_malloc(WORD_NUM *4); rt_uint32_t*read_buf =rt_malloc(WORD_NUM *4); if(!write_buf || !read_buf) { rt_kprintf("malloc failed!\n"); return-1; } // 准备测试数据 for(i =0; i < WORD_NUM; i++) { write_buf[i] = 0x12345678 + i; } // ========== 写入测试 ========== t_start = rt_hw_global_timer_get(); for (i = 0; i < WORD_NUM; i++) { writel(write_buf[i], BASE_ADDR + i * 4); // 4字节对齐写入 } t_end = rt_hw_global_timer_get(); write_cycles = t_end - t_start; // ========== 读取测试 ========== t_start = rt_hw_global_timer_get(); for (i = 0; i < WORD_NUM; i++) { read_buf[i] = readl(BASE_ADDR + i * 4); } t_end = rt_hw_global_timer_get(); read_cycles = t_end - t_start; // ========== 数据校验 ========== for (i = 0; i < WORD_NUM; i++) { if (read_buf[i] != write_buf[i]) { err_count++; rt_kprintf("ERR[%d]: R=0x%08X W=0x%08X\n", i, read_buf[i], write_buf[i]); if (err_count >10) { rt_kprintf("......\n"); break; } } } // ========== 性能统计 ========== floatwrite_time_us = (float)write_cycles /24.0f; // 24MHz 定时器 floatread_time_us = (float)read_cycles /24.0f; floattotal_bytes = WORD_NUM *4.0f; floatwrite_speed = (total_bytes / (1024*1024)) / (write_time_us /1e6); floatread_speed = (total_bytes / (1024*1024)) / (read_time_us /1e6); if(err_count ==0) { rt_kprintf("\n==== DSMC TEST PASS ====\n"); rt_kprintf("Write: %lu cycles, %.2f us, %.2f MB/s\n", write_cycles, write_time_us, write_speed); rt_kprintf("Read : %lu cycles, %.2f us, %.2f MB/s\n", read_cycles, read_time_us, read_speed); } else { rt_kprintf("\n==== DSMC TEST FAIL ====\n"); rt_kprintf("Error count: %d\n", err_count); } rt_free(write_buf); rt_free(read_buf); return0;}MSH_CMD_EXPORT(test_dsmc_read_write, test dsmc read write);
4.2 关键代码解析
① 基地址定义
uintptr_tBASE_ADDR =0xC0000000; // DSMC CS0 区域
DSMC 的 CS0 片选对应的物理地址是 0xC0000000,软件直接读写该地址即可访问 FPGA。
② 4 字节对齐访问
writel(write_buf[i], BASE_ADDR + i *4); // 每次写入4字节read_buf[i] = readl(BASE_ADDR + i *4); // 每次读取4字节
RK3506 的 DSMC 控制器要求访问地址 4 字节对齐,因此使用 writel/readl 函数,偏移量每次增加 4。
③ 性能测量
t_start = rt_hw_global_timer_get(); // 获取硬件定时器计数值// ... 执行写入或读取 ...t_end = rt_hw_global_timer_get();cycles = t_end - t_start;time_us = cycles / 24.0f; // 定时器频率 24MHz
通过硬件定时器精确测量读写耗时,计算出实际带宽。
五、运行结果
将示例工程编译下载到睿擎派 RC3506,在串口终端执行:
msh/>test_dsmc_read_write
输出结果:
==== DSMC TEST PASS ====Write: 73640 cycles, 3068.33 us, 5.09 MB/sRead : 240044 cycles, 10001.83 us, 1.56 MB/s
结果解读:
指标 |
写入 |
读取 |
数据量 |
16KB |
16KB |
耗时 |
3.07 ms |
10.00 ms |
带宽 |
5.09 MB/s |
1.56 MB/s |
校验结果 |
全部通过 |
全部通过 |
写入带宽达到5MB/s,读取带宽1.5MB/s,通过调整demo的时序和位宽,以及dma的加持,带宽可以达到200MB/s。
六、FPGA 工程说明
6.1 FPGA 实现的功能
FPGA 侧实现了一个LocalBus Server,功能如下:
接收 DSMC 发来的写请求,将数据存入 16KB 内部 RAM
响应 DSMC 的读请求,从 RAM 中读出数据返回
提供状态 LED 指示通信活动
6.2 FPGA 工程迁移
如果需要将 FPGA 工程迁移到不同版本的 IDE,步骤如下:
在目标 IDE 上创建 PGL22GB-6MBG324 工程
添加源文件:dsmc.fdc、dsmc_port.v、led.v
配置 RAM 和 PLL IP 核
RAM IP 核配置:

PGL22GB RAM IP 核配置:16KB 容量,32 位数据宽度
PLL IP 核配置:

PGL22GB PLL IP 核配置:生成 DSMC 所需时钟
七、设备树配置
DSMC 的引脚复用和时钟频率在设备树中配置:
&dsmc { status ="okay"; clock-frequency = <12000000>; /* 12MHz,可修改 */ pinctrl-names ="default"; pinctrl-0= <&dsmc_pins>; dsmc_pins: dsmc-pins { pins ="GPIO0_A0","GPIO0_A1","GPIO0_A2","GPIO0_A3", "GPIO0_A4","GPIO0_A5","GPIO0_A6","GPIO0_A7", "GPIO0_B0","GPIO0_B1"; function="dsmc"; };};
注意事项:
修改 clock-frequency 后,需同步修改 FPGA 侧 PLL 配置
引脚复用配置需与硬件原理图对应
当前示例使用 CS0,如需使用其他片选需修改设备树
八、工程实现说明
当前 DSMC 为8 位宽模式,开启 DSMC 的 CS0 的 FIFO region
默认频率为12MHz,在示例工程的 board.dts 中可修改
除 DSMC 的引脚复用与时钟,其他配置暂时不支持修改
DSMC 的 DMA 以及中断暂时不支持开启
九、应用场景
DSMC 与 FPGA 高速通信的典型应用场景:
场景 |
说明 |
高速 ADC 采集 |
FPGA 采集高速 ADC 数据,通过 DSMC 传输给处理器 |
电机控制 |
FPGA 实现多路 PWM 和编码器接口,处理器下发控制参数 |
视频预处理 |
FPGA 做 ISP 前处理,通过 DSMC 传输给处理器编码 |
协险品检测 |
FPGA 实现多传感器并行采集,处理器做 AI 推理 |
十、总结
这篇文章完整演示了睿擎派 RC3506 通过 DSMC 总线与 FPGA 实现高速通信:
理解 DSMC 的工作原理和内存映射机制
掌握 DSMC 与 FPGA 的硬件连接方式
学会使用 writel/readl 直接读写 DSMC 地址空间
完成 16KB 数据的读写测试和校验
了解 FPGA 工程的配置和迁移方法
DSMC 为处理器与 FPGA 之间提供了一种带宽适中、设计简单、引脚可控的高速通信方案,非常适合工业控制和数据采集场景。
继续浏览有关 通信 的文章
