开发板环境: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 (不同的开发板会有所差异)
勾选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手册
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语句,不然就会一直在这里等待