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.

[c5517] i2s DMA transfer to ping pong buffer, possible inconsistency of LAST_XFER bit

Hello everybody,

I noticed that on the forum, it is considered common practice to use two DMA channels to acquire data stereo from the i2s, and place it in two separate ping-pong buffers into memory (left & right), waiting to be processed. Both DMA channels are hardware-triggered by the right-receive event of the I2S but, if they are under control of the same DMA controller, they won't start at the same time. One is going to be served first, and another later. I understood that, since there is no priority setting for the channels (they are served in round robin) if the two channels are triggered by the same event, it is basically random, which one is going to be served first (am I wrong?)

And here comes my question:

let's assume that the elaboration task. at a certain point wants to read the data from the PING_PONG. It will read the status register of one or both the DMA channels to decide which half is free (I am not generating software interrupts with the DMAs). There is the very unlikely, but still realistic possibility that, reading the LAST_XFER bits will give a different result for the two different channels. One channel, the first to be served, could have just written the last slot of its PING, and have updated its LAST_XFER bit to 0, while the second channel might still be writing data in the last slot of its PING, and therefore have still the LAST_XFER bit set to 1 when the read comes.

Using transfer-complete interrupts by the DMA channels wouldn't help, because if the first channel triggers an interrupt when it completes the PING and, say, wakes the elaboration task, it could be that, when the task reads the LAST_XFER bits, the second channel is still finishing its last burst in the PING, if its burst is long.

Could this happen? And is there a way to be sure about which half of the buffer is actually not being written by any channel?

For example, knowing that one channel is ALWAYS served second would help, because even if the second-served channel is writing the last slot of its PING (and so the first-served channel just entered its PONG) the first-served channel would not write its PONG until the next i2s event, which would leave a generous margin to read the PONG sections, which are not, in fact, still being accessed by anyone.

I hope I was clear, thank you in advance for your support.

V.

  • Hi,

    I believe you meant you would like to use 2 DMA channels for ping and pong buffers.

    The Ping pong mode operation is explained below. In this example buffer size of 256 is taken (128 for each ping and pong buffer).

    Ping-Pong mode is a special mode of data transfer in which DMA generates a half way interrupt. When ping-pong mode is enabled DMA considers the source data buffer as two parts and generates an interrupt after transferring half of the data. First half of the buffer is Ping data buffer and second half of the buffer is Pong data buffer. These two buffers should be allocated in contiguous memory locations or one ping buffer of size equal to double the data transfer length should be allocated. Buffer being transferred by the DMA currently can be identified by reading 'Last Transfer Type' bit of the channel transfer control register. Ping-Pong mode can be utilized effectively in the interrupt mode of data transfer.

    To transfer the incoming data stream to its destination in the internal memory, the DMA channel must be set up for a non-burst transfer with synchronization enabled. A receive synchronization event is generated for every data sample as it arrives; hence it is necessary to have the DMA transfer each data sample individually.

    The respective DMA channel needs to be enabled in the DMA channel register. The source address of the DMA channel is set to the left data0 receive register (I2S0RXLT0) address for I2S0, and the destination address is set to the start of the data block in internal memory (for eg SARAM). Since the address of I2S0RXLT0 is fixed, the source address mode is set to 10b (constant address) and the destination address mode is set to 00b (automatic post-increment). On every receive event generated by the I2S, the DMA will transfer a full double word from I2S0RXLT0 to the destination address. After the DMA has transferred the 128th sample, it sends an interrupt to the CPU, sets the LAST_XFER bit to 0 and continues the transfer. Once the 256th sample is transferred, the DMA controller again generates an interrupt to the CPU and sets the LAST_XFER bit to 1. If the AUTORLD bit has been set to 1, the destination address is reloaded and the transfer resumes.

    Hope the above helps you.

    Regards

    Vasanth