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.

TMS320F28377S: Circular buffer with DMA

Part Number: TMS320F28377S


For my application, I want to transfer ADC results (single words) to a circular buffer (say, 256 words long). I want the transfers to happen on each ADC EOC, so each burst/transfer would be just one word.

I expected this to be doable indefinitely without any CPU intervention at all, but based on this thread, and figure 5-5 in the TRM, it's not possible. I'm baffled as to why the DMA would be designed like this, but I'm hoping I can make use of it somehow, even if it is crippled.

I want to do one burst per DMA trigger, which means I want to stay in the "lower left loop" of figure 5-5. 

  • Oops, accidentally cut myself off...

    Anyways, I want to use the loop in the lower left which passes through the "Another DMA trigger event" box at the bottom (oneshot mode disabled). However, to stay in this loop TRANSFER_COUNT must stay greater than zero, but it's being decremented on every trigger. So to keep this circular buffer going indefinitely, my CPU would have to keep TRANSFER_COUNT from reaching zero, sort of like a watchdog timer. I suppose it could be set to an arbitrarily large number, right?

    Is there any other intervention required to make this work? Aside from reading the data out of the buffer before it's clobbered, of course.

  • Mike,

    Yes, you should be able to achieve what you are trying to do.

    On each ADC EOC, you should be able to initiate a burst. Here are the key settings.

    1) Set your BURST_SIZE = 0 (1 WORD for each ADC EOC).

    This setting will ensure that on each ADC EOC, 1 word gets transferred to buffer

    2) Set your TRANSFER_SIZE = CIRCULAR_BUFFER_SIZE.

    This setting will ensure that DMA interrupt is triggered only after it completes filling the circular buffer. If you don't wish CPU intervention, just disable DMA interrupt in PIE.

    3) Set your WRAP_SIZE = CIRCULAR_BUFFER_SIZE

    This setting is what ensure to create circular buffer.

    Regards,

    Manoj

  • So if you start by setting TRANSFER_SIZE to 256, then after each DMA trigger you'll branch to the "upper right loop" because TRANSFER_COUNT>0. On the next DMA trigger, the active address registers will be reloaded with the shadow addresses. So 256 transfers (each with a one word burst) will occur, but all using the shadow addresses (the first entry in the buffer), instead of writing once to each of the 256 addresses in the buffer. Not a circular buffer at all.

  • Mike,

    Sorry, I'm not able to follow what you are trying to convey. What do you mean by upper right loop?

    What are your configuration details?

    Regards,

    Manoj

  • I'm referring to figure 5-5 from the TRM, as shown in my first post. There are two nodes in the diagram which wait for DMA trigger events, one at the top and one at the bottom. When I look at figure 5-5, I see two major loops, each having one of these wait states controlling when it iterates. Here's a clearer picture:

    The upper right loop resets the active address registers back to the shadow registers on each trigger. This does not behave as a circular buffer. The lower left loop does not reset the active address registers every trigger, but allows them to step and wrap. However, it only stays in this loop so long as TRANSFER_COUNT>1. When TRANSFER_COUNT reaches zero, it will escape back into the upper right loop, back to the top (assuming we're in continuous mode), and then the active registers will be overwritten again.

    I haven't written any code for this, I'm just working out the documentation. I'm assuming this will work with continuous mode enabled, oneshot mode disabled. I don't intend to make use of any DMA ISRs (if possible).

  • Mike,

    Yes, you will be able to achieve circular buffer with continuous mode enable and one-shot mode disabled and you don't need to use DMA ISR.

    One a DMA trigger event, DMA channel performs (BURST_SIZE + 1) words of transfer. This is called a burst.

    One DMA transfer loop is said to be complete only after (TRANSFER_SIZE + 1) number of bursts have been completed. So, in order to complete 1 DMA transfer loop, you need TRANSFER_SIZE + 1 number of DMA trigger events. When one DMA transfer loop is complete, DMA would have transferred (TRANSFER_SIZE + 1) x (BURST_SIZE + 1) words. Copying shadow registers to active registers is only necessary at the start of 1st burst.

    To implement circular buffer function, your WRAP_SIZE should be less (or) equal to TRANSFER_SIZE. WRAP_SIZE specifies the number of bursts to be completed before source / destination address wraps around to the beginning address.

    Also, i would encourage you to look into "Direct Memory Access (DMA) -- Lab: Use DMA to buffer ADC results" provided in below link. It goes over how to implement circular buffer using C2000 DMA.

    training.ti.com/c2000-f2837xd-microcontroller-workshop

    Hope this helps.

    Regards,

    Manoj

  • Hi Monaj,

    I see what you mean. It works when (transfer_size+1) is exactly an integer multiple of (wrap_size+1), and when you start at the first entry in the buffer, and wrap_step=0.  In such a case, transfer_count will reach zero at the same time that wrap_count would also become zero. Because of that, branching to the top of the flowchart causes wrapping to occur the same way it would at the bottom of the flow chart.

    One more quick question: Is it possible to manually overwrite the count registers and active registers during a transfer? I assume that doing so during an actual data transfer might cause some problem, but is it okay if I ensure it's only done while the DMA is waiting for a trigger?

    Thanks!

    Mike