cancel
Showing results for 
Search instead for 
Did you mean: 

Feeding the next buffer to SAI DMA

jw56
Associate III

Sorry if this has been answered elsewhere, but I'm not seeing it. For background, I do a lot of work with Nordic, and in their I2S implementation, you feed two buffers to the peripheral, then every time a buffer has been transmitted/received, it switches over to transmit/receive the second buffer automatically while you point it to the buffer to use when that one is done (usually the one that just got freed). In this way you never miss any data.

I'm currently trying to implement an I2S receiver using SAI on an STM32L476. I get the data via SAI in DMA mode fine, but then I have to kick off another DMA receive (HAL_SAI_Receive_DMA) when I get the interrupt from the previous one. My sampling clock is running around 3MHz, which doesn't leave much time to point the next buffer to the SAI. So my question is, is there a standard way of handling this? How do other people guarantee that the SAI DMA will have a pointer to the next buffer when it is done the current transfer? Do you somehow leverage the FIFO as well since you presumably have eight words worth of time to start a new receive? What happens if you have a few other interrupts to service in the meantime?

5 REPLIES 5

Double-buffering in the single-port DMA in 'L4 (as opposed to double-port DMA in 'F2/'F4/'F7) is accomplished by using the half-transfer interrupt.

I don't use Cube so don't know the exact Cube incantation for that, but it's quite clearly described in DMA chapter of RM.

JW

Hmmm, that is exactly the chapter I have been reading, and I don't see anything about the validity of setting a pointer to a new buffer on half-transfer. Are you sure you have the right part? A search for the word "half" on pages 336 - 360 in rm0351 only turns up information about how to enable that interrupt. I haven't seen anything about double buffering at all in several reads through that chapter, maybe there is a different term they are using?

Actually, your response was enough to lead me here, which is enough. I didn't realize you have to actually copy from the buffer in circular mode - i.e., that the DMA doesn't have a mechanism for completely releasing the buffer and pointing to a new one. Thanks for your help.

Yes, that's the case. At the end of the day, you are most likely going to process that freshly received data anyway. You probably could use memory-to-memory DMA run at a different channel to shovel the data away, if you need so, but I'm not sure that has some point. You also probably may be able to stop/readjust/restart, if you can keep the transfer-complete-latency low enough.

As I've said above, what you are looking for is the dual-port DMA IP used in 'F2/'F4/'F7.

JW

Piranha
Chief II

I've used FIFO and DMA in normal (run once) mode and that works reliably. At least for audio stream 8 words are more than enough to disable-reconfigure-enable DMA stream.

That said, the solution described by Jan is the best. Set DMA to circular mode and implement a combined copy+process code from capture buffers to send buffers.