基于Zynq 配置DMA在PS DDR 端和在PL AXI-Stream FIFO

本文详细介绍了如何在Vivado中配置PynqZ2板的blockdesign,包括设置PS-PL间的AXI接口,添加AXI_DMA模块,以及使用Vitis进行HLS编程和DMA操作,最终导出硬件XSA文件并测试读写功能。
摘要由CSDN通过智能技术生成

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

  • 24
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值