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.

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

Other Parts Discussed in Thread: AM3352

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.  

  • Hi Leo,
     
    This forum only covers the Linux SDK from TI, which is currently kernel v3.2. Kernel v3.8 is supported by the community at http://beagleboard.org/Community/Forums
  • Leo,

    Just to make sure I understand you here correctly, you are introducing a second buffer in order to avoid the latency of waiting for T_BUFF_1 (R_BUFF_1) to be flushed/refilled with data (data to be read/flushed) for the next task?

    I just want to make sure that the latency you are describing wouldn't be from changing the link register specifically to point to a new buffer address; this can always be done in between transfers and should incur no overhead. 

    -Sean

  • Thanks Sean;

        A little background on what I'm attempting--we are using SPI to talk to an ADC device, attempting to continuously monitor an analog signal.   The linux omap driver ("spi-omap2-mcspi.c") handles discreet transfers, ie, spi messages, through a queue/list, but there is a delay in between one message finishing and another being started.  This is due to the architecture of the driver, which sets up the spi device and associated DMA for EVERY transfer, and tears it down afterwards.   

       Reading through the linux documentation, I found "CYCLIC" transfers, which are capable of continuous operation, but just overwrite the same buffer over and over.   We want to preserve the data we just read, and hoped that by linking two channels together, we could read the received data from one, while the other one is in use.   CYCLIC transfers just link a channel to itself, so I tried to copy the same setup, but create an extra channel (actually two extras, one for RX and TX) and link it to the original one.   

    For example, for TX:

    "

    1003 omap_dma_link_lch( omapChanTx1->dma_ch, omapChanTx2->dma_ch );

    1004 omap_dma_link_lch( omapChanTx2->dma_ch, omapChanTx1->dma_ch );

    "

    Any help/guidance is greatly appreciated.   Can't seem to find any example code that does what I'm attempting...

  • Hi Leo,

     

    I just wanted to give you an update here that I haven't found any code as of yet that aptly describes what you are trying to do in syncing the buffers. I did find some EDMA sample test code here that might be helpful for you to look through.

     

    Also, one corner case that you might need watch out for when coding the driver is data corruption:

    RX_buffer_1 finishes receiving data, so RX_buffer_2 starts receiving data but finishes receiving new data before old data in RX_buffer_1 is used (i.e. contents are read completely). Therefore, RX_buffer_1 would again start to receive new data from the next job in the queue, erasing the contents of this buffer before it is completely read out in regards to the older job.

     

    -Sean