Learn ZYNC (2)

AXI HP接口的DMA+GIC编程(参照博客

参照文档:UG873,博客文档

参考设计代码文件:ug873源码

我的Vivado+SDK工程文件打包(60+M)

我的DMA驱动程序(已完成)

Vivado 接线图:

image

地址分配:

image

image

AXI-CDMA IP核,是由PL完成的将数据从内存的一个位置搬移到另一个位置,无需CPU来插手。

AXI CDMA 从机接口连接到PS 通用主机接口M_AXI_GP1.用于PS 来配置AXI 寄存器用于数据传输和状态检测。
AXI CDMA 主机接口连接到PS 高性能从机接口S_AXI_HP0.用于CDMA 模块读取DDR 系统内存源缓冲区数据。
AXI CDMA 主机接口连接到PS 高性能从机接口S_AXI_HP2.用于CDMA 模块将数据写回DDR 系统内存目的缓冲区。
AXI CDMA 中断从PL 连接到PS 全局中断控制器(GIC)。当数据传输完成或传输时有错误发生,则产生中断。

image

image

image

standalone代码:

#include <stdio.h>
//#include "platform.h"
#include "xaxicdma.h"
#include "xdebug.h"
#include "xil_exception.h"
#include "xil_cache.h"
#include "xparameters.h"
#include "xscugic.h"
//包含头文件,不必多言
#define NUMBER_OF_TRANSFERS 2     /* 做两次传输 */
#define DMA_CTRL_DEVICE_ID     XPAR_AXICDMA_0_DEVICE_ID     //DMA控制设备ID号=
#define INTC_DEVICE_ID         XPAR_SCUGIC_SINGLE_DEVICE_ID     //GIC控制设备ID号=
#define DMA_CTRL_IRPT_INTR       XPAR_FABRIC_AXI_CDMA_0_CDMA_INTROUT_INTR      //中断号
volatile static int Done = 0;   /* Dma transfer is done */
volatile static int Error = 0;   /* Dma Bus Error occurs */
static u32 SourceAddr  = 0x10000000;    // XPAR_PS7_DDR_0_S_AXI_HP0_BASEADDR

static u32 DestAddr      = 0x18000000;    // XPAR_PS7_DDR_0_S_AXI_HP2_BASEADDR

static XAxiCdma AxiCdmaInstance;     /* XAxiCdma  控制对象*/
static XScuGic IntcController;      /* Interrupt Controller  控制对象*/


static int Array_3[32][16];     //阵列
static int Array_4[32][16];
static int Array_1[32][16];
static int Array_2[32][16];
int const input[16] = {0xb504f33, 0xabeb4a0, 0xa267994, 0x987fbfc, 0x8e39d9c, 0x839c3cc, 0x78ad74c, 0x6d743f4, 0x61f78a8, 0x563e6a8, 0x4a5018c, 0x3e33f2c, 0x31f1704, 0x259020c, 0x1917a64, 0xc8fb2c};
/* Length of the buffers for DMA transfer */
static u32 BUFFER_BYTESIZE   = (XPAR_AXI_CDMA_0_M_AXI_DATA_WIDTH * XPAR_AXI_CDMA_0_M_AXI_MAX_BURST_LEN);      //大小为64*256/8=2KB,起始就是我们在XPS中设置好的
static int CDMATransfer(XAxiCdma *InstancePtr, int Length, int Retries);//执行传输
static void DisableIntrSystem(XScuGic *IntcInstancePtr , u32 IntrId)//禁止中断
{
              XScuGic_Disable(IntcInstancePtr ,IntrId );
              XScuGic_Disconnect(IntcInstancePtr ,IntrId );
}
//Multiply and Shift
int MUL_SHIFT_30(int x, int y)//实现x*y,但又怕溢出,所以右移30位,除以2^30~1e9
{
 return ((int) (((long long) (x) * (y)) >> 30));
}
void MULT_SHIFT_LOOP(int Value )//生成源数据的函数
{
   int i, j;
   for (i = 0; i < 32; i++) {
      for (j = 0; j < 16; j++) {
             Array_3[i][j] = (int)((MUL_SHIFT_30(input[j],Array_1[j][i])) + Value);
             Array_4[i][j] = (int)((MUL_SHIFT_30(input[j],Array_2[j][i])) + Value);
      }
   }
}

void TestPattern_Initialization(void)//生成原始数据
{
        int i, j;
          for (i = 0; i < 32; i++)
          {
             for (j = 0; j < 16; j++)
             {
                    Array_1[i][j] = (int ) ((0xA5A5A5A5 >> 1) * i );
                    Array_2[i][j] = (int ) ((0xA5A5A5A5 << 1) * i );
             }
          }
}
//下面是中断服务函数
static void Cdma_CallBack(void *CallBackRef, u32 IrqMask, int *IgnorePtr)
{
       if (IrqMask & XAXICDMA_XR_IRQ_ERROR_MASK) {
              Error = TRUE;
              printf("\r\n--- Transfer Error --- \r\n");//传输出错
       }

       if (IrqMask & XAXICDMA_XR_IRQ_IOC_MASK) {
              printf("\r\n--- Transfer Done --- \r\n");
              Done = TRUE;//传输成功
       }

}
//设置中断系统,初始化中断控制器
static int SetupIntrSystem(XScuGic *IntcInstancePtr, XAxiCdma *InstancePtr,
                     u32 IntrId)

{
       int Status;


       /*
        * Initialize the interrupt controller driver
        */
       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, IntrId, 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, IntrId,
                            (Xil_InterruptHandler)XAxiCdma_IntrHandler,
                            InstancePtr);
       if (Status != XST_SUCCESS) {
              return Status;
       }

       /*
        * Enable the interrupt for the DMA device.
        */
       XScuGic_Enable(IntcInstancePtr, IntrId);




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


       /*
        * Enable interrupts in the Processor.
        */
       Xil_ExceptionEnable();


       return XST_SUCCESS;
}


int XAxiCdma_Interrupt(XScuGic *IntcInstancePtr, XAxiCdma *InstancePtr,
       u16 DeviceId, u32 IntrId)
{
       {
              XAxiCdma_Config *CfgPtr;
              int Status;
              int SubmitTries = 1;             /* Retry to submit */
              int Tries = NUMBER_OF_TRANSFERS;
              int Index;

              /* Initialize the XAxiCdma device.
               */
              CfgPtr = XAxiCdma_LookupConfig(DeviceId);
              if (!CfgPtr) {
                     return XST_FAILURE;
              }

              Status = XAxiCdma_CfgInitialize(InstancePtr, CfgPtr, CfgPtr->BaseAddress);
              if (Status != XST_SUCCESS) {
                     return XST_FAILURE;
              }

              /* Setup the interrupt system
               */
              Status = SetupIntrSystem(IntcInstancePtr, InstancePtr, IntrId);
              if (Status != XST_SUCCESS) {
                     return XST_FAILURE;
              }

              /* Enable all (completion/error/delay) interrupts
               */
              XAxiCdma_IntrEnable(InstancePtr, XAXICDMA_XR_IRQ_ALL_MASK);

              for (Index = 0; Index < Tries; Index++) {
                     Status = CDMATransfer(InstancePtr,
                               BUFFER_BYTESIZE, SubmitTries);

                     if(Status != XST_SUCCESS) {
                            DisableIntrSystem(IntcInstancePtr, IntrId);
                            return XST_FAILURE;
                     }
              }

              /* Test finishes successfully, clean up and return
               */
              DisableIntrSystem(IntcInstancePtr, IntrId);

              return XST_SUCCESS;
       }
}
/*****************************************************************************/
/*
*
* This function does CDMA transfer
*
* @param      InstancePtr is a pointer to the XAxiCdma instance
* @param      Length is the transfer length
* @param      Retries is how many times to retry on submission
*
* @return
*            - XST_SUCCESS if transfer is successful
*            - XST_FAILURE if either the transfer fails or the data has
*             error
*
* @note         None
*
******************************************************************************/
static int CDMATransfer(XAxiCdma *InstancePtr, int Length, int Retries)
{

       int Status;

       Done = 0;
       Error = 0;


       printf("Start Transfer \n\r");
       /* Try to start the DMA transfer
        */
              Done = 0;
              Error = 0;

              /* Flush the SrcBuffer before the DMA transfer, in case the Data Cache
               * is enabled
               */
              Xil_DCacheFlushRange((u32)SourceAddr, Length);

              Status = XAxiCdma_SimpleTransfer(InstancePtr,
                                                                      (u32)(u8 *) (SourceAddr ),
                                                                      (u32)(DestAddr),
                                                                      Length,
                                                                      Cdma_CallBack,
                                                                      (void *)InstancePtr);

              if (Status == XST_FAILURE) {
                     printf("Error in Transfer \n\r");
                     return 1;
              }



              /* Wait until the DMA transfer is done
                      */
                     while (!Done && !Error) {
                            /* Wait */
                     }

                     if (Error) {
                            return XST_FAILURE;
                            return 1;
                     }
              /* Invalidate the DestBuffer before receiving the data, in case the
               * Data Cache is enabled
               */
              Xil_DCacheInvalidateRange((u32)DestAddr, Length);

       return XST_SUCCESS;
}
int main()
{
       int Status;
       u32 *SrcPtr;
       u32 *DestPtr;
       u32 Index;
       int i, j;

    printf("\r\n--- Entering main() --- \r\n");

       /*********************************************************************************
              Step : 1 : Intialization of the SOurce Memory with the Specified test pattern
                            Clear Destination memory
       **********************************************************************************/
    TestPattern_Initialization();

    /* Initialize the source buffer bytes with a pattern and the
            * the destination buffer bytes to zero
     */
    SrcPtr = (u32*)SourceAddr;
    DestPtr = (u32 *)DestAddr;
    for (Index = 0; Index < (BUFFER_BYTESIZE/1024); Index++)
    {
            MULT_SHIFT_LOOP((Index*100));
            for (i = 0; i < 32; i++)
            {
                   for (j = 0; j < 16; j++)
                   {
                          SrcPtr[((i+j))*(Index+1)]            = Array_3[i][j];
                          SrcPtr[((i+j)*(Index+1)) + 1]      = Array_4[i][j];
                          DestPtr[(i+j)*(Index+1)]             = 0;
                          DestPtr[((i+j)*(Index+1)) + 1] = 0;
                   }

            }

    }
       /*********************************************************************************
              Step : 2 : AXI CDMA Intialization
                               Association of the CDMA ISR with the Interrupt
                               Enable the CDMA Interrupt
                            Provide Source and destination location to CDMA
                            Specified Number of byte to be transfer to CDMA register
                            Start the CDMA
                            Wait for the Interrupt and return the status
       **********************************************************************************/

    Status = XAxiCdma_Interrupt( &IntcController,
                                                     &AxiCdmaInstance,
                                                     DMA_CTRL_DEVICE_ID,
                                                      DMA_CTRL_IRPT_INTR
                                                      );

    if (Status != XST_SUCCESS) {

                  printf("XAxiCdma_Interrupt: Failed\r\n");
                  return XST_FAILURE;
           }

           xil_printf("XAxiCdma_Interrupt: Passed\r\n");


    /*********************************************************************************
              Step : 3 : Compare Source memory with Destination memory
                               Return the Status
       **********************************************************************************/
           for (Index = 0; Index < (BUFFER_BYTESIZE/4); Index++)
           {
                  if ( DestPtr[Index] != SrcPtr[Index])
                  {
                         printf("Error in Comparison : Index : %x \n\r", Index);
                         return XST_FAILURE;
                  }
           }

           printf("DMA Transfer is Successful \n\r");
           return XST_SUCCESS;


    return 0;
}

Linux 驱动程序代码参考:xilinx_axicdma.c

Linux DeviceTree参考:axi-cdma.txt

Linux app程序代码(已完成,2014.6.5更新):

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#define CDMA_BASE_ADDRESS     0x80200000
#define GPIO_DATA_OFFSET     0
#define GPIO_DIRECTION_OFFSET     4

//此处要修改为我们的总线地址****************************
#define DDR_BASE_ADDRESS     0x10000000

#define DDR_BASE_WRITE_ADDRESS    0x18000000
#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 0x10000000
#define DDR_MAP_MASK (DDR_MAP_SIZE - 1)

#define DDR_WRITE_OFFSET 0x10000000



#define BUFFER_BYTESIZE		262144	// Length of the buffers for DMA transfer

int main()
{
	int memfd;
    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_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 SrcArray[BUFFER_BYTESIZE ];
    unsigned int DestArray[BUFFER_BYTESIZE ];
    unsigned int Index;
   
 /*STEP 1 : Initialize the source buffer bytes with a pattern  and clear the Destination
     	 	  location
 	 =====================================*/
  	for (Index = 0; Index < (BUFFER_BYTESIZE/2); Index++)
  	{
  			SrcArray[Index] = 0x5A5A5A5A/*Index & 0xFF*/;
  			DestArray[Index] = 0;
  	}
  	
/*STEP 2 : Map the kernel memory location starting from 0x10000000 to the User layer
  	=======================================*/
  	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 3 : Copy the Data to the DDR Memory at location 0x10000000
     ========================================*/
    memcpy(mapped_dev_base_1, SrcArray, (BUFFER_BYTESIZE));

    /* STEP 4 : 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);
  	
/*==STEP 5 : Map the AXI CDMA Register memory to the User layer
  			Do the Register Setting for DMA transfer
=================================================*/
    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_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 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));

      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 0x18000000 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 0x10000000 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 (Index = 0; Index < (BUFFER_BYTESIZE/4); Index++)
       {
    	   if (SrcArray[Index] != DestArray[Index])
    	   {
    		   printf("Error in the Data comparison \n \r");
    		   return 1;
    	   }
       }
       printf("DATA Transfer is Successfull \n\r");

    return 0;
}

linux下运行成功图:

image

转载于:https://www.cnblogs.com/shenerguang/p/3791479.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值