I getting fed up with circular array buffers. To be honest they cause more problems than they solve.
STM32 DMA supports multi-buffer mode where you can specify two distinct unrelated buffers instead of halving one buffer. However the STM32 HAL I2S driver does not support the use of this. I put it on the back burner to fix that by reimplementing my own I2S driver by borrowing and butchering the HAL code.
In the interim I discovered another technique which might work as well.
DMA Burst Mode and FIFOs. The idea I'm hoping to achieve is DMA'ing a buffer to the I2S peripheral's FIFO. Hoping that when the last DMA transfer completes into the FIFO the TX_Cmplt interrupt will fire and I will have just enough time to point it to it's new buffer before the FIFO runs out.
It would seem however the FIFO is only 16 octets in size. So even a 16bit I2S stream only has 8 samples (4 stereo pairs). At 48K that's about 100us which should be fine. EDIT: Not sure on that number now. However there are other delays in the DMA/I2S peripheral process pipeline, end to end, the DMA cores themselves have FIFOs etc. As Peter pointed out in a post when a DMA transfer reports being complete may not actually mean the peripheral has completely finished the last transaction, just that it's read for a new one.
The reason I'm posting, is, I'm obviously just discovering this technique and I'm giving you guys the opportunity to say "Nope, don't go there, it's won't work." or "Why not just do this instead?"
Why don't I like basic circular buffers?
1. They leave open the error condition of looping the same buffer over and over which creates dangerous audio output that can actually damage hearing.
2. Handling multiple streams requires memcpy'ing buffers all the time to "get out of the way" of the DMA pointers.
3. Managing buffer halves and flipping pointers is just so "flint stones"
4. I NEED to change buffers. I need to adjust buffer lengths. I need fall back/fail safe "silent" error conditions.
5. I have plenty of memory (1Mb) and plenty of power 450Mhz, it's time to bring out some of the "big iron" toys to the party.
EDIT
6: Circular buffers on ins, processing and output forces my timing into being 1 buffer long at each buffer transfer. With the asynchronous "pooled" buffers there can be multiple buffers for the same stream in play in the system.
Here's my current approach: (coded, not tested yet)