This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How to share an AM335x 600Kbytes EDMA kernel buffer with user application?

Other Parts Discussed in Thread: AM3358

I finally managed to make edma_test.c work in my BeagleBone Black ( AM3358 ).

Using 600Kbytes buffers ( VGA frame images 640x480x2 bytes ), I had to change coherent_pool to 4M in uEnv.txt ( coherent_poll = 4M ).

But, now, I have to send one buffer to application in user space area.

Which is the recommended method to share this buffer with user application with minimal overhead?

Any tutorial example ( kernel part and application part ) available?

Thanks,

Sergio

  • Hi Pavel

    Yes, I used copy_to_user API, and apparently I could copy the kernel buffer into user space, but, EDMA it is not correctly transfering the FIFO content, as can be seeing in attached dump. After 0x78 0x78 bytes, all the rest is 0. These 2 0x78 bytes are the bytes I sent to my FPGA in a write operation through GPMC. This write works, as the FPGA presets the downcounter ( I can see the pulse from this downcounter in oscilloscope in correct time ).

    Perhaps I am doing something wrong in the READ routine ( based in edma_test.c ):

    static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset)
    {
       int error_count = 0;
     
       	unsigned int numenabled = 0;
       	unsigned int BRCnt = 0;
       	int srcbidx = 0;
    	int desbidx = 0;
    	int srccidx = 0;
    	int descidx = 0;
    	int result = 0;
    	unsigned int dma_ch = 0;
    	int event_queue = 0;
    	struct edmacc_param param_set;
    	int i,x,y;
    	
    													// void __iomem	*reg_base_virt;
    	reg_base_virt = ioremap(reg_base_phys, len);	// unsigned int	reg_base_phys = 0x18000000;
    	if (reg_base_virt == NULL) 
    	{
    		printk(KERN_ALERT "ioremap of registers region failed\n");
    		release_mem_region(reg_base_phys, len);
    		return -ENOMEM;
    	}
    
    	// COUNTER = 0x7878
    	iowrite16( COUNTER , reg_base_virt );	// preset field line downcounter in FPGA
    											// to reset video frame FIFO output pointer
    											// FPGA is connected to GPMC extern side
    
    
    	/* Set B count reload as B count. */
    	BRCnt = bcnt;
    
    	/* Setting up the SRC/DES Index */
    	srcbidx = acnt;
    	desbidx = acnt;
    
    	/* A Sync Transfer Mode */
    	srccidx = acnt;
    	descidx = acnt;
    
    	result = edma_alloc_channel (EDMA_CHANNEL_ANY, callback1, NULL, event_queue);
    
    	if (result < 0) {
    		printk (KERN_ALERT "edma3: edma_alloc_channel failed for dma_ch, error:%d\n", result);
    		return result;
    	}   
    	
    	printk( "EDMA3 dma_ch = %d\n", result );
    	
    	dmaphyssrc1 = 0x18000000;	// cs1 of AM3358 GPMC
       
    	dma_ch = result;
    	edma_set_src (dma_ch, (unsigned long)(dmaphyssrc1), INCR, W16BIT);	// from GPMC interface
    	edma_set_dest (dma_ch, (unsigned long)(dmaphysdest1), INCR, W8BIT);	// to kernel buffer
    	edma_set_src_index (dma_ch, srcbidx, srccidx);
    	edma_set_dest_index (dma_ch, desbidx, descidx);
    	/* A Sync Transfer Mode */
    	edma_set_transfer_params (dma_ch, acnt, bcnt, ccnt, BRCnt, ASYNC);
    
    	/* Enable the Interrupts on Channel 1 */
    	edma_read_slot (dma_ch, &param_set);
    	param_set.opt |= (1 << ITCINTEN_SHIFT);
    	param_set.opt |= (1 << TCINTEN_SHIFT);
    	param_set.opt |= EDMA_TCC(EDMA_CHAN_SLOT(dma_ch));
    	edma_write_slot (dma_ch, &param_set);
    
    	numenabled = bcnt * ccnt;
    
    	for (i = 0; i < numenabled; i++) 
    	{
    		irqraised1 = 0;
    
    		/*
    		 * Now enable the transfer as many times as calculated above.
    		 */
    		result = edma_start(dma_ch);
    		if (result != 0) {
    			printk (KERN_ALERT "edma3: start_dma failed \n");
    			break;
    		}
    
    		/* Wait for the Completion ISR. */
    		while (irqraised1 == 0u);
    
    		/* Check the status of the completed transfer */
    		if (irqraised1 < 0) {
    			/* Some error occured, break from the FOR loop. */
    			printk (KERN_ALERT "edma3: Event Miss Occured!!!\n");
    			break;
    		}
    	}
       
      	edma_stop(dma_ch);
    	edma_free_channel(dma_ch); 
    
    // **** 2048 bytes dump to see dmabufdest1 *****	
    y = 0;
    printk("\n");
    for( x = 0 ; x < 2048 ; x++ )
    {
    	printk("%02X ",dmabufdest1[x] );
    	if( ++y > 32 )
    	{
    		printk("\n");
    		y = 0;
    	}
    }
    //**********************************************	
    	
    	size_of_message = MESSAGE_LEN;	// #define MESSAGE_LEN	640*480*2
    	
       // copy_to_user has the format ( * to, *from, size) and returns 0 on success
       error_count = copy_to_user(buffer, dmabufdest1, size_of_message);
       
    
       if (error_count==0){            // if true then have success
          printk(KERN_ALERT "Sent %d characters to the user\n", size_of_message);
          return (size_of_message=0);  // clear the position to the start and return 0
       }
       else {
          printk(KERN_ALERT "Failed to send %d characters to the user\n", error_count);
          return -EFAULT;              // Failed -- return a bad address message (i.e. -14)
       }
    }
    

    5126.dump_15082016_1018.txt

    Any help would be greatly appreciated.

    Sergio

  • Hi Pavel

    I have noted that, just after Power-On, the EDMA transfer something to buffer. After that, along the two initial 0x78 bytes, only zeros. If I do a power cycle ( power-off / power-on ), the EDMA works again, but one full cycle only ( 600Kbytes as mentioned before ).

    May be I am forgetting to setup something in EDMA just after a full transfer.

    Sergio

  • Sergio,

    From what I understand you configure your FPGA to act like NOR flash and transfer data from FPGA to AM335x GPMC memory space, start address 0x18000000. How much data you transfer there (at start address 0x18000000)? Then you transfer the data from GPMC memory space (start addr 0x18000000) to kernel buffer (is this buffer located at DDR3 memory?) with EDMA. Do you use Manual trigger or Event trigger (GPMCEVT 52)?

    I would suggest to check AM335x EDMA TRM, sections 11.3.19 EDMA Transfer Examples, 11.5.1 Debug Checklist, 11.5.2 Miscellaneous Programming/Debug Tips, 11.5.3 Setting Up a Transfer

    Regards,
    Pavel

  • Hi Pavel

    Follows answers:


    -From what I understand you configure your FPGA to act like NOR flash and transfer data from FPGA to AM335x GPMC memory space, start address 0x18000000.

    A: The GPMC is configured to access a SRAM ( Static RAM ), without muxing address and data, starting at 0x18000000 ( CS1 range ). My FPGA connects a video frame FIFO to GPMC and does'nt need address bus, only data bus, as it is a sequential memory. I use a combination of READ and CS1 to generate clock to FIFO. In all the frame transfer process, I only do a single WRITE to FPGA through GPMC, only do generate a RESET to output pointer of FIFO. All the rest is a sequential READ process. GPMC is programmed to transfer 16 bits wide data.


    - How much data you transfer there (at start address 0x18000000)?

    A: I transfer 600Kbytes ( 640 x 480 x 2 = VGA video frame ).


    - Then you transfer the data from GPMC memory space (start addr 0x18000000) to kernel buffer (is this buffer located at DDR3 memory?) with EDMA.

    A: Yes, the transfer is done to kernel buffer in DDR3 memory, using EDMA.


    - Do you use Manual trigger or Event trigger (GPMCEVT 52)?

    A: I intend to use MANUAL TRIGGER ( by SOFTWARE ). I am using edma_test.c as reference, and all commands sent to EDMA is copied from edma_test.c, that uses manual trigger.


    Using A Sync Transfer Mode:

    acnt = 512
    bcnt = 120
    ccnt = 10

    acnt * bcnt * ccnt = 614400 bytes = 600Kbytes


    As I said in previous post, I noted that just after Power-On, the EDMA works once normally ( do a full transfer ). After that, it transfer only ZEROS. If I do a power cycle, it works once again. Then, only zeroes again. Studying carefully the edma_test.c example, I don't see any special command to send to EDMA after a full transfer. For a new transfer, I reexecute the READ routine, as shown in previous post.

    Sergio
  • Hi Pavel

    The issue of EDMA transfering zeros was due use of malloc at user application side to reserve memory to buffer. If I use ordinary unsigned char buffer[BUFFER_LENGHT] it works. I don't know why, but, it works.

    I did several tests and all worked.

    Sergio