Vivado工程搭建
1. 创建基础工程
新建Vivado项目,选择目标FPGA型号。
添加Zynq Processing System IP核,配置DDR控制器和时钟。7000系列的Zynq可以参考正点原子DMA回环测试设置。


2. 添加AXI DMA IP核
配置AXI DMA为Simple模式。
设置数据位宽(如32/64位)和Width of Buffer Lenghth Register(26最大可以存2^26 bit)。

3. 添加Stream Data FIFO
这里看需要设置FIFO 深度

4. 添加自定义ip用于产生数据
这里可以参考https://fpga.eetrend.com/blog/2023/100568155.html,由于工程需要,对ip进行修改,使得传输的数据位宽是16位,一共传输320*256个数据。修改位宽后re-package可能会出现报错,请自行查找解决办法。


5. 添加自定义ip用于产生dma_start信号
由于dma传输过程中会出现数据丢失情况,这里借鉴了以下博主的解决方法:ZYNQ踩坑日记:AXI_DMA传输问题详解——问题再续篇-物联沃-IOTWORD物联网对于vivado中使用DMA传输数据时会丢数据的解决办法_vivado dma-CSDN博客

对数据产生ip进行了修改(右键ip->edit in packager),使得dma初始化之后再开始传输数据,避免数据丢失

在关键代码中进行如下修改:

最后再Re-Package IP,可以参考https://cloud.tencent.com/developer/article/1813652创建并修改自定义ip。
6. 连接IP核与总线
总体block design如下

PS端软件设计(Vitis/SDK)
1. 初始化DMA
#include"xaxidma.h"#include"xparameters.h"#include"xil_cache.h"#include"xil_printf.h"#include"my_dma_start_s.h"#include"sleep.h"#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID#define DDR_BASE_ADDR XPAR_PSU_DDR_0_S_AXI_BASEADDR#define RX_BUFFER_BASE (DDR_BASE_ADDR + 0x01000000)#define DATA_LENGTH 81920// 与 PL 端对应#define MY_DMA_START_ADDR XPAR_MY_DMA_START_S_0_S00_AXI_BASEADDR#define MY_DMA_OFFSET MY_DMA_START_S_S00_AXI_SLV_REG0_OFFSETint main() { XAxiDma AxiDma; XAxiDma_Config *Config; int status, i; u16 *RxBufferPtr = (u16 *)RX_BUFFER_BASE; xil_printf("---- Start DMA Receive Test ----
"); Config = XAxiDma_LookupConfig(DMA_DEV_ID); if (!Config) { xil_printf("No DMA config found!
"); return XST_FAILURE; } status = XAxiDma_CfgInitialize(&AxiDma, Config); if (status != XST_SUCCESS) { xil_printf("DMA Init Failed
"); return XST_FAILURE; } if (XAxiDma_HasSg(&AxiDma)) { xil_printf("DMA configured as SG mode!
"); return XST_FAILURE; } // 启动接收 status = XAxiDma_SimpleTransfer(&AxiDma, (UINTPTR)RxBufferPtr, DATA_LENGTH * sizeof(u16), XAXIDMA_DEVICE_TO_DMA); if (status != XST_SUCCESS) { xil_printf("DMA Receive Config Failed
"); return XST_FAILURE; } //这里用于通知PL端开始发送数据 MY_DMA_START_S_mWriteReg(MY_DMA_START_ADDR,MY_DMA_OFFSET,1); usleep(5); MY_DMA_START_S_mWriteReg(MY_DMA_START_ADDR,MY_DMA_OFFSET,0); // 等待DMA完成(这里简单用while轮询)while (XAxiDma_Busy(&AxiDma, XAXIDMA_DEVICE_TO_DMA)); // 失效 Cache,保证读到 DDR 最新数据 Xil_DCacheInvalidateRange((UINTPTR)RxBufferPtr, DATA_LENGTH * sizeof(u16)); // 打印接收数据for (i = 0; i < DATA_LENGTH; i++) { xil_printf("DDR[%d] = 0x%04x
", i, RxBufferPtr[i]); } xil_printf("---- DMA Receive Done ----
"); return XST_SUCCESS; }
2. 数据传输流程
启动debug,在return XST_SUCCESS处打断点,并查看memory中ddr的数据:

测试结果如下:

ila信号如下:

可以看到结果符合要求。
全部0条评论
快来发表一下你的评论吧 !