Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
Artem Melnykov
Published © MIT

Baremetal DMA transfers on Zynq in scatter-gather mode

This describes the software needed to receive and process DMA transfers from a previously designed event counter

IntermediateWork in progress3 hours414
Baremetal DMA transfers on Zynq in scatter-gather mode

Things used in this project

Hardware components

Z-turn board (Zynq-7010)
×1
Z-turn cape
×1

Software apps and online services

Vitis Unified Software Platform
AMD Vitis Unified Software Platform

Story

Read more

Code

main.c

C/C++
//#include "xtime_l.h"
#include <stdbool.h>

#include "initRxDma.h"
#include "customIPs.h"
#include "testEvsimDMA.h"

// where processed data is stored
#define STORE_BUFFER_BASE (RX_BUFFER_HIGH+1)
#define STORE_BUFFER_SIZE (PROCESSING_SIZE*20)


u8* buffData = (u8*)RX_BUFFER_BASE;
u32 RxProcessed=0; // number of packets processed by this application so far
u32 availableDataSize = 0; // size of data available for processing

u8 iatcOverflow=0;
u8 processingOverflow=0;

u8* storeBuffer = (u8*)STORE_BUFFER_BASE;
u32 processedDataSize = 0; // size of data processed so far
u32 toProcessDataSize = 0;

u32 max_iatc = 1500; // do not exceed 2^14-1 = 16383
u32 max_evsim = 16383;  // do not exceed 2^14-1 = 16383


int main(void)
{
	int Status;
	bool isProcessing = true; // a flag indicating that data should be processed

	// initial state of the counter and the event simulator
	disableIatc();
	setMaxcountIatc(max_iatc);
	disableEvsim();
	setMaxcountEvsim(max_evsim);

	// enable the event simulator
	enableEvsim();

	Status = SetupIntrSystem();
	if (Status != XST_SUCCESS) {
		xil_printf("Failed to setup the interrupt system, return value = %i\r\n", Status);
		return Status;
	}

	Status = SetupAxiDMA();
	if (Status != XST_SUCCESS) {
		xil_printf("Failed to setup AxiDMA, return value = %i\r\n", Status);
		return Status;
	}

	Status = ConnectIntrAxiDMA();
	if (Status != XST_SUCCESS) {
		xil_printf("Failed to connect AxiDMA interrupts, return value = %i\r\n", Status);
		return Status;
	}

	Status = ConnectIntrIatc(&iatcOverflow);
	if (Status != XST_SUCCESS) {
		xil_printf("Failed to connect iatc interrupts, return value = %i\r\n", Status);
		return Status;
	}

	// enable the counter
	enableIatc();

	while (1) {

		// figure out how much data is available for processing
		availableDataSize = (getRxDone()-RxProcessed)*MAX_PKT_LEN;

		// check for processing buffer overflow
		if ( availableDataSize >= PROCESSING_SIZE*BUFFER_CAPACITY/2 ) {
			processingOverflow = 1;
		}

		if (isProcessing && availableDataSize>=PROCESSING_SIZE) { // is enough data available?
   			// figure out how much contiguous data is available for processing
			if ( (u8*)RX_BUFFER_HIGH-buffData+1 < PROCESSING_SIZE) {
   				toProcessDataSize = (u8*)RX_BUFFER_HIGH-buffData+1;
   			} else {
   				toProcessDataSize = PROCESSING_SIZE;
   			}
			// check that all that data can be processed
   			if ( toProcessDataSize > (STORE_BUFFER_SIZE-((u32)storeBuffer-STORE_BUFFER_BASE)) ) {
   				toProcessDataSize = STORE_BUFFER_SIZE-((u32)storeBuffer-STORE_BUFFER_BASE);
   			}

   			// process
   			xil_printf("Copying %i bytes... ", toProcessDataSize);
   			memcpy(storeBuffer,buffData,toProcessDataSize);
   			xil_printf("Done.\r\n");

   			// flush the processed data
   			Xil_DCacheFlushRange((INTPTR)buffData, toProcessDataSize);

   			// advance pointers etc
   			storeBuffer += toProcessDataSize;
   			processedDataSize += toProcessDataSize;
   			RxProcessed += toProcessDataSize / MAX_PKT_LEN;
			buffData += toProcessDataSize;
			if (buffData>(u8*)RX_BUFFER_HIGH) {
				buffData = (u8*)RX_BUFFER_BASE;
			}

			// terminate if there is no more space left for storage
   			if ( (u8*)STORE_BUFFER_SIZE <= (storeBuffer-STORE_BUFFER_BASE) ) {
   	    		xil_printf("Terminating on reaching storage capacity.\r\n", Status);
   	    		isProcessing = false;
   	    		// comment out the next line to observe processing buffer overflow
   				break;
   			}

   		}

   		// check for overflows
    	if (iatcOverflow!=0) {
    		xil_printf("Error: iatc fifo overflow. Stopping the execution.\r\n", Status);
    		break;
    	}
    	if (processingOverflow!=0) {
    		xil_printf("Error: processing buffer overflow. Stopping the execution.\r\n", Status);
    		break;
    	}
	}

	disableIatc();
	disableEvsim();

	// check data for accuracy
	xil_printf("Starting testing...\r\n");
	u32 totalEventCount = STORE_BUFFER_SIZE/2;
	u32 totalErrorCount;
	totalErrorCount = testEvsimData((u8*)STORE_BUFFER_BASE, STORE_BUFFER_SIZE, max_evsim, max_iatc, 10);
	xil_printf("Finished testing!\r\n");
	xil_printf("Total event count = %u\r\n", totalEventCount);
	xil_printf("Total error count = %u\r\n", totalErrorCount);

	xil_printf("Done.\r\n");

	return XST_SUCCESS;
}

initRxDma.h

C/C++
#include "xaxidma.h"

#define PROCESSING_SIZE 256*512 // 128 kB

#define BD_SIZE	4*16
#define BUFFER_CAPACITY 10 // as measured in PROCESSING_SIZE chunks

#define MAX_PKT_LEN		256 // when TLAST is generated but in bytes

#define MEM_BASE_ADDR		0x01000000
#define RX_BD_SPACE_BASE	(MEM_BASE_ADDR)
#define RX_BD_SPACE_HIGH	(RX_BD_SPACE_BASE + ((PROCESSING_SIZE*BUFFER_CAPACITY)/MAX_PKT_LEN)*BD_SIZE - 1)
#define RX_BUFFER_BASE		(RX_BD_SPACE_HIGH + 1)
#define RX_BUFFER_HIGH		(RX_BUFFER_BASE + PROCESSING_SIZE*BUFFER_CAPACITY - 1)

/*
 * Number of BDs in the transfer example
 * We show how to submit multiple BDs for one transmit.
 * The receive side get one completion interrupt per cyclic transfer.
 */
#define NUMBER_OF_BDS_PER_PKT		1

/* 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 per cyclic transfer.
 */
#define COALESCING_COUNT		255
#define DELAY_TIMER_COUNT		0

int SetupIntrSystem();

int SetupAxiDMA();
int ConnectIntrAxiDMA();
void DisconnectIntrAxiDMA();

int ConnectIntrIatc(u8* Callback);

u32 getRxDone();
void resetRxDone();
int DMAReset();

initRxDma.c

C/C++
/******************************************************************************
* Copyright (C) 2018 - 2022 Xilinx, Inc.  All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/

/*****************************************************************************/
/**
*
*<pre>
* MODIFICATION HISTORY:
*
* Modified starting from xaxidma_example_sgcyclic_intr.c Ver 9.15
*</pre>
******************************************************************************/

/***************************** Include Files *********************************/

#include "initRxDma.h"

#include "xscugic.h"

/************************** Constant Definitions *****************************/

#define DMA_DEV_ID			XPAR_AXIDMA_0_DEVICE_ID

#define RX_INTR_ID		XPAR_FABRIC_AXIDMA_0_VEC_ID
#define XPAR_FABRIC_IATC_INTROUT 62U
#define	INT_TYPE_RISING_EDGE	0x03
#define INT_TYPE_HIGHLEVEL		0x01
#define INT_TYPE_MASK			0x03
#define	INT_CFG0_OFFSET	0x00000C00

#define INTC_DEVICE_ID          XPAR_SCUGIC_SINGLE_DEVICE_ID

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

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

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

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

int SetupIntrSystem();
int SetupAxiDMA();

int ConnectIntrAxiDMA();
void DisconnectIntrAxiDMA();

int ConnectIntrIatc(u8* pOverflowStatus);

static int RxSetup(XAxiDma * AxiDmaInstancePtr);
static void RxIntrHandler(void *Callback);
static void IatcIntrHandler(void *Callback);
static void IntcTypeSetup(XScuGic *InstancePtr, int intId, int intType);
static void RxCallBack(XAxiDma_BdRing * RxRingPtr);

/************************** Variable Definitions *****************************/

volatile u32 RxDone=0;
volatile int Error=0;

/* The instances to support the device drivers are global such that the
 * are initialized to zero each time the program runs.
 */
static XScuGic IntcInstance;	/* The instance of the IRQ Controller */
static XAxiDma AxiDmaInstance;

u32 getRxDone() {
	return RxDone;
}

void resetRxDone() {
	// for reasons I don't fully understand
	// the first packet after restart is compromised
	// so it is skipped
	RxDone = -1;
}

int DMAReset() {
	XAxiDma_Reset(&AxiDmaInstance);
	int TimeOut = RESET_TIMEOUT_COUNTER;
	while (TimeOut) {
		if(XAxiDma_ResetIsDone(&AxiDmaInstance)) {
			return 0;
			break;
		}
		TimeOut -= 1;
	}
	return RESET_TIMEOUT_COUNTER;
}

int SetupIntrSystem() {

	XScuGic_Config *IntcConfig;
	XScuGic* IntcInstancePtr = &IntcInstance;
	int Status;

	/*
	 * Initialize the interrupt controller driver so that it is ready to
	 * use.
	 */
	IntcConfig = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
	if (NULL == IntcConfig) {
		return XST_FAILURE;
	}
	Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
					IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	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,
				    IntcInstancePtr);

	Xil_ExceptionEnable();

	return XST_SUCCESS;
}

int SetupAxiDMA() {

    XAxiDma_Config* pConfigAxiDma;
    XAxiDma * AxiDmaInstancePtr = &AxiDmaInstance;
    int Status;

    // set up AXI_DMA
    xil_printf("Setting up AXI_DMA...");
    pConfigAxiDma = XAxiDma_LookupConfig(DMA_DEV_ID);
	if (!pConfigAxiDma) {
		xil_printf("No config found for %d\r\n", DMA_DEV_ID);

		return XST_FAILURE;
	}

	/* Initialize DMA engine */
	XAxiDma_CfgInitialize(AxiDmaInstancePtr, pConfigAxiDma);

	xil_printf("Number of channels: ");
	xil_printf("%u",AxiDmaInstancePtr->RxNumChannels);
	xil_printf("\r\n");

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

	Status = RxSetup(AxiDmaInstancePtr);
	if (Status != XST_SUCCESS) {
		xil_printf("Failed RX setup\r\n");
		return XST_FAILURE;
	}
	xil_printf("Done.\r\n");

	return XST_SUCCESS;
}

/*****************************************************************************/
/*
*
* 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(AxiDmaInstPtr);

	/* 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
	 *
	 * 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;
}

int ConnectIntrAxiDMA()
{
    XAxiDma * AxiDmaInstancePtr = &AxiDmaInstance;
	XScuGic* IntcInstancePtr = &IntcInstance;

    XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(AxiDmaInstancePtr);
	int Status;

	// set low priority to DMA and overflow interrupts
	XScuGic_SetPriorityTriggerType(IntcInstancePtr, RX_INTR_ID, 0xA0, 0x3);

	// connect DMA interrupt handler
	Status = XScuGic_Connect(IntcInstancePtr, RX_INTR_ID,
				(Xil_InterruptHandler)RxIntrHandler,
				RxRingPtr);
	if (Status != XST_SUCCESS) {
		return Status;
	}

	// enable all interrupts
	XScuGic_Enable(IntcInstancePtr, RX_INTR_ID);

	return XST_SUCCESS;

}

void DisconnectIntrAxiDMA()
{
	XScuGic* IntcInstancePtr = &IntcInstance;
	/* Disconnect and disable the interrupt for DMA */
	XScuGic_Disconnect(IntcInstancePtr, RX_INTR_ID);
}

/*****************************************************************************/
/*
*
* 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(&AxiDmaInstance);

		TimeOut = RESET_TIMEOUT_COUNTER;

		while (TimeOut) {
			if(XAxiDma_ResetIsDone(&AxiDmaInstance)) {
				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 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=0;
	XAxiDma_Bd* BdPtr;

	// Get finished BDs from hardware
	BdCount = XAxiDma_BdRingFromHw(RxRingPtr, XAXIDMA_ALL_BDS, &BdPtr);

	RxDone += BdCount;
}


int ConnectIntrIatc(u8* pOverflowStatus)
{
	int Status;
	XScuGic* IntcInstancePtr = &IntcInstance;

	// set low priority to overflow interrupts
	XScuGic_SetPriorityTriggerType(IntcInstancePtr, XPAR_FABRIC_IATC_INTROUT, 0xA0, 0x3);

	// connect iatc interrupt handler
	Status = XScuGic_Connect(IntcInstancePtr, XPAR_FABRIC_IATC_INTROUT,
				(Xil_InterruptHandler)IatcIntrHandler, pOverflowStatus);
	if (Status != XST_SUCCESS) {
		return Status;
	}
	// iatc interrupt happens on rising edge
	IntcTypeSetup(IntcInstancePtr, XPAR_FABRIC_IATC_INTROUT, INT_TYPE_RISING_EDGE);

	// enable all interrupts
	XScuGic_Enable(IntcInstancePtr, XPAR_FABRIC_IATC_INTROUT);

	return XST_SUCCESS;
}

static void IatcIntrHandler(void *Callback) {
	*(u8*)Callback = 1;
}

// is this function necessary?
static void IntcTypeSetup(XScuGic *InstancePtr, int intId, int intType)
{
	int mask;

	intType &= INT_TYPE_MASK;
	mask = XScuGic_DistReadReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4);
	mask &= ~(INT_TYPE_MASK << (intId%16)*2);
	mask |= intType << ((intId%16)*2);
	XScuGic_DistWriteReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4, mask);
}

customIPs.h

C/C++
#include "xparameters.h"

#define DISABLE_IATC 0x00000000
#define ENABLE_IATC 0x00000001
#define DISABLE_EVSIM 0x00000000
#define ENABLE_EVSIM 0x00000001

void disableIatc();
void enableIatc();
void setMaxcountIatc(int maxIatc);
void disableEvsim();
void enableEvsim();
void setMaxcountEvsim(int maxEvsim);

customIPs.c

C/C++
#include "customIPs.h"
#include "eventSimSmart.h"
#include "iatcollector2chSmart.h"

// disable the counter
void disableIatc() {
	IATCOLLECTOR2CHSMART_mWriteReg(XPAR_IATCOLLECTOR2CHSMART_0_BASEADDR,
								   IATCOLLECTOR2CHSMART_S00_AXI_SLV_REG0_OFFSET,
								   DISABLE_IATC);
}

// enable the counter
void enableIatc() {
	IATCOLLECTOR2CHSMART_mWriteReg(XPAR_IATCOLLECTOR2CHSMART_0_BASEADDR,
								   IATCOLLECTOR2CHSMART_S00_AXI_SLV_REG0_OFFSET,
								   ENABLE_IATC);
}

// write the max iatc count
void setMaxcountIatc(int maxIatc) {
	IATCOLLECTOR2CHSMART_mWriteReg(XPAR_IATCOLLECTOR2CHSMART_0_BASEADDR,
								   IATCOLLECTOR2CHSMART_S00_AXI_SLV_REG1_OFFSET,
								   maxIatc);
}

// disable the simulator
void disableEvsim() {
	EVENTSIMSMART_mWriteReg(XPAR_EVENTSIMSMART_0_BASEADDR,
							EVENTSIMSMART_S00_AXI_SLV_REG0_OFFSET,
							DISABLE_EVSIM);
}

// enable the simulator
void enableEvsim() {
	EVENTSIMSMART_mWriteReg(XPAR_EVENTSIMSMART_0_BASEADDR,
							EVENTSIMSMART_S00_AXI_SLV_REG0_OFFSET,
							ENABLE_EVSIM);
}

// write the max simulator count
void setMaxcountEvsim(int maxEvsim) {
	EVENTSIMSMART_mWriteReg(XPAR_EVENTSIMSMART_0_BASEADDR,
							EVENTSIMSMART_S00_AXI_SLV_REG1_OFFSET,
							maxEvsim);
}

testEvsimDMA.h

C/C++
#include "xil_types.h"

int testEvsimData(u8* buffer, size_t bufferSize,
				  u32 maxSimCount, u32 maxCounterValue,
				  u32 numReportedErrors);

testEvsimDMA.c

C/C++
#include "testEvsimDMA.h"
#include "xil_printf.h"
#include <stdbool.h>

// 16-bit counter
const u16 MASK_TIME = 0x3FFF;
const u16 MASK_CH1 = 0x4000;
const u16 MASK_CH2 = 0x8000;
// 32-bit counter
//const u32 MASK_TIME = 0x3FFFFFFF;
//const u32 MASK_CH1 = 0x40000000;
//const u32 MASK_CH2 = 0x80000000;

u32 eventNumber = 0; // counts channel 1 and channel 2 events only, not rollovers
u32 expectedNextValue = 0;
u64 cumulativeTime = 0;

int testEvsimData(u8* buffer, size_t bufferSize, u32 maxEvsimValue, u32 maxIatcValue, u32 numReportedErrors) {

	unsigned long errorCount = 0;
	bool reportError = true;

	// 16-bit
	u16 time;
	u16 ch1;
	u16 ch2;
	u16* ptr = (u16*)buffer;

	// 32-bit
	//u32 time;
	//u32 ch1;
	//u32 ch2;
	//u32* ptr = (u32*)buffer;

	for (size_t ii = 0; ii < bufferSize / sizeof(MASK_TIME); ii++) {

		// extract time and channel information from the data
		time = *ptr & MASK_TIME;
		ch1 = *ptr & MASK_CH1;
		ch2 = *ptr & MASK_CH2;

		cumulativeTime += time;

		if (ch1 == 0 && ch2 == 0) { // rollover event
			if (time!=maxIatcValue) {
				errorCount++;
				if (reportError) {
					xil_printf("Processing error: premature counter rollover %u at %u\r\n", time, eventNumber);
				}
			}
		}
		else if (ch1 != 0 && ch2 != 0) { // dual channel event
			eventNumber++;
			errorCount++;
			if (reportError) {
				xil_printf("Processing error: dual channel event %u at %u\r\n", cumulativeTime, eventNumber);
			}
			cumulativeTime=0;
		}
		else if (ch2 != 0) { // channel 2 event
			eventNumber++;
			if (eventNumber == 1) {} // ignore event1
			else if (eventNumber == 2) { // don't check event2 but use to calculate the next value
				if (cumulativeTime < maxEvsimValue) {
					expectedNextValue = cumulativeTime + 1; // next value should be larger by 1
				}
				else {
					expectedNextValue = 2;
				}
			}
			else {
				if (cumulativeTime != expectedNextValue) {
					if (reportError) {
						xil_printf("Processing error: mismatch; expected %u but found %u\r\n", expectedNextValue, cumulativeTime);
					}
					errorCount++;
				}
				if (cumulativeTime < maxEvsimValue) {
					expectedNextValue = cumulativeTime + 1;
				}
				else {
					expectedNextValue = 2;
				}
			}
			cumulativeTime = 0;
		}
		else if (ch1 != 0) { // channel 1 event
			eventNumber++;
			errorCount++;
			if (reportError) {
				xil_printf("Processing error: detected ch1 event %u at %u\r\n", cumulativeTime, eventNumber);
			}
			cumulativeTime = 0;
		}

		if ( reportError && (errorCount==numReportedErrors) ) {
			xil_printf("Additional errors for this block will be suppressed.\r\n");
			reportError = false;
		}
		ptr++;
	}
	return errorCount;
}

iatcollector2chSmart.zip

C/C++
No preview (download only).

eventSimSmart.zip

C/C++
No preview (download only).

Credits

Artem Melnykov
4 projects • 2 followers
Contact

Comments

Please log in or sign up to comment.