VIVADO 4.CDMA的使用

                         本次实验测试CDMA来在ddr与bram之间搬运数据。

1.Vivado工程

CDMA上同时连接了四个BRAM。Bram设置为BRAM Controller模式,真双口BRAM,宽度64,深度1024,这样分配地址8k即可。VIVADO 4.CDMA的使用_第1张图片

2.地址分配(要注意)

VIVADO 4.CDMA的使用_第2张图片

3.SDK代码

#include "xparameters.h"
#include 
#include "xuartps.h"	// if PS uart is used
#include "xscutimer.h"  // if PS Timer is used
#include "xaxicdma.h"	// if CDMA is used
#include "xscugic.h" 	// if PS GIC is used
#include "xil_exception.h"	// if interrupt is used
#include "xil_cache.h"
#include "xil_printf.h"
#include "xil_types.h"



#define RESET_LOOP_COUNT	10	// Number of times to check reset is done
#define LENGTH 32768 // source and destination buffers lengths in number of bytes
#define PROCESSOR_BRAM_MEMORY 0x80000000 // BRAM Port A mapped through 1st BRAM Controller accessed by CPU
#define CDMA_BRAM_MEMORY0 0xC0000000 // BRAM Port B mapped through 2nd BRAM Controller accessed by CDMA
#define CDMA_BRAM_MEMORY1 0xC0002000
#define CDMA_BRAM_MEMORY2 0xC0004000
#define CDMA_BRAM_MEMORY3 0xC0006000
#define DDR_MEMORY 0x01000000
#define TIMER_DEVICE_ID	XPAR_SCUTIMER_DEVICE_ID
#define TIMER_LOAD_VALUE 0xFFFFFFFF
#define INTC_DEVICE_INT_ID XPAR_SCUGIC_SINGLE_DEVICE_ID

volatile static int Done = 0;	/* Dma transfer is done */
volatile static int Error = 0;	/* Dma Bus Error occurs */

XUartPs Uart_PS;		/* Instance of the UART Device */
XScuTimer Timer;		/* Cortex A9 SCU Private Timer Instance */
XScuGic Gic;			/* PS GIC */

int getNumber (){

	uint8_t byte;
	uint8_t uartBuffer[16];
	int validNumber;
	int digitIndex;
	int digit, number, sign;
	int c;

	while(1){
		byte = 0x00;
		digit = 0;
		digitIndex = 0;
		number = 0;
		validNumber = TRUE;

		//get bytes from uart until RETURN is entered
		while(byte != 0x0d){
			while (!XUartPs_IsReceiveData(STDIN_BASEADDRESS));
			byte = XUartPs_ReadReg(STDIN_BASEADDRESS,
								    XUARTPS_FIFO_OFFSET);
			uartBuffer[digitIndex] = byte;
			XUartPs_Send(&Uart_PS, &byte, 1);
			digitIndex++;
		}

		//calculate number from string of digits

		for(c = 0; c < (digitIndex - 1); c++){
			if(c == 0){
				//check if first byte is a "-"
				if(uartBuffer[c] == 0x2D){
					sign = -1;
					digit = 0;
				}
				//check if first byte is a digit
				else if((uartBuffer[c] >> 4) == 0x03){
					sign = 1;
					digit = (uartBuffer[c] & 0x0F);
				}
				else
					validNumber = FALSE;
			}
			else{
				//check byte is a digit
				if((uartBuffer[c] >> 4) == 0x03){
					digit = (uartBuffer[c] & 0x0F);
				}
				else
					validNumber = FALSE;
			}
			number = (number * 10) + digit;
		}
		number *= sign;
		if(validNumber == TRUE){
			print("\r\n");
			return number*4; //number of bytes
		}
		print("This is not a valid number.\n\r");
	}
}

static void Example_CallBack(void *CallBackRef, u32 IrqMask, int *IgnorePtr)
{

	if (IrqMask & XAXICDMA_XR_IRQ_ERROR_MASK) {
		Error = 1;
	}

	if (IrqMask & XAXICDMA_XR_IRQ_IOC_MASK) {
		Done = 1;
	}

}

//Connect dma to Generic Interrupt Controller
int SetupIntrSystem(XScuGic *GicPtr, XAxiCdma  *DmaPtr)
{
	int Status;

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

	// Connect a device driver handler that will be called when an interrupt
	// for the device occurs, the device driver handler performs the specific
	// interrupt processing for the device

	Status = XScuGic_Connect(GicPtr,
			XPAR_FABRIC_AXI_CDMA_0_CDMA_INTROUT_INTR,      //interrupt responding to real physical CDMA//
				 (Xil_InterruptHandler)XAxiCdma_IntrHandler,
				 (void *)DmaPtr);
	if (Status != XST_SUCCESS)
		return XST_FAILURE;

	// Enable the interrupt for the device
	XScuGic_Enable(GicPtr, XPAR_FABRIC_AXI_CDMA_0_CDMA_INTROUT_INTR);

	return XST_SUCCESS;
}

int main (void) {

	uint8_t select;
	int i, CDMA_Status;
    int numofbytes;
    u8 * source = DDR_MEMORY, * destination, *destination1 = DDR_MEMORY+32768*4;
    int32_t software_cycles, interrupt_cycles, polled_cycles;
    int test_done = 0;

	// UART related definitions
    int Status;
	XUartPs_Config *Config;

	// PS Timer related definitions
	volatile u32 CntValue1, CntValue2;
	XScuTimer_Config *ConfigPtr;
	XScuTimer *TimerInstancePtr = &Timer;

    // CDMA related definitions
	XAxiCdma xcdma;
    XAxiCdma_Config * CdmaCfgPtr;

	// PS Interrupt related definitions
	XScuGic_Config *GicConfig;

	// Initialize UART
	// Look up the configuration in the config table, then initialize it.
	Config = XUartPs_LookupConfig(XPAR_PS7_UART_0_DEVICE_ID);
	if (NULL == Config) {
		return XST_FAILURE;
	}

	Status = XUartPs_CfgInitialize(&Uart_PS, Config, Config->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	// Initialize timer counter
	ConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);

	Status = XScuTimer_CfgInitialize(TimerInstancePtr, ConfigPtr,
				 ConfigPtr->BaseAddr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	// Initialize GIC
	GicConfig = XScuGic_LookupConfig(INTC_DEVICE_INT_ID);
	if (NULL == GicConfig) {
		xil_printf("XScuGic_LookupConfig(%d) failed\r\n",
				INTC_DEVICE_INT_ID);
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(&Gic, GicConfig,
				       GicConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		xil_printf("XScuGic_CfgInitialize failed\r\n");
		return XST_FAILURE;
	}

	// Disable DCache
	Xil_DCacheDisable();

	// Set options for timer/counter 0
	// Load the timer counter register.
	XScuTimer_LoadTimer(TimerInstancePtr, TIMER_LOAD_VALUE);


	// Setup DMA Controller
    CdmaCfgPtr = XAxiCdma_LookupConfig(XPAR_AXI_CDMA_0_DEVICE_ID);
   	if (!CdmaCfgPtr) {
   		return XST_FAILURE;
   	}

   	Status = XAxiCdma_CfgInitialize(&xcdma , CdmaCfgPtr, CdmaCfgPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
		xil_printf("Status=%x\r\n",Status);
	}

	print("Central DMA Initialized\r\n");

	print("Setting up interrupt system\r\n");
	Status = SetupIntrSystem(&Gic, &xcdma);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	Xil_ExceptionEnable();

	print("Enter number of words you want to transfer between 1 and 8192\r\n");
	numofbytes =0;
    do{
    	numofbytes = getNumber();
    }while(numofbytes == 0);

    if(numofbytes > 32768)
    	numofbytes = 32768;

		// Initialize src memory
		for (i=0; i

VIVADO 4.CDMA的使用_第3张图片

4.Linux驱动测试

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define CDMA_BASE_ADDRESS     0x7E200000
#define GPIO_DATA_OFFSET     0
#define GPIO_DIRECTION_OFFSET     4
#define PL_BRAM_SRC_ADDRESS  0xC0000000
#define DDR_BASE_ADDRESS     0x10000000

#define DDR_BASE_READ_ADDRESS    0x10000000
#define DDR_BASE_WRITE_ADDRESS    0x10002000

#define XGPIO_CHAN_OFFSET  8

#define XAXICDMA_CR_OFFSET      0x00000000  /**< Control register */
#define XAXICDMA_SR_OFFSET      0x00000004  /**< Status register */
#define XAXICDMA_CDESC_OFFSET   0x00000008  /**< Current descriptor pointer */
#define XAXICDMA_TDESC_OFFSET   0x00000010  /**< Tail descriptor pointer */
#define XAXICDMA_SRCADDR_OFFSET 0x00000018  /**< Source address register */
#define XAXICDMA_DSTADDR_OFFSET 0x00000020  /**< Destination address register */
#define XAXICDMA_BTT_OFFSET     0x00000028  /**< Bytes to transfer */


/** @name Bitmasks of XAXICDMA_CR_OFFSET register
 * @{
 */
#define XAXICDMA_CR_RESET_MASK  0x00000004 /**< Reset DMA engine */
#define XAXICDMA_CR_SGMODE_MASK 0x00000008 /**< Scatter gather mode */

/** @name Bitmask for interrupts
 * These masks are shared by XAXICDMA_CR_OFFSET register and
 * XAXICDMA_SR_OFFSET register
 * @{
 */
#define XAXICDMA_XR_IRQ_IOC_MASK    0x00001000 /**< Completion interrupt */
#define XAXICDMA_XR_IRQ_DELAY_MASK  0x00002000 /**< Delay interrupt */
#define XAXICDMA_XR_IRQ_ERROR_MASK  0x00004000 /**< Error interrupt */
#define XAXICDMA_XR_IRQ_ALL_MASK    0x00007000 /**< All interrupts */
#define XAXICDMA_XR_IRQ_SIMPLE_ALL_MASK 0x00005000 /**< All interrupts for
                                                        simple only mode */
/*@}*/

/** @name Bitmasks of XAXICDMA_SR_OFFSET register
 * This register reports status of a DMA channel, including
 * idle state, errors, and interrupts
 * @{
 */
#define XAXICDMA_SR_IDLE_MASK         0x00000002  /**< DMA channel idle */
#define XAXICDMA_SR_SGINCLD_MASK      0x00000008  /**< Hybrid build */
#define XAXICDMA_SR_ERR_INTERNAL_MASK 0x00000010  /**< Datamover internal err */
#define XAXICDMA_SR_ERR_SLAVE_MASK    0x00000020  /**< Datamover slave err */
#define XAXICDMA_SR_ERR_DECODE_MASK   0x00000040  /**< Datamover decode err */
#define XAXICDMA_SR_ERR_SG_INT_MASK   0x00000100  /**< SG internal err */
#define XAXICDMA_SR_ERR_SG_SLV_MASK   0x00000200  /**< SG slave err */
#define XAXICDMA_SR_ERR_SG_DEC_MASK   0x00000400  /**< SG decode err */
#define XAXICDMA_SR_ERR_ALL_MASK      0x00000770  /**< All errors */
/*@}*/

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

#define DDR_MAP_SIZE 0x00100000
#define DDR_MAP_MASK (DDR_MAP_SIZE - 1)

#define DDR_WRITE_OFFSET 0x10000000

#define BUFFER_BYTESIZE     32768   // Length of the buffers for DMA transfer
    long times = 0; // us
    double dbTotalTimes = 0.0;  // s
    long nReadTotal = 0;
    struct timeval timeStart, timeEnd;
int main()
{
    int memfd;
    int i,k;
    void *mapped_base, *mapped_dev_base;
    off_t dev_base = CDMA_BASE_ADDRESS;

    int memfd_1;
        void *mapped_base_1, *mapped_dev_base_1;
        off_t dev_base_1 = DDR_BASE_READ_ADDRESS;

    int memfd_2;
    void *mapped_base_2, *mapped_dev_base_2;
    off_t dev_base_2 = DDR_BASE_WRITE_ADDRESS;

    unsigned int TimeOut =5;
    unsigned int ResetMask;
    unsigned int RegValue;
    unsigned int DestArray[BUFFER_BYTESIZE ];
    unsigned int Index;

    for (Index = 0; Index < (BUFFER_BYTESIZE/2); Index++)
    {

            DestArray[Index] = 0x12345678+Index;
    }

    memfd_1 = open("/dev/mem", O_RDWR | O_SYNC);
   if (memfd_1 == -1)
   {
	   printf("Can't open /dev/mem.\n");
	   exit(0);
   }
   printf("/dev/mem opened.\n");
   // Map one page of memory into user space such that the device is in that page, but it may not
   // be at the start of the page.
   mapped_base_1 = mmap(0, DDR_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, memfd_1, dev_base_1 & ~DDR_MAP_MASK);
   if (mapped_base_1 == (void *) -1)
   {
	   printf("Can't map the memory to user space.\n");
	   exit(0);
   }
   printf("Memory mapped at address %p.\n", mapped_base_1);
	// get the address of the device in user space which will be an offset from the base
	// that was mapped as memory is mapped at the start of a page
	mapped_dev_base_1 = mapped_base_1 + (dev_base_1 & DDR_MAP_MASK);

	/*======================================================================================
	STEP 9 : Copy the Data from DDR Memory location 0x20000000 to Destination Buffer
	========================================================================================*/
	memcpy(mapped_dev_base_1, DestArray, (BUFFER_BYTESIZE ));
	/*======================================================================================
	STEP 10 : Un-map the Kernel memory from the User layer.
	========================================================================================*/
	if (munmap(mapped_base_1, DDR_MAP_SIZE) == -1)
	{
		printf("Can't unmap memory from user space.\n");
		exit(0);
	}

   close(memfd_1);

   for (Index = 0; Index < (BUFFER_BYTESIZE/2); Index++)
      {

              DestArray[Index] = 0;
      }

/////////////////////////////////////////////////////////////////////////////////////////////////
    memfd = open("/dev/mem", O_RDWR | O_SYNC);
    if (memfd == -1)
    {
        printf("Can't open /dev/mem.\n");
        exit(0);
    }
    printf("/dev/mem opened.\n");

    // Map one page of memory into user space such that the device is in that page, but it may not
    // be at the start of the page.
    mapped_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, memfd, dev_base & ~MAP_MASK);
    if (mapped_base == (void *) -1)
    {
          printf("Can't map the memory to user space.\n");
          exit(0);
      }

    // get the address of the device in user space which will be an offset from the base
    // that was mapped as memory is mapped at the start of a page
    mapped_dev_base = mapped_base + (dev_base & MAP_MASK);
    //Reset CDMA
      do{
              ResetMask = (unsigned long )XAXICDMA_CR_RESET_MASK;
            *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_CR_OFFSET)) = (unsigned long)ResetMask;
            /* If the reset bit is still high, then reset is not done   */
            ResetMask = *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_CR_OFFSET));
            if(!(ResetMask & XAXICDMA_CR_RESET_MASK))
            {
                break;
            }
            TimeOut -= 1;
      }while (TimeOut);
        //enable Interrupt
      RegValue = *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_CR_OFFSET));
      RegValue = (unsigned long)(RegValue | XAXICDMA_XR_IRQ_ALL_MASK );
      *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_CR_OFFSET)) = (unsigned long)RegValue;
      // Checking for the Bus Idle
      RegValue = *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_SR_OFFSET));
      if(!(RegValue & XAXICDMA_SR_IDLE_MASK))
      {
          printf("BUS IS BUSY Error Condition \n\r");
          return 1;
      }
      // Check the DMA Mode and switch it to simple mode
      RegValue = *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_CR_OFFSET));
      if((RegValue & XAXICDMA_CR_SGMODE_MASK))
      {
          RegValue = (unsigned long)(RegValue & (~XAXICDMA_CR_SGMODE_MASK));
          printf("Reading \n \r");
          *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_CR_OFFSET)) = (unsigned long)RegValue ;

      }
      //Set the Source Address
      *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_SRCADDR_OFFSET)) = (unsigned long)DDR_BASE_READ_ADDRESS;
      //Set the Destination Address
      *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_DSTADDR_OFFSET)) = (unsigned long)PL_BRAM_SRC_ADDRESS;
      RegValue = (unsigned long)(BUFFER_BYTESIZE);
      // write Byte Numbers to Transfer
      *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_BTT_OFFSET)) = (unsigned long)RegValue;
        /*======================================================================================
        STEP 6 : Wait for the DMA transfer Status
        ========================================================================================*/
gettimeofday(&timeStart, NULL);
      do
      {
              RegValue = *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_SR_OFFSET));
      }while(!(RegValue & XAXICDMA_XR_IRQ_ALL_MASK));

      //Set the Source Address
      *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_SRCADDR_OFFSET)) = (unsigned long)PL_BRAM_SRC_ADDRESS;
      //Set the Destination Address
      *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_DSTADDR_OFFSET)) = (unsigned long)DDR_BASE_WRITE_ADDRESS;
      RegValue = (unsigned long)(BUFFER_BYTESIZE);
      // write Byte Numbers to Transfer
      *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_BTT_OFFSET)) = (unsigned long)RegValue;
        /*======================================================================================
        STEP 6 : Wait for the DMA transfer Status
        ========================================================================================*/
      do
      {
    	  RegValue = *((volatile unsigned long *) (mapped_dev_base + XAXICDMA_SR_OFFSET));
      }while(!(RegValue & XAXICDMA_XR_IRQ_ALL_MASK));
gettimeofday(&timeEnd, NULL);
            times  = 1000000*(timeEnd.tv_sec - timeStart.tv_sec) + timeEnd.tv_usec - timeStart.tv_usec;

if(BUFFER_BYTESIZE == 32768)
printf("Read  32 Lines * 512 Dots :\n\r");
else
printf("Read 128 Lines * 512 Dots :\n\r");
printf("Xilinx AXI-CDMA Read %d Byte = %d us \n",   BUFFER_BYTESIZE,times);



      if((RegValue & XAXICDMA_XR_IRQ_IOC_MASK))
      {
          printf("Transfer Completed \n\r ");
      }
      if((RegValue & XAXICDMA_XR_IRQ_DELAY_MASK))
      {
        printf("IRQ Delay Interrupt\n\r ");
      }
      if((RegValue & XAXICDMA_XR_IRQ_ERROR_MASK))
      {
        printf("Transfer Error Interrupt\n\r ");
      }

      /*======================================================================================
       STEP 7 : Un-map the AXI CDMA memory from the User layer.
      ========================================================================================*/
      if (munmap(mapped_base, MAP_SIZE) == -1)
      {
            printf("Can't unmap memory from user space.\n");
            exit(0);
      }

      close(memfd);

   /*======================================================================================
    STEP 8 : Map the kernel memory location starting from 0x30000000 to the User layer
    ========================================================================================*/
      memfd_2 = open("/dev/mem", O_RDWR | O_SYNC);
       if (memfd_2 == -1)
       {
           printf("Can't open /dev/mem.\n");
           exit(0);
       }
       printf("/dev/mem opened.\n");
       // Map one page of memory into user space such that the device is in that page, but it may not
       // be at the start of the page.
       mapped_base_2 = mmap(0, DDR_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, memfd_2, dev_base_2 & ~DDR_MAP_MASK);
       if (mapped_base_2 == (void *) -1)
       {
           printf("Can't map the memory to user space.\n");
           exit(0);
       }
       printf("Memory mapped at address %p.\n", mapped_base_2);
        // get the address of the device in user space which will be an offset from the base
        // that was mapped as memory is mapped at the start of a page
        mapped_dev_base_2 = mapped_base_2 + (dev_base_2 & DDR_MAP_MASK);

        /*======================================================================================
        STEP 9 : Copy the Data from DDR Memory location 0x20000000 to Destination Buffer
        ========================================================================================*/
        memcpy(DestArray, mapped_dev_base_2, (BUFFER_BYTESIZE ));
        /*======================================================================================
        STEP 10 : Un-map the Kernel memory from the User layer.
        ========================================================================================*/
        if (munmap(mapped_base_2, DDR_MAP_SIZE) == -1)
        {
            printf("Can't unmap memory from user space.\n");
            exit(0);
        }

       close(memfd_2);


       /*======================================================================================
        STEP 11 : Compare Source Buffer with Destination Buffer.
       ========================================================================================*/
    for(i=0; i<4; i++)
    {
        k = DestArray[i];
        printf("The AXI-CDMA read from address = %4d, the read value = 0x0%7x, MSB value=%5d, LSB value=%5d-----\n\r",i,k,k >> 16,k & 0x0000FFFF);
    }
    for(i=8188; i<8192; i++)
    {
        k = DestArray[i];
        printf("The AXI-CDMA read from address = %4d, the read value = 0x%8x, MSB value=%5d, LSB value=%5d-----\n\r",i,k,k >> 16,k & 0x0000FFFF);
    }


    return 0;
}

测试效果

VIVADO 4.CDMA的使用_第4张图片

你可能感兴趣的:(cdma,zynq,vivado,sdk)