MYIR-ZYNQ7000系列-zturn教程(23):DMA迴環測試

開發板環境:vivado 2017.4 ,開發板型號xc7z020clg400-1,這個工程主要使用DMA進行迴環測試

先將DDR內寫入數據,然後DMA通過MM2S將數據從DDR讀出並寫入到fifo中,再通過S2MM將數據從

fifo中讀出寫入到DDR中構成一個迴環。

step1 調用一個zynq核並配置

調用zynq核

勾選HP0

勾選reset管腳

勾選SD卡和uart (不同的開發板會有所差異)

將SDIO設置爲50M  (不同的開發板會有所差異)

將FCLK0設置爲100M  (不同的開發板會有所差異)

選擇DDR型號  (不同的開發板會有所差異)

勾選PL中斷

配置完成後,如下圖所示

step2  調用dma和fifo進行配置,並將各個模塊連接起來

調用一個dma核

按照截圖中的進行配置

這裏調用的fifo,直接默認的設置就可以了

調用System Reset 、axi_interconnect按照如下配置就可以了

調用一個concat核,這裏直接用默認配置

按照下圖進行連接

地址分配(DDR大小根據自己開發板進行分配)

step3  綜合、生成頂層文件、生成bit文件

綜合

生成頂層文件

生成bit文件

step4  導出硬件配置,打開SDK

導出硬件配置

打開SDK

step5  新建fsbl和新建一個dma_test工程

新建fsbl

在dma_test工程的src目錄下生成一個dma_test.c文件

再將這個主程序複製到這個dma_test.c文件中



#include "xaxidma.h"
#include "xparameters.h"
#include "xil_printf.h"
#include "xscugic.h"


#define DMA_DEV_ID		  XPAR_AXIDMA_0_DEVICE_ID
#define INT_DEVICE_ID     XPAR_SCUGIC_SINGLE_DEVICE_ID
#define INTR_ID           XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR

#define MAX_PKT_LEN		32

#define TEST_START_VALUE	0x0

#define NUMBER_OF_TRANSFERS	1

/*
 * Function declaration
 */
int XAxiDma_Setup(u16 DeviceId);
static int CheckData(void);
int SetInterruptInit(XScuGic *InstancePtr, u16 IntrID, XAxiDma *XAxiDmaPtr) ;

XScuGic INST ;

XAxiDma AxiDma;

u8 TxBufferPtr[MAX_PKT_LEN] ;
u8 RxBufferPtr[MAX_PKT_LEN] ;


int main()
{
	int Status;

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

	Status = XAxiDma_Setup(DMA_DEV_ID);

	if (Status != XST_SUCCESS) {
		xil_printf("XAxiDma Test Failed\r\n");
		return XST_FAILURE;
	}

	xil_printf("Successfully Ran XAxiDma Test\r\n");

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

	return XST_SUCCESS;

}



int SetInterruptInit(XScuGic *InstancePtr, u16 IntrID, XAxiDma *XAxiDmaPtr)
{

	XScuGic_Config * Config ;
	int Status ;

	Config = XScuGic_LookupConfig(INT_DEVICE_ID) ;

	Status = XScuGic_CfgInitialize(&INST, Config, Config->CpuBaseAddress) ;
	if (Status != XST_SUCCESS)
		return XST_FAILURE ;

	Status = XScuGic_Connect(InstancePtr, IntrID,
			(Xil_ExceptionHandler)CheckData,
			XAxiDmaPtr) ;

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

	XScuGic_Enable(InstancePtr, IntrID) ;

	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
					(Xil_ExceptionHandler) XScuGic_InterruptHandler,
					InstancePtr);

	Xil_ExceptionEnable();


	return XST_SUCCESS ;

}


int XAxiDma_Setup(u16 DeviceId)
{
	XAxiDma_Config *CfgPtr;
	int Status;
	int Tries = NUMBER_OF_TRANSFERS;
	int Index;
	u8 Value;

	/* Initialize the XAxiDma device.
	 */
	CfgPtr = XAxiDma_LookupConfig(DeviceId);
	if (!CfgPtr) {
		xil_printf("No config found for %d\r\n", DeviceId);
		return XST_FAILURE;
	}

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

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

	Status = SetInterruptInit(&INST,INTR_ID, &AxiDma) ;
	if (Status != XST_SUCCESS)
		         return XST_FAILURE ;

	/* Disable MM2S interrupt, Enable S2MM interrupt */
	XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_IOC_MASK,
						XAXIDMA_DEVICE_TO_DMA);
	XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
						XAXIDMA_DMA_TO_DEVICE);

	Value = TEST_START_VALUE;

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

			Value = (Value + 1) & 0xFF;
	}
	/* Flush the SrcBuffer before the DMA transfer, in case the Data Cache
	 * is enabled
	 */
	Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, MAX_PKT_LEN);

	for(Index = 0; Index < Tries; Index ++) {

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

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

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


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


			while ((XAxiDma_Busy(&AxiDma,XAXIDMA_DEVICE_TO_DMA)) ||
				(XAxiDma_Busy(&AxiDma,XAXIDMA_DMA_TO_DEVICE)))
					{
					/* Wait */
			}


		}

		/* Test finishes successfully
		 */
		return XST_SUCCESS;
	}


static int CheckData(void)
{
	u8 *RxPacket;
	int Index = 0;
	u8 Value;

	RxPacket = RxBufferPtr;
	Value = TEST_START_VALUE;

	xil_printf("Enter Interrupt\r\n");
	/*Clear Interrupt*/
	XAxiDma_IntrAckIrq(&AxiDma, XAXIDMA_IRQ_IOC_MASK,
			XAXIDMA_DEVICE_TO_DMA) ;
	/* Invalidate the DestBuffer before receiving the data, in case the
		 * Data Cache is enabled
		 */
	Xil_DCacheInvalidateRange((UINTPTR)RxPacket, MAX_PKT_LEN);


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

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

		xil_printf("RxPacket[%08x] = %08x\n\r",Index,RxPacket[Index]);
	}

	return XST_SUCCESS;
}

右擊Create Boot Image   生成BOOT.bin文件

將BOOT.bin文件拷貝到開發板運行,可以看到串口打印了32個8位數據,這個是接收buffer裏的數據

下面是對程序的部分分析

1.   

#define MAX_PKT_LEN        32           //這裏是值發送多少個8位數據,這裏是發送32個8位數據

#define TEST_START_VALUE    0x0   //往ddr裏寫數據,寫入的第一個起始數據

#define NUMBER_OF_TRANSFERS    1   //迴環測試的次數,這裏只進行一次迴環測試

2.

	XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_IOC_MASK,
						XAXIDMA_DEVICE_TO_DMA);

設置S2MM使能中斷,這裏操作的是0x30這個寄存器,當然這裏也不只是設置了中斷也配置了其它的控制位
具體請參考這個DMA手冊

具體的設置請參考DMA手冊的0x30寄存器設置

3

	XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
						XAXIDMA_DMA_TO_DEVICE);

關閉MM2S使能中斷,這裏操作的是0x00這個寄存器,這裏不僅是關閉MM2S中斷也配置了其它的控制位
具體請參考這個DMA手冊

4

	
Value = TEST_START_VALUE;

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

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

這裏往TxBuffer裏填充32個8位數據

5

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

啓動dma發送,將發送buffer裏的數據通過MM2S讀出並寫入到fifo裏

6

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

啓動dma接收,將fifo裏數據讀出並且通過S2MM接口寫入到ddr裏

7

while ((XAxiDma_Busy(&AxiDma,XAXIDMA_DEVICE_TO_DMA)) ||
				(XAxiDma_Busy(&AxiDma,XAXIDMA_DMA_TO_DEVICE)))
					{

檢測發送和接收通道是否處於空閒狀態,這個類似於while(tx || rx),只有當發送和接收都處於空閒爲0時
纔會跳出while語句,不然就會一直在這裏等待

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章