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
}

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。