cancel
Showing results for 
Search instead for 
Did you mean: 

Circular DMA bursts

MarcelH
Associate II

I use circular DMA with a buffer of size n (on a G431) to create bursts that are not necessarily equal to a multiple of n in size. This works fine, I start and stop a timer and end up somewhere in the DMA buffer array (say, at buffer[m] where 0<=m<n) from where I can resume.

Now I'd like to change direction: I want to perform DMA in the buffer BACKWARDS from m, say p steps, with p >> n, so that cycles are made (backwards) through the buffer.

I'm not aware that backwards DMA is supported by the hardware so I plan to use a second reverse buffer. So now I need to configure circular DMA on reverse_buffer, where the buffer goes from 0 to n but I want to start at position n-m, different from 0.

According to the reference circular DMA always reloads DMA_CNDTRx with the start value. It does not specify where this value comes from. Can I access a register to use a different value for the buffer address than the start pointer?

5 REPLIES 5
TDK
Guru

It’s a bit odd. The NDTR register remembers the value it had when you start DMA. It’s not available elsewhere. I dont believe there is a way to start midway through a buffer.

You could change your buffer to always start at the beginning, though it may have performance limitations. But you have to start/stop dma anyway to “reverse�? direction so maybe this is not so hard to do as well.

If you feel a post has answered your question, please click "Accept as Solution".
MarcelH
Associate II

Thanks! Indeed, the aim is to avoid rotating the buffers because of computation time. Another approach might be to chain 'normal' mode DMA to the end of the buffer, a number of cycles in circular mode and (if needed) another normal DMA from the start to the final index, using interrupts. This will result in a bit of timing jitter at the start and finish. But an (undocumented?) access to the NDTR preload would result in much cleaner code without jitter =)

Are you talking about timer-triggered memory-to-GPIO transfers?

There's no way to start a circular DMA with an offset. When you enable the DMA channel, the exposed CNDTR is copied to a hidden one, from where it is "refreshed" after each round.

At the cost of memory, you can set up two copies of the required pattern after each other, and then start circular DMA with original size in CNDTR but the memory pointer register pointing with the required offset into that dual-buffer.

JW

MarcelH
Associate II

Hi JW,

Yes, this is about high speed mem to periph DMA on a GPIO port. Doubling the pattern is a good idea, thanks!

If I go for the circular DMA only approach there's a requirement to stop circular DMA after an exact number of timer events. What is the best way to set that up? The number of DMA transfers can be large, a 16 bit counter is not enough.

Maybe you can chain timers, using the DMA-triggering one as master, and a slave to it in external-clock mode as event counter, to determine the end of transfers. Even 16-bit timers can count up to 32 bits thanks to their prescaler...

JW