Linux 3.8, am335x, How to set up continuous DMA transfers

1,825 views
Skip to first unread message

l...@snupi.com

unread,
Dec 10, 2013, 3:28:15 PM12/10/13
to beagl...@googlegroups.com, Don Smyth

Reading the documentation on the EDMA peripheral for this part (am3352), it is clearly capable of doing continuous/chaining DMA transfers via the link-address mechanism.  The only method I see that interacts with this mechanism is the "CYCLIC" type transfer, which appears to set the address for the next transfer to the address of the current transfer.

I'd like to set up the DMA for chaining, with four buffers--two for transmit and two for receive, with the following behavior.

T_BUFF_1--currently in use

T_BUFF_2-address is loaded into link register of current transmit operation so that it is automatically utilized when the transfer from T_BUFF_1 completes.

R_BUFF_1-currently in use

R_BUFF_2-address is loaded into link register of current receive operation so that it is automatically utilized when the transfer into R_BUFF_1 completes.

Callback routines associated with these would just load the link-address associated with the new transfer with the address of the buffer not currently in use (the one having just finished).

So the transfers would look like T_BUFF_1 --> T_BUFF_2 --> T_BUFF_1 --> T_BUFF_2 -->.... and R_BUFF_1 --> R_BUFF_2 --> R_BUFF_1 --> R_BUFF_2 -->...

I don't see any full implementations of this in any example/sample code, and like I said, the "CYCLIC" transfers just seem to overwrite the same buffer, rather than update to a new buffer upon completion.

I am writing a replacement for the Linux 3.8 SPI driver ( "spi-omap2-mcspi.c" ) that does continuous transfers rather than the discreet message-queue method, in order to avoid the latency between handling of messages.  

John Syne

unread,
Dec 10, 2013, 6:49:38 PM12/10/13
to beagl...@googlegroups.com

From: <l...@snupi.com>
Reply-To: <beagl...@googlegroups.com>
Date: Tuesday, December 10, 2013 at 12:28 PM
To: <beagl...@googlegroups.com>
Cc: Don Smyth <d...@snupi.com>
Subject: [beagleboard] Linux 3.8, am335x, How to set up continuous DMA transfers
Hi Leo,
You mean DMA_CYCLIC? You should look at the DMA implementation for McBSP. Unfortunately, TI didn’t implement the McBSP driver on it’s own, but instead made it part of the sound driver implementation. I’m working on the same problem, but my SPI device generates the clock. This isn’t the same as slave mode in that my SPI device doesn’t control the SPI chip select. I hoping I can use the McBSP DMA implementation as a reference.
Regards,
John.

--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

l...@snupi.com

unread,
Dec 11, 2013, 5:57:21 PM12/11/13
to beagl...@googlegroups.com
Yes, "DMA_CYCLIC" type transfers.   What I'm attempting to do now is set up two cyclic transfers (four total, two for transmit and two for receive), and then link the two transfers together and the two receives together.  

For example, on the Rx side:

 788       // RX
 789       g_adcSpi.descRx1 = dmaengine_prep_dma_cyclic(
 790             g_adcSpi.dmaChanRx1,
 791             g_adcSpi.dmaRxBuff1,
 792             ADC_SPI_DMA_BUFFER_SIZE_BYTES,
 793             // this parameter sets the transfer level for signaling the callback();
 794             //   We can set it to be a complete transfer since the next transfer should
 795             //   already be set up and ready to go, ie, we are not racing the clock
 796             ADC_SPI_DMA_BUFFER_SIZE_BYTES,
 797             DMA_DEV_TO_MEM,
 798             DMA_PREP_INTERRUPT | DMA_CTRL_ACK /* DMA_PREP_CONTINUE ? */ );
 799 
 800       if ( !g_adcSpi.adcSpiDescRx1 )
 801       {
 802          printk( KERN "\nError acquiring SPI DMA Rx1 descriptor!\n" );
 803          return( -1 );
 804       }
 805 
 806       g_adcSpi.descRx1->callback = AdcSpiRxCallback;
 807       
 808       g_adcSpi.descRx2 = dmaengine_prep_dma_cyclic(
 809             g_adcSpi.dmaChanRx2,
 810             g_adcSpi.dmaRxBuff2,
 811             ADC_SPI_DMA_BUFFER_SIZE_BYTES,
 812             // this parameter sets the transfer level for signaling the callback();
 813             //   We can set it to be a complete transfer since the next transfer should
 814             //   already be set up and ready to go, ie, we are not racing the clock
 815             ADC_SPI_DMA_BUFFER_SIZE_BYTES,
 816             DMA_DEV_TO_MEM,
 817             DMA_PREP_INTERRUPT | DMA_CTRL_ACK /* DMA_PREP_CONTINUE ? */ );
 818 
 819       if ( !g_adcSpi.adcSpiDescRx2 )
 820       {
 821          printk( KERN "\nError acquiring SPI DMA Rx2 descriptor!\n" );
 822          return( -1 );
 823       }
 824 
 825       g_adcSpi.descRx2->callback = AdcSpiRxCallback;
 826 
 827       // now link/chain them;  1-->2-->1-->2-->1...
 828       struct omap_chan* omapChanRx1 = to_omap_dma_chan( g_adcSpi.dmaChanRx1 );
 829       struct omap_chan* omapChanRx2 = to_omap_dma_chan( g_adcSpi.dmaChanRx2 );
 830       omap_dma_link_lch( omapChanRx1->dma_ch, omapChanRx2->dma_ch );
 831       omap_dma_link_lch( omapChanRx2->dma_ch, omapChanRx1->dma_ch );


I don't think the McBSP code does anything very similar to this...all I can find is one example of setting up a cyclic transfer (overwriting the same buffer over and over again, which I don't want as it will trash my previous data)-->/sound/soc/soc-dmaengine-pcm.c, and one example of linking channels (which actually turns out to be cyclic as well, since it just links a channel to itself) -->/drivers/media/platform/soc_camera/omap1_camera.c

There's got to be a complete example of how to set this up and get it working!   :P

John Syne

unread,
Dec 12, 2013, 12:21:35 AM12/12/13
to beagl...@googlegroups.com

From: <l...@snupi.com>
Reply-To: <beagl...@googlegroups.com>
Date: Wednesday, December 11, 2013 at 2:57 PM
To: <beagl...@googlegroups.com>
Subject: Re: [beagleboard] Linux 3.8, am335x, How to set up continuous DMA transfers
Hi Leo,

I’m not sure you are correct here. Most drivers using DMA regularly use two buffers, labelled ping and pong. One buffer is filled while the other is being processed. TI have some C6000 training material which shows this working. Granted the training material is for SysBIOS, but it is written for the EDMA which is the similar to the EDMA used on the AM3359. The same concepts will apply to a Linux driver.  BTW, EDMA can support more than two buffers for both TX and RX. 

Regards,
John
Reply all
Reply to author
Forward
0 new messages