ZCU106开发板上,用PYNQ和DMA实现25MB/s高速数据传输的保姆级配置流程

张开发
2026/6/5 19:35:39 15 分钟阅读
ZCU106开发板上,用PYNQ和DMA实现25MB/s高速数据传输的保姆级配置流程
ZCU106开发板上实现25MB/s高速DMA传输的实战指南第一次在ZCU106上尝试DMA传输时我盯着屏幕上不到5MB/s的速度百思不得其解——直到发现那个被忽略的HP端口配置。本文将带你避开所有我踩过的坑从零开始构建完整的25MB/s高速传输系统。1. 环境准备与基础概念在开始前确保你的开发环境已就绪。你需要已安装Vivado 2018.3或更高版本ZCU106开发板及配套电源线已烧录PYNQ v2.6镜像的SD卡网线及USB转串口调试工具DMA传输的核心优势在于它能绕过CPU直接在外设与内存间搬运数据。在ZCU106这种异构平台上PS(处理系统)与PL(可编程逻辑)间的DMA传输尤为关键。以下是几个直接影响传输速度的关键因素因素影响程度优化方向DMA配置模式★★★★★关闭SG(Scatter-Gather)模式HP端口数量★★★★☆至少启用一个HP(High Performance)端口Buffer大小★★★☆☆合理分配CMA内存区域数据对齐★★☆☆☆确保32位对齐提示PYNQ的CMA(Contiguous Memory Allocator)管理器默认分配的内存已经是DMA友好的这是选择PYNQ而非纯Linux方案的重要原因之一。2. Vivado中的DMA系统搭建2.1 创建基础工程启动Vivado后按以下步骤创建工程选择Create Project向导指定工程名(如zcu106_dma)和路径在Default Part中选择xczu7ev-ffvc1156-2-e完成工程创建关键的一步是在芯片选择时务必确认型号完全匹配ZCU106的核心芯片否则后续生成的比特流将无法正常运行。2.2 构建Block Design在Flow Navigator中点击Create Block Design命名为dma_loop。我们将构建一个最简单的DMA回环测试系统# 这是后续会用到的重要bd.tcl命令示例 create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 axi_dma_0 create_bd_cell -type ip -vlnv xilinx.com:ip:zynq_ultra_ps_e:3.3 zynq_ultra_ps_e_0添加并配置关键IP核ZYNQ UltraScale MPSoC双击打开配置在PS-PL Configuration中展开HP Slave AXI Interface勾选S_AXI_HP0_FPD接口保持默认时钟频率(100MHz)AXI DMA这是核心传输引擎将Enable Scatter Gather Engine设为0(关闭SG模式)Width of Buffer Length Register保持23位其他参数保持默认2.3 连接与自动化使用Run Connection Automation自动连接大部分接口但需要手动完成将DMA的S_AXIS_S2MM直接连接到M_AXIS_MM2S形成回环确保axi_dma_0/M_AXI_MM2S和axi_dma_0/M_AXI_S2MM都连接到ZYNQ的S_AXI_HP0_FPD最终的Block Design应呈现清晰的信号流向ZYNQ PS --HP0-- DMA --Stream-- 回环路径注意务必验证连接正确性特别是中断信号是否被正确隔离。我曾因未隔离中断导致系统不稳定。3. 生成比特流与文件导出3.1 生成流程右键Block Design选择Generate Output Products选择Generate生成HDL包装文件在Sources面板右键顶层设计选择Create HDL Wrapper运行Generate Bitstream这个过程可能需要30分钟到2小时不等取决于你的电脑配置。期间可能会遇到时序不满足的警告对于我们的测试系统可以暂时忽略。3.2 关键文件提取比特流生成完成后需要提取三个关键文件比特流文件(.bit)位于project.runs/impl_1目录硬件描述文件(.hwh)与Block Design同名TCL脚本(.tcl)在project.srcs/sources_1/bd/bd_name/hdl目录将这些文件打包到一个文件夹中建议命名为dma_loop。以下是验证文件完整性的方法# 在Linux终端中检查文件 file dma_loop.bit # 应显示Xilinx BIT data file dma_loop.hwh # 应是XML格式文本文件4. PYNQ平台上的DMA测试4.1 文件部署将上一步的三个文件复制到ZCU106开发板上通过SCP或U盘将文件传输到PYNQ建议放在/home/xilinx/dma_test目录确保文件权限正确chmod 644 /home/xilinx/dma_test/*4.2 Jupyter Notebook实现启动PYNQ的Jupyter环境新建Python3 Notebook。以下是完整的测试代码包含详细注释import numpy as np from pynq import Xlnk, Overlay import time # 加载Overlay ol Overlay(/home/xilinx/dma_test/dma_loop.bit) dma ol.axi_dma_0 # 获取DMA实例 # 初始化CMA内存分配器 xlnk Xlnk() input_buffer xlnk.cma_array(shape(6553600,), dtypenp.uint32) output_buffer xlnk.cma_array(shape(6553600,), dtypenp.uint32) # 填充测试数据(25MB) print(Generating test data...) for i in range(len(input_buffer)): input_buffer[i] i % 256 # 防止数据过大 # 执行DMA传输 print(Starting DMA transfer...) start time.time() dma.sendchannel.transfer(input_buffer) dma.recvchannel.transfer(output_buffer) dma.sendchannel.wait() # 等待发送完成 dma.recvchannel.wait() # 等待接收完成 end time.time() # 计算性能 duration end - start data_size len(input_buffer) * 4 # 每个uint32占4字节 speed (data_size / (1024 * 1024)) / duration print(fTransfer completed in {duration:.5f} seconds) print(fSpeed: {speed:.2f} MB/s)4.3 性能优化技巧如果速度未达预期尝试以下调整Buffer大小25MB(6553600个uint32)是个平衡点过小会有启动开销过大可能引起内存碎片数据对齐确保numpy数组使用dtypenp.uint32保持32位对齐时钟频率在Vivado中可尝试提升HP端口时钟(但需验证时序)我曾通过以下命令验证内存连续性这对性能调优很有帮助# 检查CMA内存的物理连续性 print(fInput buffer physical address: {input_buffer.physical_address}) print(fOutput buffer physical address: {output_buffer.physical_address})5. 常见问题与解决方案5.1 DMA传输失败症状transfer()调用后卡在wait()处排查步骤检查比特流是否正确加载验证Buffer是否成功分配使用dma.recvchannel.idle和dma.sendchannel.idle检查通道状态5.2 速度低于预期可能原因HP端口未启用SG模式意外开启缓存未正确刷新诊断方法 在Vivado中确认HP端口连接状态get_bd_intf_pins -of_objects [get_bd_cells axi_dma_0]5.3 内存分配失败错误信息CMA allocation failed解决方案检查PYNQ镜像版本(建议v2.6)尝试分块分配内存重启Python内核释放残留内存6. 进阶测试与验证为确保数据传输的完整性建议添加数据校验步骤# 数据校验 errors 0 for i in range(0, len(input_buffer), 100000): # 抽样检查 if input_buffer[i] ! output_buffer[i]: errors 1 print(fData errors: {errors})对于长期稳定性测试可以封装为函数循环运行def run_test(iterations10): speeds [] for _ in range(iterations): start time.time() # ... DMA传输代码 ... duration time.time() - start speed (data_size / (1024 * 1024)) / duration speeds.append(speed) return speeds # 运行10次测试 results run_test(10) print(fAverage speed: {np.mean(results):.2f}±{np.std(results):.2f} MB/s)记得在实际项目中DMA传输不会只是简单的回环。将接收端替换为实际处理模块如AI加速器才能真正发挥这种高速传输的价值。

更多文章