開發板環境: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語句,不然就會一直在這裏等待