cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Observer
Observer
1,469 Views
Registered: ‎04-04-2018

AXI DMA SG Cyclic in Real Time

Jump to solution

I am trying to stream real-time ADC data by using AXI DMA in SG cyclic mode. At this stage, I try to avoid the FIFO by creating a 32-bit counter with a clock enable pin. This clock enable pin is connected to tready signal from DMA S_AXIS_S2MM interface. So when DMA is ready, the counter will start counting.

In the SDK, I modified the example code "xaxidma_example_sgcyclic_intr.c" from xilinx, but only using the S2MM channel.

1. The example code will keep DMA running for a number of defined cycles and check the data. It works fine in tests with my FPGA firmware. However, the code will not work at all without reseting the DMA in the end by call function "XAxiDma_Reset(&AxiDma);". Why is this DMA reset required?

2. Then I tried to modifed to code for real-time data streaming. Basically, I added an point "RxPacket" to "RX_BUFFER_BASE", in order to get data in real time. The counter "RxOutputted" is added to avoid overflow. The code is shown below. However, it doesn't work properly. It seems I also need to reset DMA before reading data from the address "RX_BUFFER_BASE". How can it be fixed?

3. Any other suggestions on streaming real-time DMA data are also welcomed. Thank you.

/******************************************************************************
*
* Copyright (C) 2017 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xaxidma_example_sgcyclic_intr.c
*
* This file demonstrates how to use the xaxidma driver on the Xilinx AXI
* DMA core (AXIDMA) to transfer packets in interrupt mode when the AXIDMA
* core is configured in Scatter Gather Mode
*
* This example demonstrates how to use cyclic DMA mode feature.
* This program will recycle the NUMBER_OF_BDS_TO_TRANSFER
* buffer descriptors to specified number of cyclic transfers defined in
* "NUMBER_OF_CYCLIC_TRANSFERS".
*
* This code assumes a loopback hardware widget is connected to the AXI DMA
* core for data packet loopback.
*
* To see the debug print, you need a Uart16550 or uartlite in your system,
* and please set "-DDEBUG" in your compiler options. You need to rebuild your
* software executable.
*
* Make sure that MEMORY_BASE is defined properly as per the HW system. The
* h/w system built in Area mode has a maximum DDR memory limit of 64MB. In
* throughput mode, it is 512MB. These limits are need to ensured for
* proper operation of this code.
*
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 9.4 adk 25/07/17 Initial version.
* 9.6 rsp 02/14/18 Support data buffers above 4GB.Use UINTPTR for storing
* and typecasting buffer address(CR-992638).
* </pre>
*
* ***************************************************************************
*/
/***************************** Include Files *********************************/
#include "xaxidma.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"

#ifdef __aarch64__
#include "xil_mmu.h"
#endif

#ifdef XPAR_UARTNS550_0_BASEADDR
#include "xuartns550_l.h" /* to use uartns550 */
#endif

#ifndef DEBUG
extern void xil_printf(const char *format, ...);
#endif

#ifdef XPAR_INTC_0_DEVICE_ID
#include "xintc.h"
#else
#include "xscugic.h"
#endif

/******************** Constant Definitions **********************************/
/*
* Device hardware build related constants.
*/

#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID

#ifdef XPAR_PS7_DDR_0_S_AXI_BASEADDR
#define DDR_BASE_ADDR XPAR_PS7_DDR_0_S_AXI_BASEADDR
#elif XPAR_MIG7SERIES_0_BASEADDR
#define DDR_BASE_ADDR XPAR_MIG7SERIES_0_BASEADDR
#elif XPAR_MIG_0_BASEADDR
#define DDR_BASE_ADDR XPAR_MIG_0_BASEADDR
#elif XPAR_PSU_DDR_0_S_AXI_BASEADDR
#define DDR_BASE_ADDR XPAR_PSU_DDR_0_S_AXI_BASEADDR
#endif

#ifndef DDR_BASE_ADDR
#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \
DEFAULT SET TO 0x01000000
#define MEM_BASE_ADDR 0x01000000
//#define MEM_BASE_ADDR 0x00000000
#else
#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x1000000)
#endif

#ifdef XPAR_INTC_0_DEVICE_ID
#define RX_INTR_ID XPAR_INTC_0_AXIDMA_0_S2MM_INTROUT_VEC_ID
#else
#define RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID
#endif

#define RX_BD_SPACE_BASE (MEM_BASE_ADDR)
#define RX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x0000FFFF)
#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000)
#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF)
//#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x00FFFFFF)

#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID
#else
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#endif

/* Timeout loop counter for reset
*/
#define RESET_TIMEOUT_COUNTER 10000

/*
* Buffer and Buffer Descriptor related constant definition
*/
#define MAX_PKT_LEN 32768
#define MARK_UNCACHEABLE 0x701

/*
* Number of BDs in the transfer example
* We show how to submit multiple BDs for one transmit.
* The receive side gets one completion per transfer.
*/
#define NUMBER_OF_BDS_PER_PKT 8
#define NUMBER_OF_PKTS_TO_TRANSFER 10
#define NUMBER_OF_BDS_TO_TRANSFER (NUMBER_OF_PKTS_TO_TRANSFER * \
NUMBER_OF_BDS_PER_PKT)

//#define NUMBER_OF_CYCLIC_TRANSFERS 100
#define NUMBER_OF_CYCLIC_TRANSFERS 10

/* The interrupt coalescing threshold and delay timer threshold
* Valid range is 1 to 255
*
* We set the coalescing threshold to be the total number of packets.
* The receive side will only get one completion interrupt for this example.
*/
#define COALESCING_COUNT NUMBER_OF_PKTS_TO_TRANSFER
#define DELAY_TIMER_COUNT 100 // smaller value will have more interrupt
//#define DELAY_TIMER_COUNT 0

#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC XIntc
#define INTC_HANDLER XIntc_InterruptHandler
#else
#define INTC XScuGic
#define INTC_HANDLER XScuGic_InterruptHandler
#endif

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


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


/************************** Function Prototypes ******************************/
#ifdef XPAR_UARTNS550_0_BASEADDR
static void Uart550_Setup(void);
#endif

static int CheckData(int Length);
static void RxCallBack(XAxiDma_BdRing * RxRingPtr);
static void RxIntrHandler(void *Callback);

 

static int SetupIntrSystem(INTC * IntcInstancePtr,
XAxiDma * AxiDmaPtr, u16 RxIntrId);
static void DisableIntrSystem(INTC * IntcInstancePtr,
u16 RxIntrId);

static int RxSetup(XAxiDma * AxiDmaInstPtr);
//static int TxSetup(XAxiDma * AxiDmaInstPtr);
//static int SendPacket(XAxiDma * AxiDmaInstPtr);

/************************** Variable Definitions *****************************/
/*
* Device instance definitions
*/
XAxiDma AxiDma;

static INTC Intc; /* Instance of the Interrupt Controller */

/*
* Flags interrupt handlers use to notify the application context the events.
*/
volatile unsigned int RxDone;
volatile unsigned int Error;
volatile unsigned int RxOutputted;

/*
* Buffer for transmit packet. Must be 32-bit aligned to be used by DMA.
*/

/*****************************************************************************/
/**
*
* Main function
*
* This function is the main entry of the interrupt test. It does the following:
* - Set up the output terminal if UART16550 is in the hardware build
* - Initialize the DMA engine
* - Set up Tx and Rx channels
* - Set up the interrupt system for the Tx and Rx interrupts
* - Submit a transfer
* - Wait for the transfer to finish
* - Check transfer status
* - Disable Tx and Rx interrupts
* - Print test status and exit
*
* @param None
*
* @return
* - XST_SUCCESS if tests pass
* - XST_FAILURE if fails.
*
* @note None.
*
******************************************************************************/
int main(void)
{
const uint32_t *RxPacket = (const uint32_t *)RX_BUFFER_BASE;
int Status;
XAxiDma_Config *Config;

/* Initialize flags before start transfer test */
RxDone = 0;
RxOutputted = 0;
Error = 0;

/* Initial setup for Uart16550 */
#ifdef XPAR_UARTNS550_0_BASEADDR

Uart550_Setup();

#endif

// xil_printf("\r\n--- Entering main() --- \r\n");
#ifdef __aarch64__
Xil_SetTlbAttributes(, MARK_UNCACHEABLE);
#endif

Config = XAxiDma_LookupConfig(DMA_DEV_ID);
if (!Config) {
xil_printf("No config found for %d\r\n", DMA_DEV_ID);

return XST_FAILURE;
}

/* Initialize DMA engine */
XAxiDma_CfgInitialize(&AxiDma, Config);

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

/* Set up TX/RX channels to be ready to transmit and receive packets */

Status = RxSetup(&AxiDma);
if (Status != XST_SUCCESS) {

xil_printf("Failed RX setup\r\n");
return XST_FAILURE;
}

/* Set up Interrupt system */
Status = SetupIntrSystem(&Intc, &AxiDma, RX_INTR_ID);
if (Status != XST_SUCCESS) {

xil_printf("Failed intr setup\r\n");
return XST_FAILURE;
}

/*
* Wait TX done and RX done
*/
while(!Error) {
if (RxOutputted != RxDone) {
xil_printf("%d %d\r\n", RxOutputted, RxPacket[RxOutputted & (RX_BUFFER_HIGH - RX_BUFFER_BASE)]);
RxOutputted++;
}
}

XAxiDma_Reset(&AxiDma);

if (Error) {
xil_printf("Failed test RXdone!\r\n");

goto Done;

}else {

/*
* Test finished, check data
*/
// Status = CheckData(MAX_PKT_LEN * NUMBER_OF_BDS_TO_TRANSFER);
if (Status != XST_SUCCESS) {

xil_printf("Data check failed\r\n");

goto Done;
}

// xil_printf("Successfully ran AXI DMA Cyclic SG interrupt Example\r\n");
}

/* Disable TX and RX Ring interrupts and return success */
DisableIntrSystem(&Intc, RX_INTR_ID);

Done:

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

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

return XST_SUCCESS;
}

#ifdef XPAR_UARTNS550_0_BASEADDR
/*****************************************************************************/
/*
*
* Uart16550 setup routine, need to set baudrate to 9600 and data bits to 8
*
* @param None
*
* @return None
*
* @note None.
*
******************************************************************************/
static void Uart550_Setup(void)
{

XUartNs550_SetBaud(XPAR_UARTNS550_0_BASEADDR,
XPAR_XUARTNS550_CLOCK_HZ, 9600);

XUartNs550_SetLineControlReg(XPAR_UARTNS550_0_BASEADDR,
XUN_LCR_8_DATA_BITS);
}
#endif

/*****************************************************************************/
/*
*
* This function checks data buffer after the DMA transfer is finished.
*
* We use the static tx/rx buffers.
*
* @param Length is the length to check
* @param StartValue is the starting value of the first byte
*
* @return - XST_SUCCESS if validation is successful
* - XST_FAILURE if validation fails.
*
* @note None.
*
******************************************************************************/
static int CheckData(int Length)
{
uint32_t *RxPacket;
int Index = 0;

RxPacket = (uint32_t *) RX_BUFFER_BASE;

/* Invalidate the DestBuffer before receiving the data, in case the
* Data Cache is enabled
*/
#ifndef __aarch64__
Xil_DCacheInvalidateRange((UINTPTR)RxPacket, Length);
#endif

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

xil_printf("%d %d\r\n",
Index, RxPacket[Index]);
}

return XST_SUCCESS;
}

/*****************************************************************************/
/*
*
* This is the DMA RX callback function called by the RX interrupt handler.
* This function handles finished BDs by hardware, attaches new buffers to those
* BDs, and give them back to hardware to receive more incoming packets
*
* @param RxRingPtr is a pointer to RX channel of the DMA engine.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void RxCallBack(XAxiDma_BdRing * RxRingPtr)
{
int BdCount;
XAxiDma_Bd *BdPtr;

/* Get finished BDs from hardware */
BdCount = XAxiDma_BdRingFromHw(RxRingPtr, XAXIDMA_ALL_BDS, &BdPtr);
RxDone += BdCount;
// XAxiDma_BdRingFree(RxRingPtr, BdCount, BdPtr); // Return the list
// RxDone += BdCount * RxRingPtr->Separation;
}

/*****************************************************************************/
/*
*
* This is the DMA RX interrupt handler function
*
* It gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. Otherwise, if a completion interrupt
* presents, then it calls the callback function.
*
* @param Callback is a pointer to RX channel of the DMA engine.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void RxIntrHandler(void *Callback)
{
XAxiDma_BdRing *RxRingPtr = (XAxiDma_BdRing *) Callback;
u32 IrqStatus;
int TimeOut;

/* Read pending interrupts */
IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr);

/* Acknowledge pending interrupts */
XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus);

/*
* If no interrupt is asserted, we do not do anything
*/
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
return;
}

/*
* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {

XAxiDma_BdRingDumpRegs(RxRingPtr);

Error = 1;


/* Reset could fail and hang
* NEED a way to handle this or do not call it??
*/
XAxiDma_Reset(&AxiDma);

TimeOut = RESET_TIMEOUT_COUNTER;

while (TimeOut) {
if(XAxiDma_ResetIsDone(&AxiDma)) {
break;
}

TimeOut -= 1;
}

return;
}

/*
* If completion interrupt is asserted, call RX call back function
* to handle the processed BDs and then raise the according flag.
*/
if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) {
RxCallBack(RxRingPtr);
}
}

/*****************************************************************************/
/*
*
* This function setups the interrupt system so interrupts can occur for the
* DMA, it assumes INTC component exists in the hardware system.
*
* @param IntcInstancePtr is a pointer to the instance of the INTC.
* @param AxiDmaPtr is a pointer to the instance of the DMA engine
* @param TxIntrId is the TX channel Interrupt ID.
* @param RxIntrId is the RX channel Interrupt ID.
*
* @return
* - XST_SUCCESS if successful,
* - XST_FAILURE.if not succesful
*
* @note None.
*
******************************************************************************/
static int SetupIntrSystem(INTC * IntcInstancePtr,
XAxiDma * AxiDmaPtr, u16 RxIntrId)
{
XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(AxiDmaPtr);
int Status;

#ifdef XPAR_INTC_0_DEVICE_ID

/* Initialize the interrupt controller and connect the ISRs */
Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID);
if (Status != XST_SUCCESS) {

xil_printf("Failed init intc\r\n");
return XST_FAILURE;
}

Status = XIntc_Connect(IntcInstancePtr, RxIntrId,
(XInterruptHandler) RxIntrHandler, RxRingPtr);
if (Status != XST_SUCCESS) {

xil_printf("Failed rx connect intc\r\n");
return XST_FAILURE;
}

/* Start the interrupt controller */
Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);
if (Status != XST_SUCCESS) {

xil_printf("Failed to start intc\r\n");
return XST_FAILURE;
}

XIntc_Enable(IntcInstancePtr, RxIntrId);

#else

XScuGic_Config *IntcConfig;


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

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

XScuGic_SetPriorityTriggerType(IntcInstancePtr, RxIntrId, 0xA0, 0x3);
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
Status = XScuGic_Connect(IntcInstancePtr, RxIntrId,
(Xil_InterruptHandler)RxIntrHandler,
RxRingPtr);
if (Status != XST_SUCCESS) {
return Status;
}

XScuGic_Enable(IntcInstancePtr, RxIntrId);
#endif

/* Enable interrupts from the hardware */

Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)INTC_HANDLER,
(void *)IntcInstancePtr);

Xil_ExceptionEnable();

return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* This function disables the interrupts for DMA engine.
*
* @param IntcInstancePtr is the pointer to the INTC component instance
* @param TxIntrId is interrupt ID associated w/ DMA TX channel
* @param RxIntrId is interrupt ID associated w/ DMA RX channel
*
* @return None.
*
* @note None.
*
******************************************************************************/
//static void DisableIntrSystem(INTC * IntcInstancePtr,
// u16 TxIntrId, u16 RxIntrId)
static void DisableIntrSystem(INTC * IntcInstancePtr,
u16 RxIntrId)
{
#ifdef XPAR_INTC_0_DEVICE_ID
/* Disconnect the interrupts for the DMA TX and RX channels */
XIntc_Disconnect(IntcInstancePtr, RxIntrId);
#else
XScuGic_Disconnect(IntcInstancePtr, RxIntrId);
#endif
}

/*****************************************************************************/
/*
*
* This function sets up RX channel of the DMA engine to be ready for packet
* reception
*
* @param AxiDmaInstPtr is the pointer to the instance of the DMA engine.
*
* @return - XST_SUCCESS if the setup is successful.
* - XST_FAILURE if fails.
*
* @note None.
*
******************************************************************************/
static int RxSetup(XAxiDma * AxiDmaInstPtr)
{
XAxiDma_BdRing *RxRingPtr;
int Status;
XAxiDma_Bd BdTemplate;
XAxiDma_Bd *BdPtr;
XAxiDma_Bd *BdCurPtr;
int BdCount;
int FreeBdCount;
UINTPTR RxBufferPtr;
int Index;

RxRingPtr = XAxiDma_GetRxRing(&AxiDma);

/* Disable all RX interrupts before RxBD space setup */
XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);

/* Setup Rx BD space */
BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT,
RX_BD_SPACE_HIGH - RX_BD_SPACE_BASE + 1);

Status = XAxiDma_BdRingCreate(RxRingPtr, RX_BD_SPACE_BASE,
RX_BD_SPACE_BASE,
XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount);
if (Status != XST_SUCCESS) {
xil_printf("Rx bd create failed with %d\r\n", Status);
return XST_FAILURE;
}

/*
* Setup a BD template for the Rx channel. Then copy it to every RX BD.
*/
XAxiDma_BdClear(&BdTemplate);
Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate);
if (Status != XST_SUCCESS) {
xil_printf("Rx bd clone failed with %d\r\n", Status);
return XST_FAILURE;
}

/* Attach buffers to RxBD ring so we are ready to receive packets */
FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);

Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr);
if (Status != XST_SUCCESS) {
xil_printf("Rx bd alloc failed with %d\r\n", Status);
return XST_FAILURE;
}

BdCurPtr = BdPtr;
RxBufferPtr = RX_BUFFER_BASE;

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

Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr);
if (Status != XST_SUCCESS) {
xil_printf("Rx set buffer addr %x on BD %x failed %d\r\n",
(unsigned int)RxBufferPtr,
(UINTPTR)BdCurPtr, Status);

return XST_FAILURE;
}

Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN,
RxRingPtr->MaxTransferLen);
if (Status != XST_SUCCESS) {
xil_printf("Rx set length %d on BD %x failed %d\r\n",
MAX_PKT_LEN, (UINTPTR)BdCurPtr, Status);

return XST_FAILURE;
}

/* Receive BDs do not need to set anything for the control
* The hardware will set the SOF/EOF bits per stream status
*/
XAxiDma_BdSetCtrl(BdCurPtr, 0);

XAxiDma_BdSetId(BdCurPtr, RxBufferPtr);

RxBufferPtr += MAX_PKT_LEN;
BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
}

/*
* Set the coalescing threshold, so only one receive interrupt
* occurs for this example
*
* If you would like to have multiple interrupts to happen, change
* the COALESCING_COUNT to be a smaller value
*/
Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, COALESCING_COUNT,
DELAY_TIMER_COUNT);
if (Status != XST_SUCCESS) {
xil_printf("Rx set coalesce failed with %d\r\n", Status);
return XST_FAILURE;
}

Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr);
if (Status != XST_SUCCESS) {
xil_printf("Rx ToHw failed with %d\r\n", Status);
return XST_FAILURE;
}

/* Enable all RX interrupts */
XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);
/* Enable Cyclic DMA mode */
XAxiDma_BdRingEnableCyclicDMA(RxRingPtr);
XAxiDma_SelectCyclicMode(AxiDmaInstPtr, XAXIDMA_DEVICE_TO_DMA, 1);

/* Start RX DMA channel */
Status = XAxiDma_BdRingStart(RxRingPtr);
if (Status != XST_SUCCESS) {
xil_printf("Rx start BD ring failed with %d\r\n", Status);
return XST_FAILURE;
}

return XST_SUCCESS;
}

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Moderator
Moderator
1,240 Views
Registered: ‎01-09-2019

Hello @efly_zhao 

I am not sure exactly what you are trying to do/how you would accomplish it, but I do have a couple notes about using SG Cyclic mode.  The basic premise of Cyclic mode is that the "Completed" bit does not get asserted when a BD has been used to transfer some data.  This means that you will need to handle that change in the "Completed" bit.  This code has been updated so I figured I would ask if you were using the most up-to-date code from our Github: https://github.com/Xilinx/embeddedsw/blob/master/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_sgcyclic_intr.c .

I think the reset is for the purpose of working through this "Completed" bit, but if handled properly in SW you should be able to not reset and keep streaming data.

The AXI DMA will still have to handle any delays related to the Slave you are writing to.  Where you are writing to may provide backpressure which would stop the AXI DMA from operating (deasserting TREADY).  This will make it difficult to provide full real time transfers of data.  The DMA cannot get around your Slave not being able to receive data, which most slaves will have a point where they cannot handle data at some point.

Thanks,
Caleb
-------------------------------------------------------------------------
Don’t forget to reply, kudo, and accept as solution.
-------------------------------------------------------------------------

View solution in original post

4 Replies
Highlighted
Contributor
Contributor
1,369 Views
Registered: ‎09-23-2018
Hi,

Were you able to solve this?
Thanks
0 Kudos
Highlighted
Observer
Observer
1,317 Views
Registered: ‎04-04-2018

Hi,

I didn't make progress on SG cyclic mode. So I am using DMA polling + a PL FIFO to solve this problem.

The DMA polling is modified from the example below. I modified the example so that the read data can be sent to PC via ethernet. The FIFO is placed to fill the gap when DMA is reseting.

https://www.xilinx.com/support/answers/57561.html

Some data in the 1st or 2nd transmitted packet may be lost. Because the FIFO need to synchronize between read and write at the begining. I waste lots of time on realizing it. Then everything seems to be fine. 

 To be honest, it is still far from a proper industrial design. But I am working on a research project with a tight deadline. So I live with it right now and will look back when this project moves to development stage.

0 Kudos
Highlighted
Moderator
Moderator
1,241 Views
Registered: ‎01-09-2019

Hello @efly_zhao 

I am not sure exactly what you are trying to do/how you would accomplish it, but I do have a couple notes about using SG Cyclic mode.  The basic premise of Cyclic mode is that the "Completed" bit does not get asserted when a BD has been used to transfer some data.  This means that you will need to handle that change in the "Completed" bit.  This code has been updated so I figured I would ask if you were using the most up-to-date code from our Github: https://github.com/Xilinx/embeddedsw/blob/master/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_sgcyclic_intr.c .

I think the reset is for the purpose of working through this "Completed" bit, but if handled properly in SW you should be able to not reset and keep streaming data.

The AXI DMA will still have to handle any delays related to the Slave you are writing to.  Where you are writing to may provide backpressure which would stop the AXI DMA from operating (deasserting TREADY).  This will make it difficult to provide full real time transfers of data.  The DMA cannot get around your Slave not being able to receive data, which most slaves will have a point where they cannot handle data at some point.

Thanks,
Caleb
-------------------------------------------------------------------------
Don’t forget to reply, kudo, and accept as solution.
-------------------------------------------------------------------------

View solution in original post

Highlighted
998 Views
Registered: ‎10-16-2019

Can you please share the working code ??

 

0 Kudos