ZYNQ7035实战:手把手教你用Vivado 2022.2和Linux驱动搞定AXI-DMA回环测试

张开发
2026/6/9 13:18:47 15 分钟阅读
ZYNQ7035实战:手把手教你用Vivado 2022.2和Linux驱动搞定AXI-DMA回环测试
ZYNQ7035实战从硬件配置到Linux驱动的AXI-DMA全流程解析在嵌入式系统开发中高效的数据传输一直是性能优化的关键。当我们需要在ZYNQ SoC的PS处理器系统和PL可编程逻辑之间传输大量数据时AXI-DMAAXI Direct Memory Access无疑是最佳选择之一。本文将带你从零开始完成一个完整的AXI-DMA回环测试项目涵盖Vivado硬件配置、设备树生成、Linux驱动开发等全流程。1. 项目概述与准备工作AXI-DMA是Xilinx提供的一个软核IP它允许PL端通过AXI总线直接访问PS端的内存DDR而无需CPU介入。这种机制特别适合大数据量的传输场景如图像处理、高速数据采集等。所需环境准备硬件ZYNQ-7035开发板如米联客M7035软件工具链Vivado 2022.2用于硬件设计Vitis 2022.2用于设备树生成Petalinux 2022.2可选用于系统构建交叉编译工具链arm-linux-gnueabihf-项目最终产出文件system.bitFPGA配置文件system.dtb设备树二进制文件zImageLinux内核镜像mydma.ko自定义DMA测试驱动模块2. Vivado硬件配置详解2.1 创建基本工程与IP集成首先在Vivado中创建一个新工程选择对应的ZYNQ器件型号xc7z035fbg676-2。然后通过Block Design添加ZYNQ Processing System IP并进行基本配置双击ZYNQ IP核在PS-PL Configuration中启用HP0接口用于高速数据传输在Clock Configuration中设置PL时钟如100MHz接下来添加AXI DMA IP核位于AXI Direct Memory Access类别关键配置参数如下参数项推荐值说明Enable Scatter Gather禁用使用简单模式简化首次验证Width of Buffer Length Register14决定最大传输长度2^14字节Memory Map Data Width32与HP接口位宽匹配Stream Data Width32可根据需求调整2.2 连接与地址分配使用自动连接功能完成基本连线后需要特别注意以下连接AXI DMA的S_AXI_LITE接口连接到ZYNQ的GP接口用于寄存器配置AXI DMA的M_AXI_MM2S和M_AXI_S2MM连接到ZYNQ的HP接口用于数据传输中断信号连接到ZYNQ的IRQ_F2P完成连接后运行地址自动分配确保DMA控制寄存器有正确的映射地址通常为0x40400000。2.3 生成硬件描述文件在生成比特流前需要验证设计Validate Design生成HDL Wrapper综合、实现并生成比特流最终得到两个关键文件system.bitFPGA配置文件system.xsa硬件描述文件用于后续软件开发提示建议在生成比特流前进行时序约束和验证确保设计满足时序要求。3. 设备树与内核配置3.1 从XSA生成设备树传统方式使用Petalinux生成设备树耗时较长我们可以使用Vitis更高效地完成这一步骤# 在Vitis中执行以下步骤 xsct set hw_design [open_hw_design system.xsa] xsct set repo_path {path_to_device-tree-xlnx} xsct create_sw_design device-tree -os device_tree -proc ps7_cortexa9_0 xsct generate_target -dir my_dts生成的pl.dtsi文件包含AXI DMA的节点定义关键内容如下axi_dma_0: dma40400000 { #dma-cells 1; compatible xlnx,axi-dma-7.1, xlnx,axi-dma-1.00.a; reg 0x40400000 0x10000; interrupts 0 29 4 0 30 4; dma-channel40400000 { compatible xlnx,axi-dma-mm2s-channel; interrupts 0 29 4; }; dma-channel40400030 { compatible xlnx,axi-dma-s2mm-channel; interrupts 0 30 4; }; };3.2 内核配置与编译确保Linux内核已启用以下配置选项Device Drivers --- DMA Engine support --- * Xilinx AXI DMAS Engine * DMA Test client编译内核和设备树make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- zImage -j4 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- dtbs4. Linux驱动开发实战4.1 DMA驱动框架概述Linux的DMA引擎框架提供了统一的API来操作不同厂商的DMA控制器。我们的驱动需要申请DMA通道准备DMA缓冲区配置DMA传输描述符启动传输并处理完成中断Xilinx已经提供了基础的AXI DMA驱动xilinx_dma.c我们的工作是在此基础上实现应用层逻辑。4.2 关键数据结构定义驱动私有数据结构struct my_dma_test { struct dma_chan *tx_chan; // 发送通道 struct dma_chan *rx_chan; // 接收通道 uint8_t *src_buf; // 源缓冲区虚拟地址 uint8_t *dst_buf; // 目标缓冲区虚拟地址 dma_addr_t src_dma; // 源缓冲区DMA地址 dma_addr_t dst_dma; // 目标缓冲区DMA地址 struct completion dma_complete; // 用于同步 };4.3 缓冲区分配与映射使用DMA一致性映射API分配内存dma_test-src_buf dma_alloc_coherent(dev, BUF_SIZE, dma_test-src_dma, GFP_KERNEL); dma_test-dst_buf dma_alloc_coherent(dev, BUF_SIZE, dma_test-dst_dma, GFP_KERNEL);这种分配方式能确保缓冲区在CPU和DMA视角下都是一致的无需额外缓存维护操作。4.4 DMA传输配置虽然硬件配置为简单模式但实际驱动中使用SGScatter-Gather模式更为可靠/* 准备SG列表实际上只用一个条目 */ sg_init_table(sg, 1); sg_dma_address(sg) dma_addr; sg_dma_len(sg) len; /* 准备DMA描述符 */ txd dmaengine_prep_slave_sg(chan, sg, 1, dir, flags); txd-callback dma_callback; txd-callback_param dma_test;4.5 完整驱动流程驱动的主要工作流程如下probe函数申请DMA通道分配DMA缓冲区初始化完成量准备测试数据传输启动配置MM2S内存到流传输配置S2MM流到内存传输提交传输描述符异步启动传输回调处理在传输完成中断中验证数据通知完成量打印性能统计信息remove函数释放DMA通道释放DMA缓冲区清理资源注意实际项目中应考虑错误处理、超时机制和性能优化如使用环形缓冲区减少内存分配开销。5. 测试与验证编译驱动模块make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- -C $KERNEL_SRC M$PWD modules测试步骤加载驱动模块insmod my_dma.ko查看内核日志dmesg | tail -20预期输出示例[ 1234.567890] DMA transfer started! [ 1234.567891] MM2S transfer completed [ 1234.567892] S2MM transfer completed [ 1234.567893] Data verification passed, transfer time: 1250 ns性能优化建议增大传输长度观察吞吐量变化尝试启用SG模式处理不连续内存调整DMA缓冲区对齐方式通常64字节对齐最佳考虑使用中断合并减少CPU负载在实际项目中AXI DMA的性能可以轻松达到数百MB/s的传输速率远高于CPU直接搬运的效率。掌握这一技术将为你的嵌入式系统开发打开新的大门无论是高速数据采集、实时图像处理还是网络数据包转发都能从中受益。

更多文章