前言

  在ZYNQ中进行PL-PS数据交互的时候,经常会使用到DMA,其实在前面的ZYNQ学习当中,也有学习过DMA的使用,那就是通过使用自定义的IP,完成HP接口向内存写入和读取数据的方式。同样Xilinx官方也提供有一些DMA的IP,通过调用API函数能够更加灵活地使用DMA。

1. AXI DMA的基本接口

  axi dma IP的基本结构如下,主要分为三个部分,分别是控制axi dma寄存器通道,从ddr读出数据通道和向ddr写入数据通道。其IP结构的两边分别对应着用于访问内存的AXI总线和用于用户简单操作的axis stream总线。axi stream总线相较于axi总线来说要简单很多,它没有地址,靠主机和从机之间进行握手来传递数据。

2 Block design搭建

  做一个简单的例子来测试一下axi dma。先自定义一个IP,用于缓存从zynq通过axi dma发来的数据,一次突发传输结束之后,将接收到的数据写回到内存中。

2.1 自定义一个IP

  时序设计如下,将接收到的数据缓存到FIFO中,当zynq一次axi stream 传输结束的时候,开始将数据从FIFO中读出,并将数据写入到内存中。

module dma_loop(//====================================================//clock and reset//====================================================input   wire            axis_clk            ,input   wire            rst_n               ,//====================================================//input axis port//====================================================input   wire    [7:0]   axis_in_tdata       ,input   wire            axis_in_tvalid      ,output  wire            axis_in_tready      ,input   wire            axis_in_tlast       ,//====================================================//output axis port//====================================================output  wire    [7:0]   axis_out_tdata      ,output  reg             axis_out_tvalid     ,input   wire            axis_out_tready     ,output  wire            axis_out_tlast
);//====================================================
//input axis port
//====================================================
wire            wr_fifo_en      ;
wire            rd_fifo_en      ;
wire            full,empty      ;
reg             rd_start        ;
reg     [9:0]   cnt_data_in     ;
wire            add_cnt_data_in ;
wire            end_cnt_data_in ;
reg     [9:0]   data_len        ;reg     [9:0]   cnt_data_out    ;
wire            add_cnt_data_out;
wire            end_cnt_data_out;assign wr_fifo_en = axis_in_tvalid & axis_in_tready;
assign axis_in_tready = ~full;always @(posedge axis_clk or negedge rst_n) beginif (rst_n==1'b0) beginrd_start <= 1'b0;endelse if (axis_in_tvalid & axis_in_tready & axis_in_tlast) beginrd_start <= 1'b1;endelse beginrd_start <= 1'b0;end
end
//----------------cnt_data------------------
always @(posedge axis_clk or negedge rst_n) beginif (rst_n == 1'b0) begincnt_data_in <= 'd0;endelse if (add_cnt_data_in) beginif(end_cnt_data_in)cnt_data_in <= 'd0;elsecnt_data_in <= cnt_data_in + 1'b1;endendassign add_cnt_data_in = axis_in_tvalid & axis_in_tready;
assign end_cnt_data_in = add_cnt_data_in && axis_in_tlast;//----------------data_len------------------
always @(posedge axis_clk or negedge rst_n) beginif (rst_n==1'b0) begindata_len <= 'd0;endelse if (end_cnt_data_in) begindata_len <= cnt_data_in + 1'b1;end
endsfifo_wr1024x8_rd1024x8 inst_sfifo (.clk(axis_clk),         // input wire clk.din(axis_in_tdata),    // input wire [7 : 0] din.wr_en(wr_fifo_en),     // input wire wr_en.rd_en(rd_fifo_en),     // input wire rd_en.dout(axis_out_tdata),  // output wire [7 : 0] dout.full(full),            // output wire full.empty(empty)           // output wire empty
);//----------------axis_out_tvalid------------------
always @(posedge axis_clk or negedge rst_n) beginif (rst_n==1'b0) beginaxis_out_tvalid <= 1'b0;endelse if (end_cnt_data_out) beginaxis_out_tvalid <= 1'b0;endelse if (rd_start == 1'b1) beginaxis_out_tvalid <= 1'b1;end
end//----------------cnt_data_out------------------
always @(posedge axis_clk or negedge rst_n) beginif (rst_n == 1'b0) begincnt_data_out <= 'd0;endelse if (add_cnt_data_out) beginif(end_cnt_data_out)cnt_data_out <= 'd0;elsecnt_data_out <= cnt_data_out + 1'b1;end
endassign add_cnt_data_out = axis_out_tvalid & axis_out_tready;
assign end_cnt_data_out = add_cnt_data_out && cnt_data_out == data_len - 1;assign axis_out_tlast =  end_cnt_data_out;
assign rd_fifo_en = axis_out_tvalid & axis_out_tready;wire [63:0] probe0;assign probe0 = {cnt_data_in         ,cnt_data_out        ,rd_start            ,data_len            ,axis_in_tdata       ,axis_in_tvalid      ,axis_in_tready      ,axis_in_tlast       ,axis_out_tdata      ,axis_out_tvalid     ,axis_out_tready     ,axis_out_tlast
};ila_0 inst_ila (.clk(axis_clk), // input wire clk.probe0(probe0) // input wire [63:0] probe0
);endmodule

搭建block design

3. vitis

   xilinx的东西就有这点优点,基本上fpga里面有的资源,都有一个示例工程,把它导入进来就可以参考一下具体这个外设改怎么来使用了。这个demo里面使用到了串口。串口在前面的串口中断中已经使用到,本次实验需要使用到串口的中断和DMA的中断。
  PC的串口向FPGA发送数据,一帧数据发送完成之后,会触发串口的中断。串口中断函数会接收数据,并且记录数据长度。然后将通过DMA将数据写入到自定义的IP当中,自定义IP接收完数据之后,将把数据写回到内存中。

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xaxidma.h"
#include "xuartps.h"
#include "xscugic.h"
#include "sleep.h"#define GIC_DEVICE_ID   XPAR_PS7_SCUGIC_0_DEVICE_ID
#define UART_DEV_ID     XPAR_PS7_UART_1_DEVICE_ID
#define DMA_DEVICE_ID   XPAR_AXI_DMA_0_DEVICE_ID#define UART_INTR_ID    XPAR_PS7_UART_1_INTR
#define MM2S_INTR_ID    XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID
#define S2MM_INTR_ID    XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_IDXUartPs UartInst;
XScuGic GicInst;
XAxiDma DmaInst;volatile int TxDone;
volatile int RxDone;
volatile int Error;u32 UartRxLen = 0;
int UartRxFlag = 0;
u8 * UartRxBuf = (u8 *)(0x2000000);
u8 * UartTxBuf = (u8 *)(0x4000000);
/************************************ Uart Init function**********************************/
int Uart_Init();
/********************************* DMA initialize function********************************/
int Dma_Init();int Setup_Interrupt_System();void Uart_Intr_Handler(void *CallBackRef, u32 Event, unsigned int EventData);void Mm2s_Intr_Handler();
void S2mm_Intr_Handler();int main()
{init_platform();Uart_Init();Dma_Init();Setup_Interrupt_System();while(1){/****************************************************************************** Uart has receive one frame*****************************************************************************/if (UartRxFlag == 1) {// clear the flagUartRxFlag = 0;/****************************************************************************** Transfer data from axidma to device*****************************************************************************/Xil_DCacheFlushRange((INTPTR)UartRxBuf, UartRxLen);//flush data into ddrusleep(2);// transfer data from axi dma to deviceXAxiDma_SimpleTransfer(&DmaInst, (UINTPTR)UartRxBuf, UartRxLen, XAXIDMA_DMA_TO_DEVICE);while(!TxDone);TxDone=0;//reset txdone flag; complete  txtransfer/****************************************************************************** Transfer data from device to dma*****************************************************************************/Xil_DCacheInvalidateRange((INTPTR)UartTxBuf, UartRxLen);usleep(2);XAxiDma_SimpleTransfer(&DmaInst, (UINTPTR)UartTxBuf, UartRxLen, XAXIDMA_DEVICE_TO_DMA);while(!RxDone);RxDone = 0;XUartPs_Send(&UartInst, UartTxBuf, UartRxLen);XUartPs_Recv(&UartInst, UartRxBuf, 4096);//reset conter and start recv from uart}}cleanup_platform();return 0;
}/****************************************************************************** @ function : init uart and set the callback fuction
*****************************************************************************/
int Uart_Init()
{int Status;u32 IntrMask;XUartPs_Config *UartCfgPtr;UartCfgPtr = XUartPs_LookupConfig(UART_DEV_ID);Status = XUartPs_CfgInitialize(&UartInst, UartCfgPtr, UartCfgPtr->BaseAddress);if(Status != XST_SUCCESS){printf("initialize UART failed\n");return XST_FAILURE;}/***************************************** Set uart interrput mask****************************************/IntrMask =XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY | XUARTPS_IXR_FRAMING |XUARTPS_IXR_OVER | XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXFULL |XUARTPS_IXR_RXOVR;XUartPs_SetInterruptMask(&UartInst, IntrMask);/****************************************************************************** Set Uart interrput callback function*****************************************************************************/XUartPs_SetHandler(&UartInst, (XUartPs_Handler)Uart_Intr_Handler, &UartInst);/****************************************************************************** Set Uart baud rate*****************************************************************************/XUartPs_SetBaudRate(&UartInst, 115200);/****************************************************************************** Set Uart opertion mode*****************************************************************************/XUartPs_SetOperMode(&UartInst, XUARTPS_OPER_MODE_NORMAL);/****************************************************************************** Set Uart Receive timeout*****************************************************************************/XUartPs_SetRecvTimeout(&UartInst, 8);/****************************************************************************** Start to listen*****************************************************************************/XUartPs_Recv(&UartInst, UartRxBuf, 4096);return Status;
}void Uart_Intr_Handler(void *CallBackRef, u32 Event, unsigned int EventData)
{if (Event == XUARTPS_EVENT_RECV_TOUT) {if(EventData == 0){XUartPs_Recv(&UartInst, UartRxBuf, 4096);}else if(EventData > 0) {UartRxLen = EventData;UartRxFlag = 1;}}
}/****************************************************************************** @ function : init Axi DMA
*****************************************************************************/
int Dma_Init()
{int Status;XAxiDma_Config * DmaCfgPtr;DmaCfgPtr = XAxiDma_LookupConfig(DMA_DEVICE_ID);Status = XAxiDma_CfgInitialize(&DmaInst, DmaCfgPtr);if(Status != XST_SUCCESS){printf("initialize AXI DMA failed\n");return XST_FAILURE;}/****************************************************************************** Disable all the interrupt before setup*****************************************************************************/XAxiDma_IntrDisable(&DmaInst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);XAxiDma_IntrDisable(&DmaInst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);/******************************************************************************Enable all the interrput*****************************************************************************/XAxiDma_IntrEnable(&DmaInst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);XAxiDma_IntrEnable(&DmaInst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);return Status;
}
/*****************************************************************************/
/*
*
* This is the DMA TX Interrupt handler function.
*
* It gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. Otherwise, if a completion interrupt
* is present, then sets the TxDone.flag
*
* @param   Callback is a pointer to TX channel of the DMA engine.
*
* @return  None.
*
* @note        None.
*
******************************************************************************/
void Mm2s_Intr_Handler(void *Callback)
{u32 IrqStatus;int TimeOut;XAxiDma *AxiDmaInst = (XAxiDma *)Callback;/* Read pending interrupts */IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE);/* Acknowledge pending interrupts */XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);/** If no interrupt is asserted, we do not do anything*/if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {return;}/** If error interrupt is asserted, raise error flag, reset the* hardware to recover from the error, and return with no further* processing.*/if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {Error = 1;/** Reset should never fail for transmit channel*/XAxiDma_Reset(AxiDmaInst);TimeOut = 10000;while (TimeOut) {if (XAxiDma_ResetIsDone(AxiDmaInst)) {break;}TimeOut -= 1;}return;}/** If Completion interrupt is asserted, then set the TxDone flag*/if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {TxDone = 1;}
}/*****************************************************************************/
/*
*
* This is the DMA RX interrupt handler function
*
* It gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. Otherwise, if a completion interrupt
* is present, then it sets the RxDone flag.
*
* @param   Callback is a pointer to RX channel of the DMA engine.
*
* @return  None.
*
* @note        None.
*
******************************************************************************/
void S2mm_Intr_Handler(void *Callback)
{u32 IrqStatus;int TimeOut;XAxiDma *AxiDmaInst = (XAxiDma *)Callback;/* Read pending interrupts */IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);/* Acknowledge pending interrupts */XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);/** If no interrupt is asserted, we do not do anything*/if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {return;}/** If error interrupt is asserted, raise error flag, reset the* hardware to recover from the error, and return with no further* processing.*/if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {Error = 1;/* Reset could fail and hang* NEED a way to handle this or do not call it??*/XAxiDma_Reset(AxiDmaInst);TimeOut = 10000;while (TimeOut) {if(XAxiDma_ResetIsDone(AxiDmaInst)) {break;}TimeOut -= 1;}return;}/** If completion interrupt is asserted, then set RxDone flag*/if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {RxDone = 1;}
}/****************************************************************************** @ function : Set up the interrupt system
*****************************************************************************/
int Setup_Interrupt_System()
{int Status;XScuGic_Config * GicCfgPtr;GicCfgPtr = XScuGic_LookupConfig(GIC_DEVICE_ID);Status = XScuGic_CfgInitialize(&GicInst, GicCfgPtr, GicCfgPtr->CpuBaseAddress);if(Status != XST_SUCCESS){printf("initialize GIC failed\n");return XST_FAILURE;}/****************************************************************************** initialize exception system*****************************************************************************/Xil_ExceptionInit();/****************************************************************************** register interrput type exception*****************************************************************************/Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler, &GicInst);/****************************************************************************** connect interrput to scugic controller*****************************************************************************/Status = XScuGic_Connect(&GicInst, UART_INTR_ID, (Xil_ExceptionHandler) XUartPs_InterruptHandler, &UartInst);if(Status != XST_SUCCESS){printf("Connect Uart interrput to GIC failed\n");return XST_FAILURE;}Status = XScuGic_Connect(&GicInst, MM2S_INTR_ID, (Xil_ExceptionHandler) Mm2s_Intr_Handler, &DmaInst);if(Status != XST_SUCCESS){printf("Connect DMA tx interrput to GIC failed\n");return XST_FAILURE;}Status = XScuGic_Connect(&GicInst, S2MM_INTR_ID, (Xil_ExceptionHandler) S2mm_Intr_Handler, &DmaInst);if(Status != XST_SUCCESS){printf("Connect DMA tx interrput to GIC failed\n");return XST_FAILURE;}/****************************************************************************** Enable the interrput*****************************************************************************/XScuGic_Enable(&GicInst, UART_INTR_ID);XScuGic_Enable(&GicInst, S2MM_INTR_ID);XScuGic_Enable(&GicInst, MM2S_INTR_ID);/****************************************************************************** Enable the exception system*****************************************************************************/Xil_ExceptionEnable();return Status;
}

测试结果


  从串口发出的数据被成功的接收。再看看ila抓取到的波形。

  输入到自定义IP的数据:
   从自定义IP输出的数据。一次传输之间隔了较长的时间。

ZYNQ基础---AXI DMA使用相关推荐

  1. ZYNQ学习之路11.AXI DMA

    一. AXI DMA简介 AXI DMA IP核提供了AXI4内存之间或AXI4-Stream IP之间的内存直接访问,可选为分散收集工作模式,初始化,状态和管理寄存器等通过AXI4-Lite 从机几 ...

  2. ZYNQ | AXI DMA数据环路测试

    利用AXI DMA进行批量数据环路的测试 背景 软硬件平台 原理概述 工程搭建 1.新建一个vivado工程 2.创建block design ①zynq ip核的添加与配置 ②AXI DMA ip核 ...

  3. zynq板zedboard+vitis设计(二)AXI DMA

    前言 本期将AXI DMA的写入与读取的测试,一些工程建立的详细步骤在第一次文章已经详细介绍了,此处不再赘述. 1.vivado中建立Block Design并导出hardware 新建vivado工 ...

  4. ZYNQ基础系列(四) DMA基本用法

    DMA 环路测试 涉及到高速数据传输时,DMA就显得非常重要了,本文的DMA主要是对PL侧的AXI DMA核进行介绍(不涉及PS侧的DMA控制器).AXI DMA的用法基本是:PS通过AXI-lite ...

  5. xilinx axi dma 深入开发(一)

    以下为官方 axidma-proxy 源码 /*** Copyright (C) 2021 Xilinx, Inc** Licensed under the Apache License, Versi ...

  6. AXI DMA测试-AXI总线最后一章

    AXI DMA测试 增加一个AXIDMA章节,这部分内容是很多例程的基础,难度不大但是也不小,需要彻底理解整个运行机制. 图4‑61 测试框图 处理器通过M_AXI_GP0接口和AXI_DMA通信,以 ...

  7. zcu104 AXI DMA速度测试总结

    一.前言 好久没有认真的写一些技术博客了,工作半年了,最近两个月好像才慢慢的恢复过来了,不能摸鱼了,2020年,自己的生活中会有很多可见的变化,要快速成长啊,具备与之匹配的技术和能力啊. 二.PL侧工 ...

  8. ZU9 AXI DMA使用问题-收发数据过程和时序关系AXISTREAM FIFO - GTH结合问题

    首先参考如下文章,给了我很大启发,我这部分复位确实是按照环路做的,避开了坑.而我的设计中PL端时钟和PS端不是一个时钟,就出现了各种问题 ZYNQ AXI DMA使用问题_AE_小良的博客-CSDN博 ...

  9. Xilinx HLS实现AXI DMA

    在本文中,我们将通过HLS自己动手实现一个AXI DMA,仿照的是官方AXI DMA IP核的直接模式,即给定发送起始地址和发送长度,以及接收起始地址和接收长度,就能进行一次DMA传输. HLS设计 ...

最新文章

  1. 【学习笔记】项目Leader如何成长
  2. 用SHA1或MD5 算法加密数据(示例:对用户身份验证的简单实现)
  3. 给自己的网址加上https,添加ssl证书(springboot项目)
  4. 华为等上榜全球100大最具影响力企业;猫扑关闭发帖功能;亚马逊要给逾50万名员工加薪 |极客头条...
  5. java 下载项目中的文件_java 下载web项目目录下的文件
  6. Linux时间子系统之(四):timekeeping
  7. ununtu16.04+python3+selenium+firefox环境搭建
  8. Louvain 算法的核心思路以及数据结构(最完善版)
  9. telnet 测试IP和端口命令
  10. 简单聊聊01世界中编码和解码这对磨人的小妖儿
  11. 构词法——现代单词记忆十大规律
  12. 阿里聚安全 博客 ------安卓动态调试七种武器之长生剑
  13. IO虚拟化 - virtio-blk前端驱动分析【转】
  14. 针对Faster RCNN具体细节以及源码的解读之SmoothL1Loss层
  15. Android程序打包安装过程
  16. 数据科学竞赛经验分享:你从未见过的究极进化秘笈
  17. 《低代码指南100解决方案》——5疫情防控常态化之下,如何做好访客管理?
  18. Linux Oracle install studing
  19. 编写SQL语句,从Customers表中检索所有的ID(cust_id)
  20. Tensorflow2中Kares自定义损失函数

热门文章

  1. 需要谈谈的游戏测试(五)
  2. 状态机的Verilog写法
  3. 实测有效防止colab自动断开连接
  4. 怎么通过DELL服务器的iDrac口查看硬件信息 192.168.0.120 root calvin
  5. 凤凰金融邢志峰:人工智能打败人类只是一个开始,AI真正落地业务场景仍面临严峻挑战
  6. infoq_InfoQ案例研究:纳斯达克市场重播
  7. android权限声明
  8. Python实现决策树回归模型(DecisionTreeRegressor算法)并应用网格搜索算法调优项目实战
  9. 内存函数-----Memcpy函数
  10. D3.js中Bullet Charts详解