目录
Vivado 软件程序
选择PynqZ2 板
需要在安装目录下的/data/boards/boards_file中添加Pynq_Z2的信息
创建blockdesign
配置PS-PL端的AXI接口
配置两个高性能从接口i 数据带宽为64bit
自动连接PS端中的默认连线
连接上DDR端口和IO端口
增加两个AXI_DMA模块
一个负责从DDR中读出数据到PL端,另一个负责将PL端中产生的数据写入到DDR中
不用勾选enanle scatter gather engine和enable micro dma
register 的长度为26bits
在IP块属性中修改AXI_DMA的IP Block名称
如图展示修改后的AXI模块
点击
连接DMA接口与PS端接口
PS端中的AXI从接口HP0连接read_dma中的主接口,将内存中的数据以流的形式发送出去
M_AXIS_MM2S接口作为主设备,主动从内存映射地址空间中读取视频帧数据。读取到的视频帧数据通过M_AXIS_MM2S接口转换成一个连续的数据流。
PS端中的AXI从接口HP1连接write_dma中的主接口,通常用于接收来自外部设备的数据流,并将这些数据以高效的方式存储到系统的内存中。M_AXI_S2MM接口在数据传输过程中既能根据系统的控制命令灵活响应(作为Slave),又能主动地从数据源接收数据流(作为Master),
最后连接S_AXI_LITE接口到PS模块的GP0端口
布局布线如下:
插入AXI_Stream_FIFO模块
手动连接主从模块,将FIFO的M_AXIS端口连接至write_dma的S_AXIS_S2MM端口
手动连接主从模块,将FIFO的S_AXIS端口连接至write_dma的M_AXIS_MM2S端口
M_AXI_MM2S强调的是AXI协议在主设备方面的应用,用于内存映射数据的读取和转换。而M_AXIS_MM2S则专注于数据流的传输
最后点击RUN Connection Automation 自动连接剩余的线
真实性检测
重新生成布局
生成Block Design在这里插入图片描述
创建HLS包装器
生成比特流后导出硬件XSA文件
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/
启动Vitis
Vitis 软件程序
新建文件应用项目
从文件夹中选择XSA文件
创建hello.world项目
1.构建项目
2.打开串口窗口
3.选择端口
4.在硬件上运行
5.查看结果
测试读写DMA以及AXI-Stream FIFO
代码演示了如何使用DMA将数据从处理系统(PS)的内存传输到一个FIFO缓冲区,然后再将数据从FIFO传回内存,并验证数据的一致性
使用了xilinx的专用库
#include <stdio.h>
#include "xil_printf.h"
#include "xaxidma.h"
#include "xparameters.h"
#define DMA0_DEVICE_ID XPAR_AXIDMA_0_DEVICE_ID
#define DMA1_DEVICE_ID XPAR_AXIDMA_1_DEVICE_ID
#define MEM_BASE_ADDR 0x01000000
#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000)
#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000)
#define MAX_PKT_LEN 0x20 // 定义最大数据包长度(例如32字节)
XAxiDma AxiDma0; // DMA0实例
XAxiDma AxiDma1; // DMA1实例
int Init_DMA(XAxiDma *AxiDma, int DeviceId) {
XAxiDma_Config *CfgPtr;
int Status;
// 查找DMA配置
CfgPtr = XAxiDma_LookupConfig(DeviceId);
if (!CfgPtr) {
xil_printf("No config found for %d\r\n", DeviceId);
return XST_FAILURE;
}
// 初始化DMA控制器
Status = XAxiDma_CfgInitialize(AxiDma, CfgPtr);
if (Status != XST_SUCCESS) {
xil_printf("Initialization failed %d\r\n", Status);
return XST_FAILURE;
}
if (XAxiDma_HasSg(AxiDma)) {
xil_printf("Device configured as SG mode\r\n");
return XST_FAILURE;
}
// 禁用中断(在轮询模式下不需要)
XAxiDma_IntrDisable(AxiDma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrDisable(AxiDma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
return XST_SUCCESS;
}
int main() {
int Status;
u8 *TxBufferPtr = (u8 *)TX_BUFFER_BASE;
u8 *RxBufferPtr = (u8 *)RX_BUFFER_BASE;
xil_printf("connected\n");
// 初始化DMA0
Status = Init_DMA(&AxiDma0, DMA0_DEVICE_ID);
if (Status != XST_SUCCESS) {
xil_printf("DMA0 Initialization failed\r\n");
return XST_FAILURE;
}
// 初始化DMA1
Status = Init_DMA(&AxiDma1, DMA1_DEVICE_ID);
if (Status != XST_SUCCESS) {
xil_printf("DMA1 Initialization failed\r\n");
return XST_FAILURE;
}
// 准备数据
for(int i = 0; i < MAX_PKT_LEN; i++) {
xil_printf("%d",i);
TxBufferPtr[i] = i;
RxBufferPtr[i] = 0; // 清零接收缓冲区
}
xil_printf("\r\n");
Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, 30*4);
//刷新Cache中的数据搭配设备中
// 从内存通过DMA0向FIFO发送数据
Status = XAxiDma_SimpleTransfer(&AxiDma0, (UINTPTR)TxBufferPtr, MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
while (XAxiDma_Busy(&AxiDma0, XAXIDMA_DMA_TO_DEVICE)) {
/* 等待DMA0传输完成 */
}
Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, 30*4);
//刷新Cache中的数据搭配设备中
// 从FIFO通过DMA1接收数据回内存
Status = XAxiDma_SimpleTransfer(&AxiDma1, (UINTPTR)RxBufferPtr, MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
while (XAxiDma_Busy(&AxiDma1, XAXIDMA_DEVICE_TO_DMA)) {
/* 等待DMA1传输完成 */
}
// 验证数据
for (int i = 0; i < MAX_PKT_LEN; i++) {
if (TxBufferPtr[i] != RxBufferPtr[i]) {
xil_printf("Data mismatch: byte %d - TX %d != RX %d\r\n", i, TxBufferPtr[i], RxBufferPtr[i]);
return XST_FAILURE;
}
}
xil_printf("Test Passed\r\n");
return XST_SUCCESS;
}
在硬件上运行程序
在串口终端中查看结果
测试成功通过发送和接受的两个缓冲区结果一直
参考
教程参考的视频链接来源FPGA 30 - Zynq SoC FPGA Direct Memory Access (DMA) between PS DDR memory and PL AXI4-Stream FIFO