Xilinx AXI DMA v7.1 实战:Vivado 2024.1 连接 FIFO 实现 512 字节 Loopback 测试
在 FPGA 系统设计中,高效的数据传输机制是提升整体性能的关键。AXI DMA(直接内存访问)作为 Xilinx 平台的核心 IP,能够在不占用 CPU 资源的情况下,实现内存与流式接口之间的高速数据传输。本文将深入探讨如何在 Vivado 2024.1 环境中,利用 AXI DMA IP 核与 AXI4-Stream Data FIFO 构建一个完整的、可验证的数据通路。
1. 环境准备与硬件配置
1.1 Vivado 工程创建与基本设置
首先启动 Vivado 2024.1,创建一个新的 RTL 工程。选择目标器件型号时,需根据实际使用的 Zynq 或 Versal 平台进行匹配。建议勾选"Do not specify sources at this time"选项,以便后续灵活添加设计文件。
在工程创建完成后,需要设置正确的器件封装和速度等级。对于 Zynq-7000 系列,典型的配置如下:
set_property part xc7z020clg484-1 [current_project] set_property board_part_repo_paths {/opt/Xilinx/vivado/2024.1/data/boards} [current_project] set_property board_part digilentinc.com:zedboard:part0:1.0 [current_project]1.2 添加必要的 IP 核
在 Block Design 界面中,通过 IP Integrator 添加以下关键 IP 核:
- Zynq Processing System:作为系统的核心处理单元
- AXI DMA (v7.1):选择配置为 MM2S 和 S2MM 通道,数据宽度设为 64 位
- AXI4-Stream Data FIFO:深度设置为 512,TDATA 宽度与 DMA 保持一致
关键配置参数对比如下:
| IP 核 | 参数 | 推荐值 | 说明 |
|---|---|---|---|
| AXI DMA | Data Width | 64-bit | 匹配 FIFO 接口宽度 |
| AXI DMA | Enable Scatter Gather | Disabled | 简化初始测试 |
| AXI FIFO | FIFO Depth | 512 | 存储 512 字节数据 |
| AXI FIFO | TDATA Width | 64-bit | 与 DMA 配置一致 |
2. 系统连接与自动化配置
2.1 基础连接拓扑
在 Block Design 中完成以下关键连接:
- 将 Zynq 的 AXI HP 接口连接到 DMA 的 M_AXI_MM2S 和 M_AXI_S2MM 端口
- 连接 Zynq 的 AXI GP 接口到 DMA 的 S_AXI_LITE 接口
- 将 DMA 的 M_AXIS_MM2S 连接到 FIFO 的 S_AXIS 输入
- 将 FIFO 的 M_AXIS 输出连接到 DMA 的 S_AXIS_S2MM
时钟和复位信号的连接需要特别注意:
connect_bd_net [get_bd_pins zynq_ps/FCLK_CLK0] \ [get_bd_pins axi_dma/s_axi_lite_aclk] \ [get_bd_pins axi_fifo/s_axis_aclk] connect_bd_net [get_bd_pins zynq_ps/FCLK_RESET0_N] \ [get_bd_pins axi_dma/axi_resetn] \ [get_bd_pins axi_fifo/s_axis_aresetn]2.2 地址空间分配
使用 Vivado 的 Address Editor 工具自动分配地址空间。确保 DMA 控制寄存器有正确的映射地址,典型配置如下:
| 接口 | 基地址 | 范围 | 说明 |
|---|---|---|---|
| S_AXI_LITE | 0x40400000 | 64K | DMA 控制寄存器 |
| M_AXI_MM2S | 0x00000000 | 1G | 内存读取通道 |
| M_AXI_S2MM | 0x00000000 | 1G | 内存写入通道 |
提示:在 Zynq 系统中,HP 端口默认连接到 DDR 控制器,确保在 Zynq 配置中启用了至少一个 HP 端口。
3. 软件环境搭建与测试代码
3.1 Vitis IDE 工程创建
在 Vivado 中生成比特流后,导出硬件平台到 Vitis IDE。创建一个新的应用工程,选择"Empty Application"模板。需要添加 Xilinx DMA 驱动库到工程中:
#include "xaxidma.h" #include "xparameters.h" #include "xil_cache.h"3.2 DMA 测试代码实现
以下是一个完整的 loopback 测试程序,实现 512 字节数据的发送和接收验证:
#define TEST_START_ADDR 0x01000000 #define TEST_LENGTH 512 int main() { XAxiDma_Config *cfg; XAxiDma dma_inst; u8 *tx_buf, *rx_buf; int status, i; // 初始化 DMA cfg = XAxiDma_LookupConfig(XPAR_AXIDMA_0_DEVICE_ID); status = XAxiDma_CfgInitialize(&dma_inst, cfg); if (status != XST_SUCCESS) { xil_printf("DMA init failed\r\n"); return XST_FAILURE; } // 分配内存缓冲区 tx_buf = (u8 *)memalign(32, TEST_LENGTH); rx_buf = (u8 *)memalign(32, TEST_LENGTH); // 初始化测试数据 for (i = 0; i < TEST_LENGTH; i++) { tx_buf[i] = i % 256; rx_buf[i] = 0; } // 刷新缓存 Xil_DCacheFlushRange((u32)tx_buf, TEST_LENGTH); Xil_DCacheFlushRange((u32)rx_buf, TEST_LENGTH); // 启动 DMA 传输 status = XAxiDma_SimpleTransfer(&dma_inst, (u32)tx_buf, TEST_LENGTH, XAXIDMA_DMA_TO_DEVICE); status |= XAxiDma_SimpleTransfer(&dma_inst, (u32)rx_buf, TEST_LENGTH, XAXIDMA_DEVICE_TO_DMA); // 等待传输完成 while (XAxiDma_Busy(&dma_inst, XAXIDMA_DMA_TO_DEVICE)); while (XAxiDma_Busy(&dma_inst, XAXIDMA_DEVICE_TO_DMA)); // 验证数据 for (i = 0; i < TEST_LENGTH; i++) { if (rx_buf[i] != tx_buf[i]) { xil_printf("Data mismatch at %d: %02x vs %02x\r\n", i, rx_buf[i], tx_buf[i]); return XST_FAILURE; } } xil_printf("Loopback test passed!\r\n"); return XST_SUCCESS; }4. 调试技巧与性能优化
4.1 常见问题排查
在实际调试中,可能会遇到以下典型问题:
DMA 初始化失败:
- 检查 Vivado 中地址分配是否正确
- 确认 PS 侧已正确配置时钟和复位信号
- 验证 AXI 互联是否正确建立
数据传输不完整:
- 确保 TLAST 信号在适当的时候被断言
- 检查 FIFO 的深度是否足够
- 验证内存缓冲区是否已正确对齐
性能瓶颈分析:
- 使用 AXI 性能监控器测量实际带宽
- 检查时钟域交叉是否导致时序问题
- 评估 DMA 突发传输长度是否最优
4.2 高级配置选项
对于需要更高性能的场景,可以考虑以下优化措施:
- 启用 Scatter Gather 模式:减少 CPU 干预开销
- 调整突发长度:根据目标平台特性优化
- 使用多通道 DMA:并行化数据传输
- 启用数据重对齐:处理非对齐访问
关键寄存器配置示例:
// 优化 MM2S 通道配置 XAxiDma_WriteReg(dma_inst.RegBase + XAXIDMA_TX_OFFSET, XAXIDMA_CR_OFFSET, XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_CR_CYCLIC_BD_MASK); // 设置最大突发长度 XAxiDma_WriteReg(dma_inst.RegBase + XAXIDMA_TX_OFFSET, XAXIDMA_BUFFLEN_OFFSET, 256); // 256字节突发5. 实际应用场景扩展
5.1 与自定义 IP 集成
AXI DMA 可以方便地与用户自定义的 AXI4-Stream IP 集成。典型连接方式如下:
- 将自定义 IP 的流接口连接到 DMA 的流接口
- 通过 AXI-Lite 接口配置自定义 IP 的参数
- 使用中断机制协调数据传输
5.2 多 DMA 通道协同工作
对于需要同时处理多个数据流的应用,可以配置多个 DMA 通道:
// 在 Vivado 中实例化多个 DMA 控制器 axi_dma_0: entity work.axi_dma_0_wrapper axi_dma_1: entity work.axi_dma_1_wrapper // 在软件中分别初始化和管理 XAxiDma_CfgInitialize(&dma0_inst, cfg0); XAxiDma_CfgInitialize(&dma1_inst, cfg1);5.3 低延迟优化技术
对于实时性要求高的应用,可采取以下措施降低延迟:
- 使用较小的 FIFO 深度减少缓冲延迟
- 优化中断处理流程
- 采用轮询模式替代中断模式
- 使用 AXI Cache 信号优化内存访问
6. 系统验证与性能测试
6.1 功能验证方法
完整的验证流程应包括:
- 单元测试:验证 DMA 基本传输功能
- 边界测试:测试最大/最小数据包传输
- 压力测试:连续传输大量数据验证稳定性
- 错误注入测试:模拟异常情况下的行为
6.2 性能指标测量
使用以下方法量化系统性能:
吞吐量测试:
start_time = Xil_GetTime(); // 执行大数据量传输 end_time = Xil_GetTime(); throughput = data_size / (end_time - start_time);延迟测量:
- 使用 GPIO 引脚和逻辑分析仪测量端到端延迟
- 通过 TLAST 信号时间戳计算处理延迟
资源利用率:
- 在 Vivado 实现后查看资源报告
- 监控动态功耗变化
7. 进阶主题与最佳实践
7.1 安全考量
在安全敏感应用中,需注意:
- 配置 DMA 仅访问指定内存区域
- 启用 AXI 保护位防止非法访问
- 实现数据完整性检查机制
- 使用校验和或 CRC 验证数据传输
7.2 电源管理
对于低功耗设计:
- 动态启用/禁用 DMA 通道
- 利用时钟门控降低空闲时功耗
- 根据负载调整 DMA 工作频率
- 使用 Versal 平台的电源管理功能
7.3 调试技巧
高效的调试方法包括:
- 使用 ILA 核捕获 AXI 流信号
- 通过 XSDB 接口实时监控寄存器
- 实现环形缓冲区记录运行状态
- 添加辅助调试寄存器输出状态信息
在实际项目中,我们发现 FIFO 深度设置为数据包大小的 2-3 倍时,通常能在面积和性能间取得良好平衡。对于 512 字节的数据传输,1024 深度的 FIFO 已经足够应对大多数情况。