一、AXI DMA介绍
本篇博文讲述AXI DMA的一些使用总结,硬件IP子系统搭建与SDK C代码封装参考米联客ZYNQ教程。若想让ZYNQ的PS与PL两部分高速数据传输,需要利用PS的HP(高性能)接口通过AXI_DMA完成数据搬移,这正符合PG021 AXI DMA v7.1 LogiCORE IP Product Guide中介绍的AXI DMA的应用场景:The AXI DMA provides high-speed data movement between system memory and an AXI4-Stream-based target IP such as AXI Ethernet.
如图,AXI DMA主要包括Memory Map和 Stream两部分接口,前者连接PS子系统,后者则连接带有流接口的PL IP核。
其最简单的事直接寄存器模式(Simple DMA),这里需要注意地址对齐的问题:当没有使能地址重对齐的情况下,如果AXI Memory Map数据位宽是32bit,则搬移数据所在地址必须在0x0,0x4,0x8等起始地址上。接下来关注DMA IP核配置界面主要参数:
AXI DMA可以有两个传输方向:读通道和写通道,依次为MM2S和S2MM方向。也就是说“读”和“写”是DMA主动对CPU发起的操作。重点查看以下几个参数:
1 Width of Buffer Length Register:
在直接寄存器模式下,它指定在MM2S_LENGTH和S2MM_LENGTH寄存器的有效比特数。MM2S_LENGTH寄存器指定了MM2S通道传输数据字节数,当CPU写入非零值时开始进行PS到PL的数据搬移,而S2MM_LENGTH对应另一个数据流方向。比特数直接与对应寄存器可写入的最大数直接相关,传输最大字节数= 2^(Width of Buffer Length Register)。此处保持默认14bit,也就是说启动DMA传输的最大数据量是16384byte。
2 Memory Map Data Width:
该参数指定了Memory Map侧数据接口宽度,选定32bit后搬移数据所在内存地址必须与4对齐。
3 Max Burst Size:
之前在讲解PS子系统内部的DMA时介绍过DMA的Burst概念,即分批次传输数据块。官方IP核文档解释为:
理解起来burst size确定了突发周期的最大数值,也就是burst size越大,突发粒度越大(单次传输的数据个数越多)。这与PS端DMA有所区别,显然与 PS DMA的burst length意义相近。笔者也进行过尝试,当启动传输数据量相同时,burst size设置较大情况下,每批次传输数据量更多。
二、AXI DMA Loop IP子系统
在利用ZYNQ搭建系统时,经常需要利用各种IP核做所谓的“计算加速”,将重复性高 计算量大 占用较大CPU资源的底层处理交给各个IP核完成。这时PS ->DMA ->PL -> DMA -> PS的环路架构非常适用。这里使用AXI Stream Data FIFO代替自定义IP核作为演示,硬件IP子系统如下:
三、SDK 官方demo解析
首先分析下官方的demo。
1 /****************************************************************************** 2 * 3 * Copyright (C) 2010 - 2016 Xilinx, Inc. All rights reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * Use of the Software is limited solely to applications: 16 * (a) running on a Xilinx device, or 17 * (b) that interact with a Xilinx device through a bus or interconnect. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 * 27 * Except as contained in this notice, the name of the Xilinx shall not be used 28 * in advertising or otherwise to promote the sale, use or other dealings in 29 * this Software without prior written authorization from Xilinx. 30 * 31 ******************************************************************************/ 32 /*****************************************************************************/ 33 /** 34 * 35 * @file xaxidma_example_simple_intr.c 36 * 37 * This file demonstrates how to use the xaxidma driver on the Xilinx AXI 38 * DMA core (AXIDMA) to transfer packets.in interrupt mode when the AXIDMA core 39 * is configured in simple mode 40 * 41 * This code assumes a loopback hardware widget is connected to the AXI DMA 42 * core for data packet loopback. 43 * 44 * To see the debug print, you need a Uart16550 or uartlite in your system, 45 * and please set "-DDEBUG" in your compiler options. You need to rebuild your 46 * software executable. 47 * 48 * Make sure that MEMORY_BASE is defined properly as per the HW system. The 49 * h/w system built in Area mode has a maximum DDR memory limit of 64MB. In 50 * throughput mode, it is 512MB. These limits are need to ensured for 51 * proper operation of this code. 52 * 53 * 54 * <pre> 55 * MODIFICATION HISTORY: 56 * 57 * Ver Who Date Changes 58 * ----- ---- -------- ------------------------------------------------------- 59 * 4.00a rkv 02/22/11 New example created for simple DMA, this example is for 60 * simple DMA,Added interrupt support for Zynq. 61 * 4.00a srt 08/04/11 Changed a typo in the RxIntrHandler, changed 62 * XAXIDMA_DMA_TO_DEVICE to XAXIDMA_DEVICE_TO_DMA 63 * 5.00a srt 03/06/12 Added Flushing and Invalidation of Caches to fix CRs 64 * 648103, 648701. 65 * Added V7 DDR Base Address to fix CR 649405. 66 * 6.00a srt 03/27/12 Changed API calls to support MCDMA driver. 67 * 7.00a srt 06/18/12 API calls are reverted back for backward compatibility. 68 * 7.01a srt 11/02/12 Buffer sizes (Tx and Rx) are modified to meet maximum 69 * DDR memory limit of the h/w system built with Area mode 70 * 7.02a srt 03/01/13 Updated DDR base address for IPI designs (CR 703656). 71 * 9.1 adk 01/07/16 Updated DDR base address for Ultrascale (CR 799532) and 72 * removed the defines for S6/V6. 73 * 9.2 vak 15/04/16 Fixed compilation warnings in the example 74 * </pre> 75 * 76 * *************************************************************************** 77 */ 78 79 /***************************** Include Files *********************************/ 80 81 #include "xaxidma.h" 82 #include "xparameters.h" 83 #include "xil_exception.h" 84 #include "xdebug.h" 85 86 #ifdef XPAR_UARTNS550_0_BASEADDR 87 #include "xuartns550_l.h" /* to use uartns550 */ 88 #endif 89 90 91 #ifdef XPAR_INTC_0_DEVICE_ID 92 #include "xintc.h" 93 #else 94 #include "xscugic.h" 95 #endif 96 97 /************************** Constant Definitions *****************************/ 98 99 /* 100 * Device hardware build related constants. 101 */ 102 103 #define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID 104 105 #ifdef XPAR_AXI_7SDDR_0_S_AXI_BASEADDR 106 #define DDR_BASE_ADDR XPAR_AXI_7SDDR_0_S_AXI_BASEADDR 107 #elif XPAR_MIG7SERIES_0_BASEADDR 108 #define DDR_BASE_ADDR XPAR_MIG7SERIES_0_BASEADDR 109 #elif XPAR_MIG_0_BASEADDR 110 #define DDR_BASE_ADDR XPAR_MIG_0_BASEADDR 111 #elif XPAR_PSU_DDR_0_S_AXI_BASEADDR 112 #define DDR_BASE_ADDR XPAR_PSU_DDR_0_S_AXI_BASEADDR 113 #endif 114 115 #ifndef DDR_BASE_ADDR 116 #warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \ 117 DEFAULT SET TO 0x01000000 118 #define MEM_BASE_ADDR 0x01000000 119 #else 120 #define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x1000000) 121 #endif 122 123 #ifdef XPAR_INTC_0_DEVICE_ID 124 #define RX_INTR_ID XPAR_INTC_0_AXIDMA_0_S2MM_INTROUT_VEC_ID 125 #define TX_INTR_ID XPAR_INTC_0_AXIDMA_0_MM2S_INTROUT_VEC_ID 126 #else 127 #define RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID 128 #define TX_INTR_ID XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID 129 #endif 130 131 #define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) 132 #define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000) 133 #define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF) 134 135 #ifdef XPAR_INTC_0_DEVICE_ID 136 #define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID 137 #else 138 #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID 139 #endif 140 141 #ifdef XPAR_INTC_0_DEVICE_ID 142 #define<