moerjielovecookie

Sawen_Blog

一个普通工科牲的博客网站
x
github
follow
email

AXI DMA+AXI-S FIFO回环学习

DMA 简介#

DMA 是现代计算机的特色之一,是硬件实现存储器与存储器、存储器与 I/O 设备之间直接进行高速数据传输的内存技术,它允许不同速率的设备进行沟通,而不需要依靠 CPU 的中断负载。
如果不使用 DMA,那么 CPU 需要从数据源把每一个片段的数据复制到寄存器中,这个过程会一直占用 CPU 的资源。当使用 DMA 时,CPU 向 DMA 发送一个存储传输请求,当 DMA 控制器收到请求时就会将数据从源地址搬运到目的地址,搬运过程中不消化 CPU 的资源,当传输完成后 DMA 控制器以中断的方式通知 CPU。
为了发起传输事务,DMA 控制器必须有:

  1. 源地址
  2. 目的地址
  3. 传输长度
    DMA 存储传输的过程如下:
  4. 处理器向 DMA 控制器发送一条 DMA 命令
  5. DMA 控制器把数据从外设传输到存储器或从存储器搬运到存储器,而让 CPU 腾出手来做其它操作
  6. 数据传输完成后,DMA 控制器向 CPU 发出一个中断,来通知处理器 DMA 传输完成

ZYNQ 提供两种 DMA,一种是集成在 PS 中的硬核 DMA,一种是 PL 中的软核 AXI DMA IP。
各种接口方式的比较如下:
|500
PL 的 DMA 和 AXI_HP 接口的传输适用于大量数据的高性能传输,带宽高,传输方式的拓扑图如下:
|500

AXI DMA IP#

AXI Direct Memory Access(AXI DMA)IP 核在 AXI 4 内存映射和 AXI 4-Stream IP 接口之间提供高带宽直接储存访问。

|500
AXI DMA 用到了三种总线。AXI 4-Lite 用于对寄存器进行配置,AXI 4 Memory Map 总线用于读写 DDR 中的数据,AXI 4 Stream 总线用于 AXI DMA 对外设数据的读写,其中 AXI 4 Stream Master(MM 2 S,Memory Map to Stream)接口用于向 PL 写入数据,AXI 4-Stream Slave (S 2 MM,Stream to Memory Map) 接口用于从 PL 读取数据。
AXI DMA 提供 3 种模式,分别是 Direct Register 模式、Scatter/Gather 模式和 Cyclic DMA(循环 DMA)模式,常用的是 Direct Register 模式。
Direct Register DMA 模式即 Simple DMA 模式。Direct Register 模式提供了一种配置,用于在 MM 2 S 和 S 2 MM 通道上执行简单的 DMA 传输。Simple DMA(简单 DMA)允许应用程序在 DMA 和 Device 之间定义单个事务。它有两个通道:一个从 DMA 到 Device,另一个从 Device 到 DMA。这里有个地方需要大家注意下,在编写 Simple DMA(简单 DMA)代码时必须设置缓冲区地址和长度字段以启动相应通道中的传输。(其中 PL 对应 Device)

Vivado 中的 IP 配置#

image

Enable Scatter Gather Engine
选中此选项可启用 Scatter Gather 模式操作,并在 AXI DMA 中包含 Scatter Gather Engine。取消选中此选项可启用 Direct Register 模式操作,但不包括 AXI DMA 中的 Scatter Gather Engine。禁用 Scatter Gather Engine 会使 Scatter/Gather Engine 的所有输出端口都绑定为零,并且所有输入端口都将保持打开状态。此处我们取消勾选 Enable Scatter Gather Engine
Enable Micro DMA
使能后会生成高度优化的 DMA,资源消耗较少,用于极少量数据的传输
Width of Buffer Length Register
该选项配置了 AXI DMA 单次最大能搬运多少个字节,字节数 $=2^{Width}$
Address Width (32 - 64)
指定地址空间的宽度,可以是 32 到 64 之间的任意值
Enable Read Channel
开启 AXI DMA 的读通道 MM 2 S,相关配置如下:

  • Number of Channels:指定通道数。保持默认值 1
  • Memory Map Data Width:AXI MM 2 S 存储映射读取数据总线的数据位宽。有效值为 32、64、128、256、512 和 1024。此处保持默认值 32
  • Stream Data Width:AXI MM 2 S AXI 4-Stream 数据总线的数据位宽。该值必须小于或等于 Memory Map Data Width。有效值为 8、16、32、64、128、512 和 1024。此处保持默认值 32
  • Max Burst Size:突发分区粒度设置。此设置指定 MM 2 S 的 AXI 4-Memory Map 侧的突发周期的最大值。有效值为 2、4、8、16、32、64、128 和 256
  • Allow Unaligned Transfers:启用或禁用 MM 2 S 数据重新排列引擎(Data Realignment Engine,DRE)。选中时,DRE 被使能并允许在 MM 2 S 存储映射数据路径上数据重新对齐到 8 位的字节水平。对于 MM 2 S 通道,则从内存中读取数据。如果 DRE 被使能,则数据读取可以从任何缓冲区地址字节偏移开始,并且读取数据被对齐,使得第一个字节读取是 AXI 4-Stream 上的第一个有效字节输出
    Enable Write Channel
    开启 AXI DMA 的写通道 S 2 MM,相关配置同上

Vitis 工程解析#

头文件引用和宏定义#

/***************************** Include Files *********************************/

#include "xaxidma.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "xil_util.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

/************************** 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 defined(XPAR_MIG7SERIES_0_BASEADDR)
#define DDR_BASE_ADDR XPAR_MIG7SERIES_0_BASEADDR
#elif defined(XPAR_MIG_0_C0_DDR4_MEMORY_MAP_BASEADDR)
#define DDR_BASE_ADDR XPAR_MIG_0_C0_DDR4_MEMORY_MAP_BASEADDR
#elif defined(XPAR_PSU_DDR_0_S_AXI_BASEADDR)
#define DDR_BASE_ADDR XPAR_PSU_DDR_0_S_AXI_BASEADDR
#endif

#define DDR_BASE_ADDR XPAR_PS7_DDR_0_S_AXI_BASEADDR // 0x00100000

#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 + 0x01000000) // 0x01100000
#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) // 0x01200000
#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000) // 0x01400000
#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF) // 0x015FFFFF

#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

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

#define TEST_START_VALUE 0x1
/*
 * Buffer and Buffer Descriptor related constant definition
 */
#define MAX_PKT_LEN 0x200

#define NUMBER_OF_TRANSFERS 10
#define POLL_TIMEOUT_COUNTER 1000000U
#define NUMBER_OF_EVENTS 1

#define DDR_BASE_ADDR XPAR_AXI_7SDDR_0_S_AXI_BASEADDR 重新定义了 DDR 3 的基址.。数据读写的基址为 #define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x01000000) // 0x01100000 AXI DMA 读取数据的起始地址为 #define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) // 0x01200000,写入地址为 0x01400000

定义函数和声明相关的 instance 和 flag 变量#

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

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

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

#ifdef XPAR_UARTNS550_0_BASEADDR
static void Uart550_Setup(void);
#endif

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

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

/************************** Variable Definitions *****************************/
/*
 * Device instance definitions
 */

static XAxiDma AxiDma; /* Instance of the XAxiDma */

static INTC Intc; /* Instance of the Interrupt Controller */

/*
 * Flags interrupt handlers use to notify the application context the events.
 */
volatile u32 TxDone;
volatile u32 RxDone;
volatile u32 Error;

Main 函数#

/*****************************************************************************/
/**
 *
 * Main function
 *
 * This function is the main entry of the interrupt test. It does the following:
 *	Set up the output terminal if UART16550 is in the hardware build
 *	Initialize the DMA engine
 *	Set up Tx and Rx channels
 *	Set up the interrupt system for the Tx and Rx interrupts
 *	Submit a transfer
 *	Wait for the transfer to finish
 *	Check transfer status
 *	Disable Tx and Rx interrupts
 *	Print test status and exit
 *
 * @param	None
 *
 * @return
 *		- XST_SUCCESS if example finishes successfully
 *		- XST_FAILURE if example fails.
 *
 * @note		None.
 *
 ******************************************************************************/
int main(void)
{
	int Status;
	XAxiDma_Config *Config;
	int Tries = NUMBER_OF_TRANSFERS;
	int Index;
	u8 *TxBufferPtr;
	u8 *RxBufferPtr;
	u8 Value;

	TxBufferPtr = (u8 *)TX_BUFFER_BASE;
	RxBufferPtr = (u8 *)RX_BUFFER_BASE;
	/* Initial setup for Uart16550 */
#ifdef XPAR_UARTNS550_0_BASEADDR

	Uart550_Setup();

#endif

	xil_printf("\r\n--- Entering main() --- \r\n");

	Config = XAxiDma_LookupConfig(DMA_DEV_ID);
	if (!Config)
	{
		xil_printf("No config found for %d\r\n", DMA_DEV_ID);

		return XST_FAILURE;
	}
	else
	{
		xil_printf("Config found for %d\r\n", DMA_DEV_ID);
	}

	/* Initialize DMA engine */
	Status = XAxiDma_CfgInitialize(&AxiDma, Config);

	if (Status != XST_SUCCESS)
	{
		xil_printf("Initialization failed %d\r\n", Status);
		return XST_FAILURE;
	}
	else
	{
		xil_printf("DMA Initialization success %d\r\n", Status);
	}

	if (XAxiDma_HasSg(&AxiDma))
	{
		xil_printf("Device configured as SG mode \r\n");
		return XST_FAILURE;
	}
	else
	{
		xil_printf("Device configured as simple mode \r\n");
	}

	/* Set up Interrupt system  */
	Status = SetupIntrSystem(&Intc, &AxiDma, TX_INTR_ID, RX_INTR_ID);
	if (Status != XST_SUCCESS)
	{

		xil_printf("Failed intr setup\r\n");
		return XST_FAILURE;
	}

	/* Disable all interrupts before setup */

	XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
						XAXIDMA_DMA_TO_DEVICE);

	XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
						XAXIDMA_DEVICE_TO_DMA);

	/* Enable all interrupts */
	XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
					   XAXIDMA_DMA_TO_DEVICE);

	XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
					   XAXIDMA_DEVICE_TO_DMA);

	/* Initialize flags before start transfer test  */
	TxDone = 0;
	RxDone = 0;
	Error = 0;

	Value = TEST_START_VALUE;

	for (Index = 0; Index < MAX_PKT_LEN; Index++)
	{
		TxBufferPtr[Index] = Value;

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

	/* Flush the buffers before the DMA transfer, in case the Data Cache
	 * is enabled
	 */
	Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, MAX_PKT_LEN);
	Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, MAX_PKT_LEN);
	/* Send a packet */
	for (int i = 0; i < Tries; i++)
	{

		Status = XAxiDma_SimpleTransfer(&AxiDma, (UINTPTR)RxBufferPtr,
										MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);

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

		Status = XAxiDma_SimpleTransfer(&AxiDma, (UINTPTR)TxBufferPtr,
										MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);

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

		Status = Xil_WaitForEventSet(POLL_TIMEOUT_COUNTER, NUMBER_OF_EVENTS, &Error);
		if (Status == XST_SUCCESS)
		{
			if (!TxDone)
			{
				xil_printf("Transmit error %d\r\n", Status);
				goto Done;
			}
			else if (Status == XST_SUCCESS && !RxDone)
			{
				xil_printf("Receive error %d\r\n", Status);
				goto Done;
			}
		}

		/*
		 * Wait for TX done or timeout
		 */
		Status = Xil_WaitForEventSet(POLL_TIMEOUT_COUNTER, NUMBER_OF_EVENTS, &TxDone);
		if (Status != XST_SUCCESS)
		{
			xil_printf("Transmit failed %d\r\n", Status);
			goto Done;
		}

		/*
		 * Wait for RX done or timeout
		 */
		Status = Xil_WaitForEventSet(POLL_TIMEOUT_COUNTER, NUMBER_OF_EVENTS, &RxDone);
		if (Status != XST_SUCCESS)
		{
			xil_printf("Receive failed %d\r\n", Status);
			goto Done;
		}

		/*
		 * Test finished, check data
		 */
		Status = CheckData(MAX_PKT_LEN, 0x1);
		if (Status != XST_SUCCESS)
		{
			xil_printf("Data check failed\r\n");
			goto Done;
		}
		xil_printf("Transfer %d done\r\n", i + 1);
	}
	xil_printf("Successfully ran AXI DMA interrupt Example\r\n");

	/* Disable TX and RX Ring interrupts and return success */

	DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID);

Done:
	xil_printf("--- Exiting main() --- \r\n");

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

	return XST_SUCCESS;
}

Tries 为测试回环的次数

函数的实现#

*****************************************************************************/
/*
 *
 * 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.
 *
 ******************************************************************************/
static 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
	 */
	Xil_DCacheInvalidateRange((UINTPTR)RxPacket, Length);

	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)
{

	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 = RESET_TIMEOUT_COUNTER;

		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.
 *
 ******************************************************************************/
static void RxIntrHandler(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 = RESET_TIMEOUT_COUNTER;

		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;
	}
}

/*****************************************************************************/
/*
 *
 * 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 successful
 *
 * @note		None.
 *
 ******************************************************************************/
static int SetupIntrSystem(INTC *IntcInstancePtr,
						   XAxiDma *AxiDmaPtr, u16 TxIntrId, u16 RxIntrId)
{
	int Status;

#ifdef XPAR_INTC_0_DEVICE_ID

	/* Initialize the interrupt controller and connect the ISRs */
	Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID);
	if (Status != XST_SUCCESS)
	{

		xil_printf("Failed init intc\r\n");
		return XST_FAILURE;
	}

	Status = XIntc_Connect(IntcInstancePtr, TxIntrId,
						   (XInterruptHandler)TxIntrHandler, AxiDmaPtr);
	if (Status != XST_SUCCESS)
	{

		xil_printf("Failed tx connect intc\r\n");
		return XST_FAILURE;
	}

	Status = XIntc_Connect(IntcInstancePtr, RxIntrId,
						   (XInterruptHandler)RxIntrHandler, AxiDmaPtr);
	if (Status != XST_SUCCESS)
	{

		xil_printf("Failed rx connect intc\r\n");
		return XST_FAILURE;
	}

	/* Start the interrupt controller */
	Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);
	if (Status != XST_SUCCESS)
	{

		xil_printf("Failed to start intc\r\n");
		return XST_FAILURE;
	}

	XIntc_Enable(IntcInstancePtr, TxIntrId);
	XIntc_Enable(IntcInstancePtr, RxIntrId);

#else

	XScuGic_Config *IntcConfig;

	/*
	 * 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(IntcInstancePtr, IntcConfig,
								   IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}
	//设置中断优先级和触发类型
	XScuGic_SetPriorityTriggerType(IntcInstancePtr, TxIntrId, 0xA0, 0x3);

	XScuGic_SetPriorityTriggerType(IntcInstancePtr, RxIntrId, 0xA0, 0x3);
	/*
	 * 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(IntcInstancePtr, TxIntrId,
							 (Xil_InterruptHandler)TxIntrHandler,
							 AxiDmaPtr);
	if (Status != XST_SUCCESS)
	{
		return Status;
	}

	Status = XScuGic_Connect(IntcInstancePtr, RxIntrId,
							 (Xil_InterruptHandler)RxIntrHandler,
							 AxiDmaPtr);
	if (Status != XST_SUCCESS)
	{
		return Status;
	}
	
	XScuGic_Enable(IntcInstancePtr, TxIntrId);
	XScuGic_Enable(IntcInstancePtr, RxIntrId);

#endif

	/* Enable interrupts from the hardware */

	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
								 (Xil_ExceptionHandler)INTC_HANDLER,
								 (void *)IntcInstancePtr);

	Xil_ExceptionEnable();

	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
}

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。