AXI DMA PS+PL Loopback on ZYNQ FPGA using VIVADO + VITIS UNIFIED IDE on Alinx AXU2CGBI
Dr. Hazoor Ahmad (EEDHA)
0:00 / 0:00
AXI DMA PS+PL Loopback on ZYNQ FPGA using VIVADO + VITIS UNIFIED IDE on Alinx AXU2CGBI
153 просмотра · 2 недели назад
Dr. Hazoor Ahmad (EEDHA)
285 подписчиков
153 просмотра · 2 недели назад
In this tutorial, I build a complete AXI DMA loopback design on the Alinx AXU2CGBI board (Xilinx Zynq UltraScale+ MPSoC, XCZU2CG-SFVC784-1-E) — going beyond a PS-only Hello World to real PS-PL codesign. We configure the AXI DMA IP in Vivado, wire it into the Zynq UltraScale+ processing system, and verify a working data path with a bare-metal loopback test in Vitis Unified IDE.
This is the essential next step after PS Hello World for anyone learning FPGA/embedded codesign on the AXU2CGBI — and a foundation for more advanced datapaths like streaming DSP and FFT-based processing.
What you'll learn:
✅ Enabling the right PS-PL interfaces (AXI HPM0 LPD, AXI HP0 FPD) for DMA
✅ Configuring interrupts (PL to PS, IRQ0/IRQ1) for AXI DMA
✅ Adding and wiring AXI DMA, AXI SmartConnect, and reset/clock signals in Vivado IP Integrator
✅ Direct Register mode vs Scatter Gather mode — and a real hardware/software mismatch bug I hit and fixed
✅ Writing and running a bare-metal AXI DMA loopback test in Vitis Unified IDE
✅ A critical Vitis workflow gotcha: why "switching XSA" on an existing platform can silently fail, and why creating a fresh platform + application project is the reliable fix
✅ Verifying DMA Loopback PASSED over UART
Hardware used:
🔹 Alinx AXU2CGBI (Zynq UltraScale+ MPSoC, XCZU2CG-SFVC784-1-E)
🔹 USB-UART / JTAG cable
Software used:
🔹 Xilinx Vivado 2024.2
🔹 Vitis Unified IDE
Timestamps:
00:08 – Intro
00:20 – Creating a Vivado project
01:00 – Creating a Block Design and adding Zynq IP
01:30 – PS UART and DDR configuration
02:30 – PS-PL Configuration: enabling AXI HP/HPM ports and interrupts
04:10 – Adding and configuring AXI DMA
05:00 – Adding AXI SmartConnect, wiring clocks, resets, and interrupts
06:30 – Validating design and generating bitstream
08:00 – Setting up Vitis workspace
08:50 – Creating platform from xsa file and building
09:50 – Creating application from the generated platform
11:15 – Application build
12:00 – Application run
12:30 – DMA Loopback PASSED
If this helped you get PS-PL codesign working on your own AXU2CGBI board, please like, subscribe, and let me know in the comments what you'd like to see next — AXI4-Stream FIFO, Scatter Gather with BD rings, or the Xilinx FFT IP for matched filtering!
Tags: #Zynq #UltraScale #AlinxAXU2CGBI #Vitis #Vivado #FPGA #AXIDMA #embeddedsystems #Xilinx #AMDXilinx #MPSoC #PSPLCodesign
// AXI DMA Simple Loopback Example
#include "xparameters.h"
#include "xaxidma.h"
#include "xil_cache.h"
#include "xil_printf.h"
#define MAX_PKT_LEN 32
#define TIMEOUT 1000000
#define TX_BUFFER_BASE (XPAR_PSU_DDR_0_BASEADDRESS + 0x02000000)
#define RX_BUFFER_BASE (XPAR_PSU_DDR_0_BASEADDRESS + 0x02200000)
XAxiDma AxiDma;
int main(void){
XAxiDma_Config *CfgPtr;
u8 *TxBuffer = (u8 *)TX_BUFFER_BASE;
u8 *RxBuffer = (u8 *)RX_BUFFER_BASE;
int Status = XST_SUCCESS;
int i, Timeout;
xil_printf("\r\nAXI DMA Simple Loopback Test\r\n");
CfgPtr = XAxiDma_LookupConfig(XPAR_XAXIDMA_0_BASEADDR);
if (CfgPtr == NULL) return XST_FAILURE;
Status = XAxiDma_CfgInitialize(&AxiDma, CfgPtr);
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
for (i = 0; i != MAX_PKT_LEN; i++) {
TxBuffer[i] = i;
RxBuffer[i] = 0;
}
Xil_DCacheFlushRange((UINTPTR)TxBuffer, MAX_PKT_LEN);
Xil_DCacheFlushRange((UINTPTR)RxBuffer, MAX_PKT_LEN);
if (Status == XST_SUCCESS)
Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR)RxBuffer,MAX_PKT_LEN,XAXIDMA_DEVICE_TO_DMA);
if (Status == XST_SUCCESS)
Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR)TxBuffer,MAX_PKT_LEN,XAXIDMA_DMA_TO_DEVICE);
Timeout = TIMEOUT;
while (Status == XST_SUCCESS && (XAxiDma_Busy(&AxiDma, XAXIDMA_DMA_TO_DEVICE) || XAxiDma_Busy(&AxiDma, XAXIDMA_DEVICE_TO_DMA)) && Timeout--);
if (Timeout == 0) Status = XST_FAILURE;
Xil_DCacheInvalidateRange((UINTPTR)RxBuffer, MAX_PKT_LEN);
for (i = 0; (i != MAX_PKT_LEN) && (Status == XST_SUCCESS); i++)
if (TxBuffer[i] != RxBuffer[i]) Status = XST_FAILURE;
xil_printf("DMA Loopback %s\r\n", (Status == XST_SUCCESS) ? "PASSED" : "FAILED");
return Status;
}