ZYNQ裸板简单实战-AXIDMA篇(简单模式)

前言

  DMA(Direct Memory Access,直接存储器访问)是计算机科学中的一种内存访问技术。它允许某些计算机内部的硬件子系统可以独立地直接读写系统内存,而不需中央处理器( CPU)介入处理。 DMA 是一种快速的数据传送方式, 通常用来传送数据量较多的数据块
  使用 DMA时, CPU 向 DMA 控制器发出一个存储传输请求, 这样当 DMA 控制器在传输的时候, CPU 执行其它操作,传输操作完成时 DMA 以中断的方式通知 CPU。
  为了发起传输事务, DMA 控制器必须得到以下数据:
• 源地址 — 数据被读出的地址
• 目的地址 — 数据被写入的地址
• 传输长度 — 应被传输的字节数
在这里插入图片描述
DMA 存储传输的过程如下:

  1. 为了配置用 DMA 传输数据到存储器,处理器发出一条 DMA 命令
  2. DMA 控制器把数据从外设传输到存储器或从存储器到存储器,而让 CPU 腾出手来做其它操作。
  3. 数据传输完成后,向 CPU 发出一个中断来通知它 DMA 传输可以关闭了。ZYNQ 提供了两种 DMA,一种是集成在 PS 中的硬核 DMA,另一种是 PL 中使用的软核 AXI DMA IP。
    在 ARM CPU 设计的过程中,已经考虑到了大量数据搬移的情况,因此在 CPU 中自带了一个 DMA 控制器 DAMC,这个 DAMC 驻留在 PS 内,而且必须通过驻留在内存中的 DMA 指令编程,这些程序往往由CPU 准备,因此需要部分的 CPU 参与。 DMAC 支持高达 8 个通道,所以多个 DMA 结构的核可以挂在单个DMAC 上。 DAMC 与 PL 的连接是通过 AXI_GP 接口,这个接口最高支持到 32 位宽度,这也限制了这种模式下的传输速率,理论最高速率为 600MB/s。这种模式不占用 PL 资源,但需要对 DMA 指令编程,会增加软件的复杂性。
    为了获取更高的传输速率,可以以空间换时间,在 PL 中添加 AXI DMA IP 核,并利用 AXI_HP 接口完成高速的数据传输。原子将各个接口方式的比较做了表格,很是详细
    在这里插入图片描述
      可见通过 PL 的 DMA 和 AXI_HP 接口的传输适用于大块数据的高性能传输,带宽高。
      下面我们简单的介绍下 PL 的 DMA,即 AXI DMA IP 核。
      AXI Direct Memory Access( AXI DMA) IP 内核在 AXI4 内存映射和 AXI4-Stream IP 接口之间提供高带宽直接储存访问。其可选的 scatter gather 功能还可以从基于处理器的系统中的中央处理单元( CPU)卸载数据移动任务。初始化、 状态和管理寄存器通过 AXI4-Lite 从接口访问。核心的功能组成如下图所示:
    在这里插入图片描述
      AXI DMA 用到了三种总线, AXI4-Lite 用于对寄存器进行配置, AXI4 Memory Map 用于与内存交互,又分为 AXI4 Memory Map Read 和 AXI4 Memory Map Write 两个接口,一个是读一个是写。 AXI4 Stream 接口用于对外设的读写,其中 AXI4 Stream Master( MM2S, Memory Map to Stream)用于对外设写, AXI4-Stream Slave(S2MM, Stream to Memory Map)用于对外设读。总之,在以后的使用中需要知道 AXI_MM2S 和AXI_S2MM 是存储器端映射的 AXI4 总线,提供对存储器( DDR3)的访问。 AXIS_MM2S 和 AXIS_S2MM是 AXI4-streaming 总线,可以发送和接收连续的数据流,无需地址。
      AXI DMA 提供 3 种模式,分别是 Direct Register 模式、 Scatter/Gather 模式和 Cyclic DMA 模式,这里我们简单的介绍下常用的 Direct Register 模式和 Scatter/Gather 模式。
      Direct Register DMA 模式也就是 Simple DMA。 Direct Register 模式提供了一种配置,用于在 MM2S 和S2MM 通道上执行简单的 DMA 传输,这需要更少的 FPGA 资源。 Simple DMA 允许应用程序在 DMA 和Device 之间定义单个事务。它有两个通道:一个从 DMA 到 Device,另一个从 Device 到 DMA。应用程序必须设置缓冲区地址和长度字段以启动相应通道中的传输。
      Scatter/Gather DMA 模式允许在单个 DMA 事务中将数据传输到多个存储区域或从多个存储区域传输数据。它相当于将多个 Simple DMA 请求链接在一起。 SGDMA 允许应用程序在内存中定义事务列表,硬件将在应用程序没有进一步干预的情况下处理这些事务。在此期间,应用程序可以继续添加更多工作以保持硬件工作。用户可以通过轮询或中断来检查事务是否完成。 SGDMA 处理整个数据包( 被定义为表示消息的一系列数据字节)并允许将数据包分解为一个或多个事务。例如,采用以太网 IP 数据包,该数据包由 14 字节的报头后跟 1 个或多个字节的有效负载组成。使用 SGDMA,应用程序可以将 BD( Buffer Descriptor, 用于描述事务的对象) 指向报头,将另一个 BD 指向有效负载,然后将它们作为单个消息传输。这种策略可以使TCP / IP 堆栈更有效,它允许将数据包标头和数据保存在不同的内存区域,而不是将数据包组装成连续的内存块。
      在此次的工程中暂时用不到SG模式,如果用sata这些的话估计得用到了,正常情况下简单模式还是够用的
    下面做一个简单的AXIDMA初始化和收发demo测试
    头文件如下
#ifndef SRC_XDMA_DRIVER_H_
#define SRC_XDMA_DRIVER_H_



#include "xaxidma.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"

#ifdef XPAR_UARTNS550_0_BASEADDR
#include "xuartns550_l.h"       /* to use uartns550 */
#endif

#ifdef XPAR_INTC_0_DEVICE_ID
 #include "xintc.h"
#else
 #include "xscugic.h"
#endif

#include "xgpiops.h"

/************************** Constant Definitions *****************************/

/*
 * Device hardware build related constants.
 */

#define DMA_DEV_ID		XPAR_AXIDMA_0_DEVICE_ID

#ifdef XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
#define DDR_BASE_ADDR		XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
#elif XPAR_MIG7SERIES_0_BASEADDR
#define DDR_BASE_ADDR	XPAR_MIG7SERIES_0_BASEADDR
#elif XPAR_MIG_0_BASEADDR
#define DDR_BASE_ADDR	XPAR_MIG_0_BASEADDR
#elif XPAR_PSU_DDR_0_S_AXI_BASEADDR
#define DDR_BASE_ADDR	XPAR_PSU_DDR_0_S_AXI_BASEADDR
#endif

#ifndef DDR_BASE_ADDR
#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \
		DEFAULT SET TO 0x01000000
#define MEM_BASE_ADDR		0x01000000
#else
#define MEM_BASE_ADDR		(DDR_BASE_ADDR + 0x1000000)
#endif

#ifdef XPAR_INTC_0_DEVICE_ID
#define RX_INTR_ID		XPAR_INTC_0_AXIDMA_0_S2MM_INTROUT_VEC_ID
#define TX_INTR_ID		XPAR_INTC_0_AXIDMA_0_MM2S_INTROUT_VEC_ID
#else
//#define RX_INTR_ID		XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID
//#define TX_INTR_ID		XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID
#endif

#define TX_BUFFER_BASE		(MEM_BASE_ADDR + 0x00100000)
#define TX_BUFFER_BASE1		(MEM_BASE_ADDR + 0x00101000)
#define TX_BUFFER_BASE2		(MEM_BASE_ADDR + 0x00102000)
#define TX_BUFFER_BASE3		(MEM_BASE_ADDR + 0x00103000)
#define RX_BUFFER_BASE		(MEM_BASE_ADDR + 0x00300000)
#define RX_BUFFER_BASE1		(MEM_BASE_ADDR + 0x00301000)
#define RX_BUFFER_BASE2 	(MEM_BASE_ADDR + 0x00302000)
#define RX_BUFFER_BASE3		(MEM_BASE_ADDR + 0x00303000)
#define RX_BUFFER_HIGH		(MEM_BASE_ADDR + 0x004FFFFF)

#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC_DEVICE_ID          XPAR_INTC_0_DEVICE_ID
#else
#define INTC_DEVICE_ID          XPAR_SCUGIC_SINGLE_DEVICE_ID
#endif

#ifdef XPAR_INTC_0_DEVICE_ID
 #define INTC		XIntc
 #define INTC_HANDLER	XIntc_InterruptHandler
#else
 #define INTC		XScuGic
 #define INTC_HANDLER	XScuGic_InterruptHandler
#endif


extern XAxiDma AxiDma;		/* Instance of the XAxiDma */
extern XAxiDma AxiDma1;		/* Instance of the XAxiDma */
extern XAxiDma AxiDma2;		/* Instance of the XAxiDma */
extern XAxiDma AxiDma3;		/* Instance of the XAxiDma */

/* Timeout loop counter for reset
 */
#define RESET_TIMEOUT_COUNTER	10000

#define TEST_START_VALUE	0xC
/*
 * Buffer and Buffer Descriptor related constant definition
 */
#define MAX_PKT_LEN		0x100

#define NUMBER_OF_TRANSFERS	10


static XGpioPs Gpio; /* The Instance of the GPIO Driver */

/* The interrupt coalescing threshold and delay timer threshold
 * Valid range is 1 to 255
 *
 * We set the coalescing threshold to be the total number of packets.
 * The receive side will only get one completion interrupt for this example.
 */

/************* Type Definitions ******************/


/***** Macros (Inline Functions) Definitions **********/


/************* Function Prototypes **************/
#ifndef DEBUG
extern void xil_printf(const char *format, ...);
#endif

#ifdef XPAR_UARTNS550_0_BASEADDR
 void Uart550_Setup(void);
#endif

static int CheckData(int Length, u8 StartValue);
//static void TxIntrHandler(void *Callback);
//static void RxIntrHandler(void *Callback);


int dma_init(void);
int dma_8_10b_send(XAxiDma* AxiDmaIns,u8 *wBuffer , unsigned int length);
unsigned int dma_8_10b_recv(XAxiDma* AxiDmaIns,u8 *rBuffer);


static int SetupIntrSystem(INTC * IntcInstancePtr,
			   XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId);
static void DisableIntrSystem(INTC * IntcInstancePtr,
					u16 TxIntrId, u16 RxIntrId);

 int SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio,
				u16 GpioIntrId);

static void TxIntrHandler(AxiDma);
static void RxIntrHandler(AxiDma);

/************** Variable Definitions ****************/
/*
 * Device instance definitions
 */
static INTC Intc;	/* Instance of the Interrupt Controller */
/*
 * Flags interrupt handlers use to notify the application context the events.
 */
volatile int TxDone;
volatile int DMA0RxDone;
volatile int DMA1RxDone;
volatile int DMA2RxDone;
volatile int DMA3RxDone;
volatile int Error;
#endif /* SRC_XDMA_DRIVER_H_ */

驱动文件如下

#include "xdma_driver.h"

XAxiDma AxiDma;		/* Instance of the XAxiDma */
XAxiDma AxiDma1;		/* Instance of the XAxiDma */
XAxiDma AxiDma2;		/* Instance of the XAxiDma */
XAxiDma AxiDma3;		/* Instance of the XAxiDma */

#ifdef XPAR_UARTNS550_0_BASEADDR
/*****************************************************************************/
/*
*
* Uart16550 setup routine, need to set baudrate to 9600 and data bits to 8
*
* @param	None
*
* @return	None
*
* @note		None.
*
******************************************************************************/
extern void Uart550_Setup(void)
{
    
    

	XUartNs550_SetBaud(XPAR_UARTNS550_0_BASEADDR,
			XPAR_XUARTNS550_CLOCK_HZ, 9600);

	XUartNs550_SetLineControlReg(XPAR_UARTNS550_0_BASEADDR,
			XUN_LCR_8_DATA_BITS);
}
#endif

/*****************************************************************************/
/*
*
* This function checks data buffer after the DMA transfer is finished.
*
* We use the static tx/rx buffers.
*
* @param	Length is the length to check
* @param	StartValue is the starting value of the first byte
*
* @return
*		- XST_SUCCESS if validation is successful
*		- XST_FAILURE if validation is failure.
*
* @note		None.
*
******************************************************************************/
int CheckData(int Length, u8 StartValue)
{
    
    
	u8 *RxPacket;
	int Index = 0;
	u8 Value;

	RxPacket = (u8 *) RX_BUFFER_BASE;
	Value = StartValue;

	/* Invalidate the DestBuffer before receiving the data, in case the
	 * Data Cache is enabled
	 */
#ifndef __aarch64__
	Xil_DCacheInvalidateRange((UINTPTR)RxPacket, Length);
#endif

	for(Index = 0; Index < Length; Index++) {
    
    
		if (RxPacket[Index] != Value)
		{
    
    
			xil_printf("Data error %d: %x/%x\r\n",
			    Index, RxPacket[Index], Value);

			return XST_FAILURE;
		}
		Value = (Value + 1) & 0xFF;
	}

	return XST_SUCCESS;
}

/*****************************************************************************/
/*
*
* 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.
*
******************************************************************************/
//static void TxIntrHandler(void *Callback)
static void TxIntrHandler(XAxiDma *AxiDma)
{
    
    

	u32 IrqStatus;
	int TimeOut;
	//XAxiDma *AxiDmaInst = (XAxiDma *)Callback;

	/* Read pending interrupts */
	IrqStatus = XAxiDma_IntrGetIrq(AxiDma, XAXIDMA_DMA_TO_DEVICE);

	/* Acknowledge pending interrupts */

	XAxiDma_IntrAckIrq(AxiDma, 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(AxiDma);

		TimeOut = RESET_TIMEOUT_COUNTER;

		while (TimeOut) {
    
    
			if (XAxiDma_ResetIsDone(AxiDma)) {
    
    
				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.
*
******************************************************************************/
//static void RxIntrHandler(void *Callback)
static void RxIntrHandler(XAxiDma *AxiDmaIns )
{
    
    
	u32 IrqStatus;
	int TimeOut;
	//XAxiDma *AxiDmaInst = (XAxiDma *)Callback;

	/* Read pending interrupts */
	IrqStatus = XAxiDma_IntrGetIrq(AxiDmaIns, XAXIDMA_DEVICE_TO_DMA);

	/* Acknowledge pending interrupts */
	XAxiDma_IntrAckIrq(AxiDmaIns, 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(AxiDmaIns);

		TimeOut = RESET_TIMEOUT_COUNTER;

		while (TimeOut) {
    
    
			if(XAxiDma_ResetIsDone(AxiDmaIns)) {
    
    
				break;
			}

			TimeOut -= 1;
		}

		return;
	}

	/*
	 * If completion interrupt is asserted, then set RxDone flag
	 */
	if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK))
	{
    
    
		if(AxiDmaIns == &AxiDma)
		{
    
    
		    DMA0RxDone = 1;
		}
		else if(AxiDmaIns == &AxiDma1)
		{
    
    
			DMA1RxDone = 1;
		}
		else if(AxiDmaIns == &AxiDma2)
		{
    
    
			DMA2RxDone = 1;
		}
		else if(AxiDmaIns == &AxiDma3)
		{
    
    
			DMA3RxDone = 1;
		}
	}
}

/*****************************************************************************/
/*
*
* This function setups the interrupt system so interrupts can occur for the
* DMA, it assumes INTC component exists in the hardware system.
*
* @param	IntcInstancePtr is a pointer to the instance of the INTC.
* @param	AxiDmaPtr is a pointer to the instance of the DMA engine
* @param	TxIntrId is the TX channel Interrupt ID.
* @param	RxIntrId is the RX channel Interrupt ID.
*
* @return
*		- XST_SUCCESS if successful,
*		- XST_FAILURE.if not succesful
*
* @note		None.
*
******************************************************************************/
static void IntrHandler(void *CallBackRef, u32 Bank, u32 Status)
{
    
    

	XGpioPs *Gpio = (XGpioPs *)CallBackRef;
	u32 DataRead = 0;;

	/* Push the switch button */

	//DataRead = XGpioPs_ReadPin(Gpio, Input_Pin);
	DataRead = XGpioPs_Read(Gpio, 2);

	xil_printf("0x%x IntrHandler\r\n",DataRead);
	if ((DataRead & 0x1) == 0x01)
	{
    
    
		TxIntrHandler(&AxiDma);
	}
	if((DataRead & 0x2) == 0x02)
	{
    
    
		RxIntrHandler(&AxiDma);
	}
	if ((DataRead & 0x4) == 0x04)
	{
    
    
		TxIntrHandler(&AxiDma1);
//		xil_printf("data 4t\r\n");
	}
	if((DataRead & 0x8) == 0x08)
	{
    
    
		RxIntrHandler(&AxiDma1);
//		xil_printf("data 4r\r\n");
	}
	if ((DataRead & 0x10) == 0x010)
	{
    
    
		TxIntrHandler(&AxiDma2);
	}
	if((DataRead & 0x20) == 0x20)
	{
    
    
		RxIntrHandler(&AxiDma2);
	}
	if ((DataRead & 0x40) == 0x40)
	{
    
    
		TxIntrHandler(&AxiDma3);
	}
	if((DataRead & 0x80) == 0x080)
	{
    
    
		RxIntrHandler(&AxiDma3);
	}
	else
	{
    
    

	}
}

/*****************************************************************************/
/**
*
* This function sets up the interrupt system for the example. It enables falling
* edge interrupts for all the pins of bank 0 in the GPIO device.
*
* @param	GicInstancePtr is a pointer to the XScuGic driver Instance.
* @param	GpioInstancePtr contains a pointer to the instance of the GPIO
*		component which is going to be connected to the interrupt
*		controller.
* @param	GpioIntrId is the interrupt Id and is typically
*		XPAR_<GICPS>_<GPIOPS_instance>_VEC_ID value from
*		xparameters.h.
*
* @return	XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note		None.
*
****************************************************************************/
 int SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio,
				u16 GpioIntrId)
{
    
    
	xil_printf("SetupInterruptSystem\r\n");
	int Status;

	XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */

	Xil_ExceptionInit();

	/*
	 * Initialize the interrupt controller driver so that it is ready to
	 * use.
	 */
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfig) {
    
    
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,
					IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
    
    
		return XST_FAILURE;
	}


	/*
	 * Connect the interrupt controller interrupt handler to the hardware
	 * interrupt handling logic in the processor.
	 */
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
				(Xil_ExceptionHandler)XScuGic_InterruptHandler,
				GicInstancePtr);

	/*
	 * Connect the device driver handler that will be called when an
	 * interrupt for the device occurs, the handler defined above performs
	 * the specific interrupt processing for the device.
	 */
	Status = XScuGic_Connect(GicInstancePtr, GpioIntrId,
				(Xil_ExceptionHandler)XGpioPs_IntrHandler,
				(void *)Gpio);
	if (Status != XST_SUCCESS) {
    
    
		return Status;
	}

	/* Enable falling edge interrupts for all the pins in bank 0. */
	XGpioPs_SetIntrType(Gpio, 2, 0x00, 0xFFFFFFFF, 0x00);


	/* Set the handler for gpio interrupts. */
	XGpioPs_SetCallbackHandler(Gpio, (void *)Gpio, IntrHandler);


	/* Enable the GPIO interrupts of Bank 2. */
	XGpioPs_IntrEnable(Gpio, 2, 0xFF);


	/* Enable the interrupt for the GPIO device. */
	XScuGic_Enable(GicInstancePtr, GpioIntrId);


	/* Enable interrupts in the Processor. */
	Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);

	return XST_SUCCESS;
}



/*****************************************************************************/
/**
*
* This function disables the interrupts for DMA engine.
*
* @param	IntcInstancePtr is the pointer to the INTC component instance
* @param	TxIntrId is interrupt ID associated w/ DMA TX channel
* @param	RxIntrId is interrupt ID associated w/ DMA RX channel
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void DisableIntrSystem(INTC * IntcInstancePtr,
					u16 TxIntrId, u16 RxIntrId)
{
    
    
#ifdef XPAR_INTC_0_DEVICE_ID
	/* Disconnect the interrupts for the DMA TX and RX channels */
	XIntc_Disconnect(IntcInstancePtr, TxIntrId);
	XIntc_Disconnect(IntcInstancePtr, RxIntrId);
#else
	XScuGic_Disconnect(IntcInstancePtr, TxIntrId);
	XScuGic_Disconnect(IntcInstancePtr, RxIntrId);
#endif
}

int dma_init(void)
{
    
    
	int Status;
	XAxiDma_Config *Config;
	XAxiDma_Config *Config1;
	XAxiDma_Config *Config2;
	XAxiDma_Config *Config3;
	XGpioPs_Config *ConfigPtr;


	u8 *RxBufferPtr = (u8 *)RX_BUFFER_BASE;
	u8 *RxBufferPtr1 = (u8 *)RX_BUFFER_BASE1;
	u8 *RxBufferPtr2 = (u8 *)RX_BUFFER_BASE2;
	u8 *RxBufferPtr3 = (u8 *)RX_BUFFER_BASE3;

	memset(RxBufferPtr,0,MAX_PKT_LEN);
	memset(RxBufferPtr1,0,MAX_PKT_LEN);
	memset(RxBufferPtr2,0,MAX_PKT_LEN);
	memset(RxBufferPtr3,0,MAX_PKT_LEN);

	xil_printf("\r\n--- Entering dma init() --- \r\n");

	Config = XAxiDma_LookupConfig(0);
	if (!Config) {
    
    
		xil_printf("No config found for 0\r\n");
		return XST_FAILURE;
	}

	Config1 = XAxiDma_LookupConfig(1);
	if (!Config1) {
    
    
		xil_printf("No config found for 1\r\n");
		return XST_FAILURE;
	}

	Config2 = XAxiDma_LookupConfig(2);
	if (!Config2) {
    
    
		xil_printf("No config found for 2\r\n");
		return XST_FAILURE;
	}

	Config3 = XAxiDma_LookupConfig(3);
	if (!Config3) {
    
    
		xil_printf("No config found for 3\r\n");
		return XST_FAILURE;
	}

	/* Initialize DMA engine */
	Status = XAxiDma_CfgInitialize(&AxiDma, Config);
	if (Status != XST_SUCCESS) {
    
    
			xil_printf("Initialization 0 failed %d\r\n", Status);
			return XST_FAILURE;
		}

	Status = XAxiDma_CfgInitialize(&AxiDma1, Config1);
	if (Status != XST_SUCCESS) {
    
    
			xil_printf("Initialization 1 failed %d\r\n", Status);
			return XST_FAILURE;
		}

	Status = XAxiDma_CfgInitialize(&AxiDma2, Config2);
	if (Status != XST_SUCCESS) {
    
    
			xil_printf("Initialization 2 failed %d\r\n", Status);
			return XST_FAILURE;
		}

	Status = XAxiDma_CfgInitialize(&AxiDma3, Config3);
	if (Status != XST_SUCCESS) {
    
    
			xil_printf("Initialization 3 failed %d\r\n", Status);
			return XST_FAILURE;
		}

	/* Initialize the Gpio driver. */
	ConfigPtr = XGpioPs_LookupConfig(0);
	if (ConfigPtr == NULL) {
    
    
		return XST_FAILURE;
	}
	XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);

	/* Set the direction for the specified pin to be input */
	XGpioPs_SetDirectionPin(&Gpio,54,0);
	XGpioPs_SetDirectionPin(&Gpio,55,0);
	XGpioPs_SetDirectionPin(&Gpio,56,0);
	XGpioPs_SetDirectionPin(&Gpio,57,0);
	XGpioPs_SetDirectionPin(&Gpio,58,0);
	XGpioPs_SetDirectionPin(&Gpio,59,0);
	XGpioPs_SetDirectionPin(&Gpio,60,0);
	XGpioPs_SetDirectionPin(&Gpio,61,0);
	/*
	 * Setup the interrupts such that interrupt processing can occur. If
	 * an error occurs then exit.
	 */
	Status = SetupInterruptSystem(&Intc, &Gpio, XPAR_XGPIOPS_0_INTR);
	if (Status != XST_SUCCESS) {
    
    
		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);
	XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
	XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);

    XAxiDma_IntrDisable(&AxiDma1, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
	XAxiDma_IntrDisable(&AxiDma1, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
	XAxiDma_IntrEnable(&AxiDma1, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
	XAxiDma_IntrEnable(&AxiDma1, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);

    XAxiDma_IntrDisable(&AxiDma2, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
	XAxiDma_IntrDisable(&AxiDma2, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
	XAxiDma_IntrEnable(&AxiDma2, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
	XAxiDma_IntrEnable(&AxiDma2, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);

    XAxiDma_IntrDisable(&AxiDma3, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
	XAxiDma_IntrDisable(&AxiDma3, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
	XAxiDma_IntrEnable(&AxiDma3, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
	XAxiDma_IntrEnable(&AxiDma3, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);

	/**************************************************************************/
//	Status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR,0x58);
//	xil_printf(" RX length is 0x%x\r\n",Status);
//	Status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR,0x28);
//	xil_printf("TX length is 0x%x\r\n",Status);
	/**************************************************************************/
	Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR) RxBufferPtr,
				MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
	if (Status != XST_SUCCESS) {
    
    
		return XST_FAILURE;
	}

	Status = XAxiDma_SimpleTransfer(&AxiDma1,(UINTPTR) RxBufferPtr1,
				MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
	if (Status != XST_SUCCESS) {
    
    
		return XST_FAILURE;
	}

	Status = XAxiDma_SimpleTransfer(&AxiDma2,(UINTPTR) RxBufferPtr2,
				MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
	if (Status != XST_SUCCESS) {
    
    
		return XST_FAILURE;
	}

	Status = XAxiDma_SimpleTransfer(&AxiDma3,(UINTPTR) RxBufferPtr3,
				MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
	if (Status != XST_SUCCESS) {
    
    
		return XST_FAILURE;
	}


	/* Initialize flags before start transfer test  */
	TxDone = 0;
	DMA0RxDone = 0;
	DMA1RxDone = 0;
	DMA2RxDone = 0;
	DMA3RxDone = 0;
	Error = 0;
}

int dma_8_10b_send(XAxiDma* AxiDmaIns,u8 *wBuffer , unsigned int length)
{
    
    
	int Status;
	u8 *TxBufferPtr;
	if((AxiDmaIns == NULL)||(wBuffer == NULL))
	{
    
    
		xil_printf("send Pointer err\r\n");
		return XST_FAILURE;
	}

	if (AxiDmaIns == &AxiDma)
		TxBufferPtr = (u8 *)TX_BUFFER_BASE ;
	else if(AxiDmaIns == &AxiDma1)
		TxBufferPtr = (u8 *)TX_BUFFER_BASE1 ;
	else if(AxiDmaIns == &AxiDma2)
		TxBufferPtr = (u8 *)TX_BUFFER_BASE2 ;
	else if(AxiDmaIns == &AxiDma3)
		TxBufferPtr = (u8 *)TX_BUFFER_BASE3 ;
	else
	{
    
    
		xil_printf("para err\r\n");
		return XST_FAILURE;
	}

	memset(TxBufferPtr,0,length);
	memcpy(TxBufferPtr,wBuffer,length);

	Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, MAX_PKT_LEN);

	Status = XAxiDma_SimpleTransfer(AxiDmaIns,(UINTPTR) TxBufferPtr,
			length, XAXIDMA_DMA_TO_DEVICE);
//	xil_printf("status is %d",Status);
	if (Status != XST_SUCCESS)
	{
    
    

		return XST_FAILURE;
	}

    return XST_SUCCESS;
}

unsigned int dma_8_10b_recv(XAxiDma* AxiDmaIns,u8 *rBuffer)
{
    
    
	int Status;
	int i;
	int Length = 0 ;
	u8 *RxBufferPtr;

	Length = XAxiDma_ReadReg(AxiDmaIns->RegBase,0x58);
	if((AxiDmaIns == NULL)||(rBuffer == NULL))
	{
    
    
		xil_printf("recv Pointer err\r\n");
		return XST_FAILURE;
	}

	if (AxiDmaIns == &AxiDma)
		RxBufferPtr = (u8 *)RX_BUFFER_BASE ;
	else if(AxiDmaIns == &AxiDma1)
		RxBufferPtr = (u8 *)RX_BUFFER_BASE1 ;
	else if(AxiDmaIns == &AxiDma2)
		RxBufferPtr = (u8 *)RX_BUFFER_BASE2 ;
	else if(AxiDmaIns == &AxiDma3)
		RxBufferPtr = (u8 *)RX_BUFFER_BASE3 ;
	else
	{
    
    
		xil_printf("para err\r\n");
		return XST_FAILURE;
	}

	Xil_DCacheInvalidateRange(RxBufferPtr,MAX_PKT_LEN);

	for(i = 0; i < Length; i++)
		{
    
    
			rBuffer[i] = RxBufferPtr[i];

		}

	Status = XAxiDma_SimpleTransfer(AxiDmaIns,(UINTPTR) RxBufferPtr,
				MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);

	if (Status != XST_SUCCESS) {
    
    
		return XST_FAILURE;
	}

    return Length;
}

Demo部分如下

void Xdma_demo()
{
    
    
	int Status;
	int Length;
	u8 rBuffer[256] = {
    
    0};
	u8 wBuffer[256] = {
    
    0};

	int i;

	dma_init();

    for(i=0;i<256;i++)
    {
    
    
    	wBuffer[i]=i+1;
    }
	dma_8_10b_send(&AxiDma,wBuffer,4);
    for(i=0;i<256;i++)
    {
    
    
    	wBuffer[i]=i+2;
    }
	dma_8_10b_send(&AxiDma1,wBuffer , 16);
    for(i=0;i<256;i++)
    {
    
    
    	wBuffer[i]=i+3;
    }
	dma_8_10b_send(&AxiDma2,wBuffer , 32);
    for(i=0;i<256;i++)
    {
    
    
    	wBuffer[i]=i+4;
    }
	dma_8_10b_send(&AxiDma3,wBuffer , 32);

	while(1)
	{
    
    
		if(DMA0RxDone == 1)
		{
    
    
//			Status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR,0x58);
//						xil_printf("length2 is 0x%x\r\n",Status);
//		    Status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR,0x28);
//						xil_printf("TX length2 is 0x%x\r\n",Status);

			Length = dma_8_10b_recv(&AxiDma,rBuffer);
			xil_printf("length DMA0 is 0x%x\r\n",Length);
			xil_printf("DATE: ");
			for(i=0; i<33; i++)
			{
    
    
				xil_printf("%x ",rBuffer[i]);
			}
			xil_printf("\r\n");
			DMA0RxDone = 0;
		}
		if(DMA1RxDone == 1)
		{
    
    
			Length = dma_8_10b_recv(&AxiDma1,rBuffer);
		xil_printf("length DMA1 is 0x%x\r\n",Length);

			xil_printf("DATE: ");
			for(i=0; i<33; i++)
			{
    
    
				xil_printf("%x ",rBuffer[i]);
			}
			xil_printf("\r\n");
			DMA1RxDone = 0;
		}
		if(DMA2RxDone == 1)
		{
    
    
			dma_8_10b_recv(&AxiDma2,rBuffer);
			xil_printf("DATE: ");
			for(i=0; i<33; i++)
			{
    
    
				xil_printf("%x ",rBuffer[i]);
			}
			xil_printf("\r\n");
			DMA2RxDone = 0;
		}
		if(DMA3RxDone == 1)
		{
    
    
			dma_8_10b_recv(&AxiDma3,rBuffer);
			xil_printf("DATE: ");
			for(i=0; i<33; i++)
			{
    
    
				xil_printf("%x ",rBuffer[i]);
			}
			xil_printf("\r\n");
			DMA3RxDone = 0;
		}

	}

}

  dma_8_10b_send()为封装后的发送函数,将宏定义的四路TXBUFFER和DMA匹配,实现DMA向设备发送数据的功能,并通过Xil_DCacheFlushRange()函数清理缓存
  dma_8_10b_recv()为封装后的接收函数,将宏定义的四路RXBUFFER和DMA匹配,实现DMA接收设备发送的数据的功能,数据长度通过读取DMA长度寄存器获得,这样的话更具有普遍性,同样通过Xil_DCacheFlushRange()函数清理缓存
  XAxiDma_SimpleTransfer是其原型,最后一个参数表示了传输方向收发的处理函数基本上是AXIDMA例程里的,仅对多余的接收完成标志位做了补充(多余的应该没了,也能在导入一个工程比较一下)
  初始化部分是结合了之前章节讲的GPIO中断,没有用例程中的中断方式

先写这么多了,目前只了解到这些,SG模式的用法后续有机会更新吧
学习zynq时间较短,认知有限,代码也比较简陋。如有错误欢迎批评指正。影响阅读的图片水印也已去掉欢迎大家收藏
参考:芯片手册 原子开发手册 CSDN Xilinx社区等网络资源

猜你喜欢

转载自blog.csdn.net/qq_42330920/article/details/113769945