0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ZYNQ SOC验证设计:PS端DMA缓存数据到PS端DDR

电子设计 来源:CSDN博主 作者:没落骑士 2020-12-31 11:24 次阅读

上篇该系列博文中讲述W5500接收到上位机传输的数据,此后需要将数据缓存起来。当数据量较大或者其他数据带宽较高的情况下,片上缓存(OCM)已无法满足需求,这时需要将大量数据保存在外挂的DDR SDRAM中。

最简单的方式是使用Xilinx的读写地址库函数Xil_In32()和Xil_Out32(),当然不仅支持32bit位宽,还包括8 16和64bit。但这种方式每次读写都要占用CPU,无法在读写的同时接收后续数据或者对之前的数据进一步处理,也就无法形成类似FPGA逻辑设计中的“流水线结构”,此时前段数据缓存过程中,后段数据会被丢弃。所以,需要利用PS端CPU子系统内的专用硬件DMA完成高速的批量数据搬移工作。

pIYBAF9uKQWAI-4wAAMm2ngn2_4294.png

在Xilinx SDK的system.mss页面下直接导入ps_dma示例工程。
#include
#include
#include "sleep.h"
#include "xparameters.h"
#include "xil_types.h"
#include "xil_assert.h"
#include "xil_io.h"
#include "xil_exception.h"
#include "xil_cache.h"
#include "xil_printf.h"
#include "xscugic.h"
#include "xdmaps.h"

/************************** Constant Definitions *****************************/
/*
* The following constants map to the XPAR parameters created in the
* xparameters.h file. They are defined here such that a user can easily
* change all the needed parameters in one place.
*/
#define DMA_DEVICE_ID XPAR_XDMAPS_1_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID

#define DMA_DONE_INTR_0 XPAR_XDMAPS_0_DONE_INTR_0
#define DMA_DONE_INTR_1 XPAR_XDMAPS_0_DONE_INTR_1
#define DMA_DONE_INTR_2 XPAR_XDMAPS_0_DONE_INTR_2
#define DMA_DONE_INTR_3 XPAR_XDMAPS_0_DONE_INTR_3
#define DMA_DONE_INTR_4 XPAR_XDMAPS_0_DONE_INTR_4
#define DMA_DONE_INTR_5 XPAR_XDMAPS_0_DONE_INTR_5
#define DMA_DONE_INTR_6 XPAR_XDMAPS_0_DONE_INTR_6
#define DMA_DONE_INTR_7 XPAR_XDMAPS_0_DONE_INTR_7
#define DMA_FAULT_INTR XPAR_XDMAPS_0_FAULT_INTR

#define TEST_ROUNDS 1 /* Number of loops that the Dma transfers run.*/
#define DMA_LENGTH 1024 /* Length of the Dma Transfers */
#define TIMEOUT_LIMIT 0x2000 /* Loop count for timeout */

/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Function Prototypes ******************************/

int XDmaPs_Example_W_Intr(XScuGic *GicPtr, u16 DeviceId);
int SetupInterruptSystem(XScuGic *GicPtr, XDmaPs *DmaPtr);
void DmaDoneHandler(unsigned int Channel, XDmaPs_Cmd *DmaCmd,
void *CallbackRef);

/************************** Macro Definitions *****************************/

/************************** Variable Definitions *****************************/
#ifdef __ICCARM__
#pragma data_alignment=32
static int Src[DMA_LENGTH];
static int Dst[DMA_LENGTH];
#pragma data_alignment=4
#else
static int Src[DMA_LENGTH] __attribute__ ((aligned (32)));
static int Dst[DMA_LENGTH] __attribute__ ((aligned (32)));
#endif

XDmaPs DmaInstance;
#ifndef TESTAPP_GEN
XScuGic GicInstance;
#endif

/****************************************************************************/
/**
*
* This is the main function for the DmaPs interrupt example.
*
* @param None.
*
* @return XST_SUCCESS to indicate success, otherwise XST_FAILURE.
*
* @note None.
*
****************************************************************************/
#ifndef TESTAPP_GEN
int main(void)
{
int Status;

Status = XDmaPs_Example_W_Intr(&GicInstance,DMA_DEVICE_ID);
if (Status != XST_SUCCESS) {
xil_printf("Error: XDMaPs_Example_W_Intr failed/r/n");
return XST_FAILURE;
}

xil_printf("XDMaPs_Example_W_Intr passed/r/n");
return XST_SUCCESS;

}
#endif

/*****************************************************************************/
/**
*
* Interrupt Example to test the DMA.
*
* @param DeviceId is the Device ID of the DMA controller.
*
* @return XST_SUCCESS to indicate success, otherwise XST_FAILURE.
*
* @note None.
*
****************************************************************************/
int XDmaPs_Example_W_Intr(XScuGic *GicPtr, u16 DeviceId)
{
int Index;
unsigned int Channel = 0;
int Status;
int TestStatus;
int TestRound;
int TimeOutCnt;
volatile int Checked[XDMAPS_CHANNELS_PER_DEV];
XDmaPs_Config *DmaCfg;
XDmaPs *DmaInst = &DmaInstance;
XDmaPs_Cmd DmaCmd;

memset(&DmaCmd, 0, sizeof(XDmaPs_Cmd));

DmaCmd.ChanCtrl.SrcBurstSize = 4;
DmaCmd.ChanCtrl.SrcBurstLen = 4;
DmaCmd.ChanCtrl.SrcInc = 1;
DmaCmd.ChanCtrl.DstBurstSize = 4;
DmaCmd.ChanCtrl.DstBurstLen = 4;
DmaCmd.ChanCtrl.DstInc = 1;
DmaCmd.BD.SrcAddr = (u32) Src;
DmaCmd.BD.DstAddr = (u32) Dst;
DmaCmd.BD.Length = DMA_LENGTH * sizeof(int);

/*
* Initialize the DMA Driver
*/
DmaCfg = XDmaPs_LookupConfig(DeviceId);
if (DmaCfg == NULL) {
return XST_FAILURE;
}

Status = XDmaPs_CfgInitialize(DmaInst,
DmaCfg,
DmaCfg->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/*
* Setup the interrupt system.
*/
Status = SetupInterruptSystem(GicPtr, DmaInst);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

TestStatus = XST_SUCCESS;

for (TestRound = 0; TestRound xil_printf("Test round %d/r/n", TestRound);
for (Channel = 0;
Channel Channel++) {

/* Initialize source */
for (Index = 0; Index Src[Index] = DMA_LENGTH - Index;

/* Clear destination */
for (Index = 0; Index Dst[Index] = 0;

Checked[Channel] = 0;

/* Set the Done interrupt handler */
XDmaPs_SetDoneHandler(DmaInst,
Channel,
DmaDoneHandler,
(void *)Checked);

Status = XDmaPs_Start(DmaInst, Channel, &DmaCmd, 0);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

TimeOutCnt = 0;

/* Now the DMA is done */
while (!Checked[Channel]
&& TimeOutCnt TimeOutCnt++;
}

if (TimeOutCnt >= TIMEOUT_LIMIT) {
TestStatus = XST_FAILURE;
}

if (Checked[Channel] /* DMA controller failed */
TestStatus = XST_FAILURE;
}
}
}

return TestStatus;

}

/******************************************************************************/
/**
*
* This function connects the interrupt handler of the interrupt controller to
* the processor. This function is seperate to allow it to be customized for
* each application. Each processor or RTOS may require unique processing to
* connect the interrupt handler.
*
* @param GicPtr is the GIC instance pointer.
* @param DmaPtr is the DMA instance pointer.
*
* @return None.
*
* @note None.
*
****************************************************************************/
int SetupInterruptSystem(XScuGic *GicPtr, XDmaPs *DmaPtr)
{
int Status;
#ifndef TESTAPP_GEN
XScuGic_Config *GicConfig;

Xil_ExceptionInit();

/*
* Initialize the interrupt controller driver so that it is ready to
* use.
*/
GicConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == GicConfig) {
return XST_FAILURE;
}

Status = XScuGic_CfgInitialize(GicPtr, GicConfig,
GicConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
GicPtr);
#endif
/*
* Connect the device driver handlers that will be called when an interrupt
* for the device occurs, the device driver handler performs the specific
* interrupt processing for the device
*/

/*
* Connect the Fault ISR
*/
Status = XScuGic_Connect(GicPtr,
DMA_FAULT_INTR,
(Xil_InterruptHandler)XDmaPs_FaultISR,
(void *)DmaPtr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/*
* Connect the Done ISR for all 8 channels of DMA 0
*/
Status = XScuGic_Connect(GicPtr,
DMA_DONE_INTR_0,
(Xil_InterruptHandler)XDmaPs_DoneISR_0,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_1,
(Xil_InterruptHandler)XDmaPs_DoneISR_1,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_2,
(Xil_InterruptHandler)XDmaPs_DoneISR_2,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_3,
(Xil_InterruptHandler)XDmaPs_DoneISR_3,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_4,
(Xil_InterruptHandler)XDmaPs_DoneISR_4,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_5,
(Xil_InterruptHandler)XDmaPs_DoneISR_5,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_6,
(Xil_InterruptHandler)XDmaPs_DoneISR_6,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_7,
(Xil_InterruptHandler)XDmaPs_DoneISR_7,
(void *)DmaPtr);

if (Status != XST_SUCCESS)
return XST_FAILURE;

/*
* Enable the interrupts for the device
*/
XScuGic_Enable(GicPtr, DMA_DONE_INTR_0);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_1);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_2);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_3);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_4);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_5);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_6);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_7);
XScuGic_Enable(GicPtr, DMA_FAULT_INTR);

Xil_ExceptionEnable();

return XST_SUCCESS;

}

/*****************************************************************************/
/**
*
* DmaDoneHandler.
*
* @param Channel is the Channel number.
* @param DmaCmd is the Dma Command.
* @param CallbackRef is the callback reference data.
*
* @return None.
*
* @note None.
*
******************************************************************************/
void DmaDoneHandler(unsigned int Channel, XDmaPs_Cmd *DmaCmd, void *CallbackRef)
{

/* done handler */
volatile int *Checked = (volatile int *)CallbackRef;
int Index;
int Status = 1;
int *Src;
int *Dst;

Src = (int *)DmaCmd->BD.SrcAddr;
Dst = (int *)DmaCmd->BD.DstAddr;

/* DMA successful */
/* compare the src and dst buffer */
for (Index = 0; Index if ((Src[Index] != Dst[Index]) ||
(Dst[Index] != DMA_LENGTH - Index)) {
Status = -XST_FAILURE;
}
}

Checked[Channel] = Status;
}

ps_dma_demo

其实demo中做的操作非常简单,仅仅是定义了两个数组Src和Dst,之后利用PS_DMA将Src中数据搬移到Dst中,搬移完成后进入中断函数比较两部分地址数据是否一致。Xilinx的SDK软件代码有固定的套路,“上有政策,下有对策”,我们可以将其封装成固定格式的一个个子函数,方便今后调用。这里把整个工程分为:系统中断,PS_DMA专有中断以及主函数三个部分。
#include "xscugic.h"
#include "sys_intr.h"

int sys_IntrInit(XScuGic *GicPtr)
{
XScuGic_Config *GicConfig;
/*
* Initialize the interrupt controller driver so that it is ready to
* use.
*/
int Status;
GicConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == GicConfig) {
return XST_FAILURE;
}

Status = XScuGic_CfgInitialize(GicPtr, GicConfig,
GicConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return XST_SUCCESS;
}

void setupIntrException(XScuGic *GicPtr)
{
Xil_ExceptionInit();
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
GicPtr);
Xil_ExceptionEnable();
}

sys_intr.c

#ifndef SRC_SYS_INTR_H_
#define SRC_SYS_INTR_H_

#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID

int sys_IntrInit(XScuGic *GicPtr);
void setupIntrException(XScuGic *GicPtr);

#endif /* SRC_SYS_INTR_H_ */

sys_intr.h

#include "xil_types.h"
#include "xdmaps.h"
#include "xscugic.h"
#include "psdma_intr.h"

int PS_DMA_IntrInit(XDmaPs *DmaInst,u16 DeviceId)
{
/*
* Initialize the DMA Driver
*/
int Status;
XDmaPs_Config *DmaCfg = NULL;
DmaCfg = XDmaPs_LookupConfig(DeviceId);
if (DmaCfg == NULL) {
return XST_FAILURE;
}

Status = XDmaPs_CfgInitialize(DmaInst,
DmaCfg,
DmaCfg->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return XST_SUCCESS;
}

int PS_DMA_SetupIntr(XScuGic *GicPtr,XDmaPs *DmaPtr,unsigned Channel)
{
int Status;
/*
* Connect the device driver handlers that will be called when an interrupt
* for the device occurs, the device driver handler performs the specific
* interrupt processing for the device
*/

/*
* Connect the Fault ISR
*/
Status = XScuGic_Connect(GicPtr,
DMA_FAULT_INTR,
(Xil_InterruptHandler)XDmaPs_FaultISR,
(void *)DmaPtr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/*
* Connect the Done ISR for all 8 channels of DMA 0
*/
Status = XScuGic_Connect(GicPtr,
DMA_DONE_INTR_0,
(Xil_InterruptHandler)XDmaPs_DoneISR_0,
(void *)DmaPtr);
/*Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_1,
(Xil_InterruptHandler)XDmaPs_DoneISR_1,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_2,
(Xil_InterruptHandler)XDmaPs_DoneISR_2,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_3,
(Xil_InterruptHandler)XDmaPs_DoneISR_3,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_4,
(Xil_InterruptHandler)XDmaPs_DoneISR_4,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_5,
(Xil_InterruptHandler)XDmaPs_DoneISR_5,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_6,
(Xil_InterruptHandler)XDmaPs_DoneISR_6,
(void *)DmaPtr);
Status |= XScuGic_Connect(GicPtr,
DMA_DONE_INTR_7,
(Xil_InterruptHandler)XDmaPs_DoneISR_7,
(void *)DmaPtr);*/

if (Status != XST_SUCCESS)
return XST_FAILURE;

/* Set the Done interrupt handler */
XDmaPs_SetDoneHandler(DmaPtr,
Channel,//Channel
DmaDoneHandler,//真正的中断函数
(void *)Checked);

/*
* Enable the interrupts for the device
*/
XScuGic_Enable(GicPtr, DMA_DONE_INTR_0);
/*
XScuGic_Enable(GicPtr, DMA_DONE_INTR_1);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_2);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_3);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_4);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_5);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_6);
XScuGic_Enable(GicPtr, DMA_DONE_INTR_7);*/
XScuGic_Enable(GicPtr, DMA_FAULT_INTR);

return XST_SUCCESS;
}

void DmaDoneHandler(unsigned int Channel, XDmaPs_Cmd *DmaCmd, void *CallbackRef)
{

/* done handler */
volatile int *Checked = (volatile int *)CallbackRef;
//int Index;
int Status = 1;

xil_printf("Enter into the interrupt/n");
Checked[Channel] = Status;
}

void PS_DMA_InitPara(XDmaPs_Cmd* DmaCmd)
{

memset(DmaCmd, 0, sizeof(XDmaPs_Cmd));

DmaCmd->ChanCtrl.SrcBurstSize = 4;
DmaCmd->ChanCtrl.SrcBurstLen = 4;
DmaCmd->ChanCtrl.SrcInc = 1;
DmaCmd->ChanCtrl.DstBurstSize = 4;
DmaCmd->ChanCtrl.DstBurstLen = 4;
DmaCmd->ChanCtrl.DstInc = 1;
DmaCmd->BD.SrcAddr = (u32) Src;
DmaCmd->BD.DstAddr = (u32) DDR_BASEADDR;//Dst
DmaCmd->BD.Length = DMA_LENGTH * sizeof(int);
}

psdma_intr.c

#ifndef SRC_PSDMA_INTR_H_
#define SRC_PSDMA_INTR_H_

#define DMA_DONE_INTR_0 XPAR_XDMAPS_0_DONE_INTR_0
#define DMA_DONE_INTR_1 XPAR_XDMAPS_0_DONE_INTR_1
#define DMA_DONE_INTR_2 XPAR_XDMAPS_0_DONE_INTR_2
#define DMA_DONE_INTR_3 XPAR_XDMAPS_0_DONE_INTR_3
#define DMA_DONE_INTR_4 XPAR_XDMAPS_0_DONE_INTR_4
#define DMA_DONE_INTR_5 XPAR_XDMAPS_0_DONE_INTR_5
#define DMA_DONE_INTR_6 XPAR_XDMAPS_0_DONE_INTR_6
#define DMA_DONE_INTR_7 XPAR_XDMAPS_0_DONE_INTR_7
#define DMA_FAULT_INTR XPAR_XDMAPS_0_FAULT_INTR

#define DDR_BASEADDR 0x00600000//XPAR_PS7_DDR_0_S_AXI_BASEADDR 0x00100000
#define DMA_LENGTH 1024 /* Length of the Dma Transfers */

int Src[DMA_LENGTH] __attribute__ ((aligned (32)));
volatile int Checked[XDMAPS_CHANNELS_PER_DEV];

int PS_DMA_IntrInit(XDmaPs *DmaInst,u16 DeviceId);
int PS_DMA_SetupIntr(XScuGic *GicPtr,XDmaPs *DmaPtr,unsigned Channel);
void DmaDoneHandler(unsigned int Channel, XDmaPs_Cmd *DmaCmd, void *CallbackRef);
void PS_DMA_InitPara(XDmaPs_Cmd* DmaCmd);

#endif /* SRC_PSDMA_INTR_H_ */

psdma_intr.h

#include
#include
#include "sleep.h"
#include "xparameters.h"
#include "xil_types.h"
#include "xil_assert.h"
#include "xil_io.h"
#include "xil_exception.h"
#include "xil_cache.h"
#include "xil_printf.h"
#include "xscugic.h"
#include "xdmaps.h"

#include "sys_intr.h"
#include "psdma_intr.h"

#define DMA_DEVICE_ID XPAR_XDMAPS_1_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID

#define TEST_ROUNDS 1 /* Number of loops that the Dma transfers run.*/
#define TIMEOUT_LIMIT 0x2000 /* Loop count for timeout */

static XScuGic GicInstance;
static XDmaPs DmaInstance;
static XDmaPs_Cmd DmaCmd;
unsigned int Channel = 0;

/************************** Function Prototypes ******************************/

int PS_DMA_WriteTest();
int SetupInterruptSystem(XScuGic *GicPtr, XDmaPs *DmaPtr);
void DmaDoneHandler(unsigned int Channel, XDmaPs_Cmd *DmaCmd,
void *CallbackRef);
int dataCheck(u32 baseAddr,u32 len);
int systemInit(XScuGic *GicPtr,u16 DeviceId);

int main(void)
{
int Status;
Status = systemInit(&GicInstance,DMA_DEVICE_ID);
if (Status != XST_SUCCESS) {
xil_printf("System initialization is failed/r/n");
return XST_FAILURE;
}

Status = PS_DMA_WriteTest();
if (Status != XST_SUCCESS) {
xil_printf("Error: XDMaPs_Example_W_Intr failed/r/n");
return XST_FAILURE;
}
xil_printf("Checking data.../n");
Status = dataCheck(DDR_BASEADDR,DMA_LENGTH);
if(Status != XST_SUCCESS)
{
xil_printf("Error:check failed/n");
return XST_FAILURE;
}

xil_printf("Writing data to DDR using DMA test passed!/r/n");
return XST_SUCCESS;

}

int dataCheck(u32 baseAddr,u32 len)
{
u32 DDR_ReadData[1024];
int i;
for(i=0;i {
DDR_ReadData[i] = Xil_In32(baseAddr+i*4);
if(DDR_ReadData[i]!=Src[i])
return XST_FAILURE;
//else //将写入DDR数据读回 并打印
// xil_printf("data at %x is %d/n",baseAddr+i*4,DDR_ReadData[i]);
}
return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* Interrupt Example to test the DMA.
*
* @param DeviceId is the Device ID of the DMA controller.
*
* @return XST_SUCCESS to indicate success, otherwise XST_FAILURE.
*
* @note None.
*
****************************************************************************/
int PS_DMA_WriteTest()
{
int Index;
int Status;
int TestStatus;
int TestRound;
int TimeOutCnt;

TestStatus = XST_SUCCESS;

for (TestRound = 0; TestRound xil_printf("Test round %d/r/n", TestRound);
for (Channel = 0;Channel {
/* Initialize source */
for (Index = 0; Index Src[Index] = DMA_LENGTH - Index;

Checked[Channel] = 0;

Status = XDmaPs_Start(&DmaInstance, Channel, &DmaCmd, 0);
if (Status != XST_SUCCESS) {
xil_printf("Starting the DMA is failed./n");
return XST_FAILURE;
}
xil_printf("Starting the DMA is successful./n");
TimeOutCnt = 0;

while (!Checked[Channel]
&& TimeOutCnt TimeOutCnt++;
}
/* Now the DMA is done */
xil_printf("Jump out of the interrupt/n");
if (TimeOutCnt >= TIMEOUT_LIMIT) {
xil_printf("Overtime!/n");
TestStatus = XST_FAILURE;
}

if (Checked[Channel] /* DMA controller failed */
xil_printf("Checking failure!/n");
TestStatus = XST_FAILURE;
}
}
}

return TestStatus;

}

int systemInit(XScuGic *GicPtr,u16 DeviceId)
{
xil_printf("Start to initialize interrupt system./n");

PS_DMA_InitPara(&DmaCmd);//主要设置DMA的源目的地址
//xil_printf("Configuring DMA parameters is successful./n");

int Status;

Status = PS_DMA_IntrInit(&DmaInstance,DeviceId);
if (Status != XST_SUCCESS) {
xil_printf("DMA initialization is failed./n");
return XST_FAILURE;
}
//xil_printf("DMA initialization is successful./n");

Status = sys_IntrInit(GicPtr);
if (Status != XST_SUCCESS) {
xil_printf("Initialization of the interrupt system is failed./n");
return XST_FAILURE;
}
//xil_printf("Initialization of the interrupt system is successful./n");

setupIntrException(GicPtr);

Status = PS_DMA_SetupIntr(GicPtr,&DmaInstance,Channel);//////////////////////////DMA中断入口///////////////////////
if (Status != XST_SUCCESS) {
xil_printf("Setting up DMA interrupt is failed./n");
return XST_FAILURE;
}
//xil_printf("Setting up DMA interrupt is successful./n");

xil_printf("System initialization is finished./n");
xil_printf("------------------------------------------/n");
return XST_SUCCESS;
}

main.c

上述代码的封装方式参考了米联客教程中的思想。先说明系统中断部分:sys_IntrInit()函数中进行查找表配置和中断控制器初始化操作,setupIntrException()函数负责使能中断异常处理。再来说说PS_DMA中断部分:PS_DMA_IntrInit()函数与系统中断中sys_IntrInit()从操作到格式几乎完成相同,亦是查找表配置和DMA的初始化。PS_DMA_SetupIntr()函数完成了中断源和中断控制器的连接和设置中断处理器,以及中断使能,也就是所有PS_DMA的专用中断操作。

PS_DMA_SetupIntr()内最重要的部分是XDmaPs_SetDoneHandler(),其相当于一个调用中断函数的通用处理框架,它的第三个参数DoneHandler才是真正的中断处理函数。这里涉及到C语言的高级话题:函数通过函数指针调用另一个函数,被函数指针调用的函数就是通常讲的“回调函数”了。指针调用函数的方式兼顾了程序的通用架构和灵活性,具体参考文章:不懂C语言回调函数,那就看这篇文章吧! - 简书 https://www.jianshu.com/p/2f695d6fd64f 在该程序中,中断回调函数为DmaDoneHandler()。

PS_DMA_InitPara()是自行添加的PS_DMA参数初始化函数,内部的参数更是重中之重了,我们来查看Xilinx官方文档ug585的DMA Controller章节。

pIYBAF9uKQiAex56AAKFFebVFeI958.png

简要来说,DMA以burst形式传输数据,意思是分批次搬移。手册说明原或目的burst_size位宽不能超过64bit,这也是其挂载AXI总线的数据位宽。PS_DMA_InitPara()里的SrcBurstSize为源突发传输位宽字节数,最大为8.SrcBurstLen是手册中所说的“burst length”,即突发传输数据个数。SrcInc表示burst types为地址自增(1)还是地址固定(0)模式。目的控制字同理。剩下的三个参数最重要:SrcAddr DstAddr Length分别代表源首地址 目的首地址和一共需要搬移的数据字节数。需要注意的是,一定要满足srcburstsize*srcburstlen == dstburstsize*dstburstlen,否则发生错误。这一点也比较好理解,相当于FPGA逻辑设计中的异步FIFO两侧数据带宽要匹配。

那么要想完成OCM到DDR的数据搬移,改动下地址就可以嘛。由于读写DDR要访问绝对地址,所以要格外注意读写操作的地址不能和DDR内存储程序代码和中间数据的地址段重叠。避免程序崩溃很简单的做法就是在XPAR_PS7_DDR_0_S_AXI_BASEADDR 的基础上加一段偏移量,具体加多少的问题本人也不是很明确,希望看到的朋友能在评论中指点一二。

对于ZYNQ这一SOC架构来说,PS端连接如以太网USB等高带宽外设计接口更加方便,所以PS_DMA的灵活运用还好是十分必要的,更灵活高效的利用这一硬件资源还要后期继续探索。PS端和PL端高速数据交互就需要用到另一个DMA成员AXI_DMA,可以说它利用片内总线打破了CPU+FPGA架构的性能瓶颈,该部分内容将在后续说明。

编辑:hfy


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1629

    文章

    21729

    浏览量

    602986
  • 以太网
    +关注

    关注

    40

    文章

    5419

    浏览量

    171598
  • usb
    usb
    +关注

    关注

    60

    文章

    7936

    浏览量

    264474
  • Zynq
    +关注

    关注

    10

    文章

    609

    浏览量

    47174
收藏 人收藏

    评论

    相关推荐

    自动驾驶技术研究与分析

    传递和全局优化的优势,成为智能驾驶技术发展的重要方向。与传统模块化架构相比,技术通过深度神经网络实现从传感器数据输入车辆控制信号输出
    的头像 发表于 12-19 13:07 80次阅读

    在自动泊车的应用

    与城市环境的复杂性和高速公路驾驶的风险相比,停车场景的特点是低速、空间有限和高可控性。这些特点为在车辆中逐步部署自动驾驶能力提供了可行的途径。最重要的是自动泊车对时间不敏感,而自动驾驶帧率至少
    的头像 发表于 12-18 11:38 329次阅读
    <b class='flag-5'>端</b><b class='flag-5'>到</b><b class='flag-5'>端</b>在自动泊车的应用

    PS3111固件下载,PS3111 SSD开卡工具成功修复,HG2258量产开卡参考教程

    PS3111 SSD开卡成功,PS3111固件下载,HG2258量产开卡参考教程
    的头像 发表于 12-04 18:18 271次阅读
    <b class='flag-5'>PS</b>3111固件下载,<b class='flag-5'>PS</b>3111 SSD开卡工具成功修复,HG2258量产开卡参考教程

    爆火的如何加速智驾落地?

    自动驾驶,唯有?)技术通过消除模块间数据
    的头像 发表于 11-26 13:17 238次阅读
    爆火的<b class='flag-5'>端</b><b class='flag-5'>到</b><b class='flag-5'>端</b>如何加速智驾落地?

    连接视觉语言大模型与自动驾驶

    自动驾驶在大规模驾驶数据上训练,展现出很强的决策规划能力,但是面对复杂罕见的驾驶场景,依然存在局限性,这是因为
    的头像 发表于 11-07 15:15 223次阅读
    连接视觉语言大模型与<b class='flag-5'>端</b><b class='flag-5'>到</b><b class='flag-5'>端</b>自动驾驶

    InfiniBand网络解决LLM训练瓶颈

    的,这需要大量的计算资源和高速数据传输网络。InfiniBand(IB)网络作为高性能计算和AI模型训练的理想选择,发挥着重要作用。在本文中,我们将深入探讨大型语言模型(LLM)
    的头像 发表于 10-23 11:26 379次阅读
    <b class='flag-5'>端</b><b class='flag-5'>到</b><b class='flag-5'>端</b>InfiniBand网络解决LLM训练瓶颈

    测试用例怎么写

    测试方法,旨在验证整个应用程序从前端后端的流程是否能够按照预期工作。它涉及多个系统组件和接口的交互,确保业务流程的完整性和正确性。 二、编写
    的头像 发表于 09-20 10:29 439次阅读

    复旦微PS+PL异构多核开发案例分享,基于FMQL20SM国产处理器平台

    FMQL20S400M是复旦微四核ARM Cortex-A7@1GHz(PS)+85K可编程逻辑资源(PL)异构多核SoC处理器。创龙科技基于FMQL20S400M设计的工业核心板
    发表于 08-22 14:04

    实现自动驾驶,唯有

    ,去年行业主流方案还是轻高精地图城区智驾,今年大家的目标都瞄到了(End-to-End, E2E)。
    的头像 发表于 08-12 09:14 720次阅读
    实现自动驾驶,唯有<b class='flag-5'>端</b><b class='flag-5'>到</b><b class='flag-5'>端</b>?

    FM20S用户手册-PS + PL异构多核案例开发手册

    PS) + FPGA可编程逻辑资源(PL)异构多核SoC处理器设计的全国产工业评估板,PS
    发表于 07-25 16:14

    有关PL利用AXI总线控制PSDDR进行读写(从机wready信号一直不拉高)

    一直拉高的。这与写数据通道好像有点区别。 我不清楚PS DDR到底发生了什么,但是和MIG核就是有点不一样,通过仿真MIG核可以发现,PL
    发表于 05-31 12:04

    小鹏汽车发布大模型

    小鹏汽车近日宣布,其成功研发并发布了“国内首个量产上车”的大模型,该模型可直接通过传感器输入内容来控制车辆,标志着智能驾驶技术的新突破。
    的头像 发表于 05-21 15:09 676次阅读

    Xilinx ZYNQ 动手实操演练

    的一致性。也就是是说,第一个A9处理器写存储时,只是写在了缓存里,没有进主存,如果第二个A9读操作,涉及第一个写脏了的数据段, SCU要保证第二个A9的缓存里是最新的
    发表于 05-03 19:28

    如何使用Vitis自带的LWIP模板进行PS千兆以太网TCP通信?

    开发板有两路千兆以太网,通过RGMII接口连接,本实验演示如何使用Vitis自带的LWIP模板进行PS千兆以太网TCP通信。
    的头像 发表于 04-28 10:44 3381次阅读
    如何使用Vitis自带的LWIP模板进行<b class='flag-5'>PS</b><b class='flag-5'>端</b>千兆以太网TCP通信?

    请问FX3的UART口和Xilinx ZYNQ7000的PS的UART进行硬件连接需要TTL电平转换吗?

    想让FX3的UART口和Xilinx ZYNQ7000的PS(Processor system)的内置UART相互通信,两个芯片使用的是同一个电源(同在一块板子上或分别在两块相互连接的板子上),请教一下它们之间的硬件连接需要T
    发表于 02-28 08:32