CDMA上同时连接了四个BRAM。Bram设置为BRAM Controller模式,真双口BRAM,宽度64,深度1024,这样分配地址8k即可。
#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
#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;
}
测试效果