Introduction to DMA#
DMA is one of the features of modern computers, a memory technology that allows for high-speed data transfer directly between memory and I/O devices without relying on CPU interrupts. It enables communication between devices operating at different speeds without burdening the CPU.
Without DMA, the CPU must copy each fragment of data from the data source into registers, which continuously occupies CPU resources. When using DMA, the CPU sends a memory transfer request to the DMA controller, which then transfers data from the source address to the destination address without consuming CPU resources during the transfer. Once the transfer is complete, the DMA controller notifies the CPU via an interrupt.
To initiate a transfer transaction, the DMA controller must have:
- Source address
- Destination address
- Transfer length
The process of DMA memory transfer is as follows: - The processor sends a DMA command to the DMA controller.
- The DMA controller transfers data from the peripheral to memory or from memory to memory, allowing the CPU to perform other operations.
- After the data transfer is complete, the DMA controller issues an interrupt to notify the processor that the DMA transfer is complete.
ZYNQ provides two types of DMA: one is a hard-core DMA integrated into the PS, and the other is a soft-core AXI DMA IP in the PL.
The comparison of various interface methods is as follows:
The DMA in the PL and the AXI_HP interface are suitable for high-performance transfers of large amounts of data, with high bandwidth. The topology diagram of the transfer method is as follows:
AXI DMA IP#
AXI Direct Memory Access (AXI DMA) IP core provides high-bandwidth direct memory access between AXI 4 memory-mapped and AXI 4-Stream IP interfaces.
AXI DMA utilizes three types of buses. AXI 4-Lite is used for configuring registers, the AXI 4 Memory Map bus is used for reading and writing data in DDR, and the AXI 4 Stream bus is used for AXI DMA's read and write operations on peripheral data. The AXI 4 Stream Master (MM 2 S, Memory Map to Stream) interface is used to write data to the PL, while the AXI 4-Stream Slave (S 2 MM, Stream to Memory Map) interface is used to read data from the PL.
AXI DMA offers three modes: Direct Register mode, Scatter/Gather mode, and Cyclic DMA mode, with Direct Register mode being the most commonly used.
Direct Register DMA mode is also known as Simple DMA mode. The Direct Register mode provides a configuration for executing simple DMA transfers on the MM 2 S and S 2 MM channels. Simple DMA allows applications to define a single transaction between DMA and Device. It has two channels: one from DMA to Device and the other from Device to DMA. It is important to note that when writing Simple DMA code, the buffer address and length fields must be set to initiate the transfer in the corresponding channel (where PL corresponds to Device).
IP Configuration in Vivado#
Enable Scatter Gather Engine
Selecting this option enables Scatter Gather mode operations and includes the Scatter Gather Engine in AXI DMA. Unchecking this option enables Direct Register mode operations but does not include the Scatter Gather Engine in AXI DMA. Disabling the Scatter Gather Engine will bind all output ports of the Scatter/Gather Engine to zero, while all input ports will remain open. Here we will uncheck Enable Scatter Gather Engine.
Enable Micro DMA
Enabling this will generate a highly optimized DMA that consumes fewer resources for transferring a very small amount of data.
Width of Buffer Length Register
This option configures the maximum number of bytes that AXI DMA can transfer in a single operation, where the number of bytes $=2^{Width}$.
Address Width (32 - 64)
Specifies the width of the address space, which can be any value between 32 and 64.
Enable Read Channel
Enables the read channel MM 2 S of AXI DMA, with the following configurations:
- Number of Channels: Specifies the number of channels. Keep the default value of 1.
- Memory Map Data Width: The data bit width of the AXI MM 2 S memory-mapped read data bus. Valid values are 32, 64, 128, 256, 512, and 1024. Keep the default value of 32 here.
- Stream Data Width: The data bit width of the AXI MM 2 S AXI 4-Stream data bus. This value must be less than or equal to the Memory Map Data Width. Valid values are 8, 16, 32, 64, 128, 512, and 1024. Keep the default value of 32 here.
- Max Burst Size: Burst partition granularity setting. This setting specifies the maximum value of burst cycles on the AXI 4-Memory Map side of MM 2 S. Valid values are 2, 4, 8, 16, 32, 64, 128, and 256.
- Allow Unaligned Transfers: Enables or disables the MM 2 S data realignment engine (Data Realignment Engine, DRE). When checked, DRE is enabled and allows data to be realigned to 8-bit byte levels on the MM 2 S memory-mapped data path. For the MM 2 S channel, data is read from memory. If DRE is enabled, data reads can start from any buffer address byte offset, and the read data is aligned such that the first byte read is the first valid byte output on AXI 4-Stream.
Enable Write Channel
Enables the write channel S 2 MM of AXI DMA, with configurations similar to the above.
Vitis Project Analysis#
Header File Inclusion and Macro Definitions#
/***************************** 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
redefines the base address of DDR 3. The base address for data read and write is #define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x01000000) // 0x01100000
, the starting address for AXI DMA reading data is #define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) // 0x01200000
, and the writing address is 0x01400000
.
Function Definitions and Declaration of Related Instances and Flag Variables#
/**************************** 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 Function#
/*****************************************************************************/
/**
*
* 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
is the number of times the loop test is performed.
Function Implementation#
/*****************************************************************************/
/*
*
* 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;
}
// Set interrupt priority and trigger type
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.
*/
// Set interrupt handler
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
}