cancel
Showing results for 
Search instead for 
Did you mean: 

DMA MemoryToMemory using Timer for delivery rate?

skeezix
Associate II
Posted on January 27, 2014 at 23:27

Given an F4 (F405 and F429) or even F2 ..

Is it possible for a DMA to be both MemoryToMemory and have the rate of delivery be set by a timer?

ie: I'm effecting a copy from an array in RAM, to a GPIO. (a byte at a time, say, otherwise I could use SPI tricks.)

With MemoryToPeripheral I think you can do it, but is M2M full speed only?

Or is it possible to refer to a GPIO as a peripheral somehow?

Thank you my friends,

jeff

#stm32f4-dma
20 REPLIES 20
skeezix
Associate II
Posted on January 28, 2014 at 20:44

Theres some macros that aren't fond in the .h file referenced; you're also just using src and dst memory buffers, with one as a peripheral. Doesn't seem to work for me when I do that.

How odd 🙂

I think I need to reduce to a very specific test case and try similar..

Posted on January 29, 2014 at 14:39

> ''Each stream also supports software trigger for memory-to-memory transfers (only

available for the DMA2 controller)''

> --> I'm unclear on 'trigger' term if it means what I think it does.. but this suggests memory to memory rate control as I'd need

This probably supposed to read like ''If you set M2M mode (and you can do that on any stream in DMA2), then it is enough to set EN (from software - that's why ''software trigger'') to start the transfer; unlike in M2P/P2M modes, where transfers are initiated from the hardware inputs connected to the peripherals (through the ''channels'' multiplexer)''.

> Theres some macros that aren't fond in the .h file referenced

Namely?

Did you notice that I don't use the stock stm32f4xx.h?

> you're also just using src and dst memory buffers, with one as a peripheral.

That was the purpose of my experiment, to determine, whether in M2P/P2M modes the DMA insists of having an APB-mapped address, or any other could be used. As the comment says, DMA1 throws an error if both addresses are in SRAM, whereas DMA2 allows it. I would be very surprised if GPIO wouldn't be as good as SRAM as target address.

While I like to play, I am not fond of using experiments as replacement for what I expect to be described clearly in the manual. But, given the current state of publicly available documentation, and given that ST's support apparently doesn't want to deal with a petty sub1M consumer I am, sadly, this is the only option left for me.

JW

skeezix
Associate II
Posted on January 29, 2014 at 15:55

I had not noticed your using a non-standard header; will check it out or diff it 😉

Very interesting.. I'm ripping out my DMA-specific code to make a little test case, as my larger project is weighing down this investigation; my next order was to switch over some DMA mem-to-mem operations to mem-to-periph and periph-to-mem and see if they still work, or which of those do. In the past, just cutting over from mem-to-mem to m2p with p being a gpio address did not work, but I didn't try very hard.. quite possibly borked it.

I'll fiddle around and post my code later on; RL is in the way, but this is what I really want to sort out today 😉

Thank you for your replies; it is very helpful, and I'm still new with the STM32 arch.

jeff

skeezix
Associate II
Posted on January 29, 2014 at 17:36

Does this suggest anything?

Narrowing in .. the parts of the DMA struct in the StdPeriph library that care about Mem and Periph can be narrowed down here:

#if MODE == 1 // M2M                                                                                                                                                                           

  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;

  DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)&GPIOC->ODR;

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)src;

#elif MODE == 2 // P2M                                                                                                                                                                         

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;

  DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)&GPIOC->ODR;

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)src;

#else // M2P                                                                                                                                                                                   

  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

  DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)src;

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOC->ODR;

#endif

The rest of the code can remain unchanged.

In this case, the M2M mode works to blit from src array to GPIO. The other two modes M2P and P2M do not work. Perhaps I'm messing something else up, but strikes me .. just doing the above, with no other changes, suggests you cannot just sub in a GPIO address. It implies neither RAM nor GPIO can be treated as a periph.

I will verify with src and dst both being RAM, since I believe you have demonstrated that to work in M2P. If src/dst both M2M it should work, and prove the code.

It is interesting to note that in your case, with M2P (or whichever) with both as RAM points, that implies that RAM does in fact work as a Periph. And even if GPIO only works as a Mem side, and sicne your test suggests RAM can work as periph, then P2M RAM to GPIO should at least work.

So my test case is either broken (quite possible ;), or yours is (less likely.) I'll fiddle.

Posted on January 29, 2014 at 17:56

Here's an externally clocked example I built a while back. I think I'd just need to change the channel/stream for it to clock from an internal source.

https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Data%20transfer%20from%20GPIO%20port%20to%20RAM%20buffer%20using%20DMA%20upon%20receiving%20a%20trigger%20signal%20on%20the%20timer%20capture%2...

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on January 29, 2014 at 18:10

> In this case, the M2M mode works to blit from src array to GPIO. The other two modes M2P and P2M do not work.

Specify ''do not work''. Have you looked at the DMA stream and error register content after it ''did not work''?

Are you sure you set up correctly the DMA's trigger? Which timer are you using, and to which stream/channel are you feeding it and how?

JW

Posted on January 29, 2014 at 19:18

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6dU&d=%2Fa%2F0X0000000bsD%2FECTFMlOBYKM52fAgg6cOsNzBziAUh6KDmI6iv8UAlro&asPdf=false
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
skeezix
Associate II
Posted on January 29, 2014 at 22:30

Excellent; this one works out of the box, and looks like a perfect match .. M2P, memory to GPIO, timer updating the flow rate I think. At least, the settings seem right.

Thank you both for bearing with me .. I'll work through my code and see how its differing. I must be missing something, though it seems to be the same stuff.

In my case I'm using another timer to turn on/off the DMA, so its entirely possible I'm clobbering it somehow. Video and audio generation. Tried to get clever and slaving multipler timers off each other.

Will report back. This thread is certainly very helpful and I hope will be useful to others in the future 🙂

skeezix
Associate II
Posted on January 29, 2014 at 23:31 Aha! Thank you both, my problem has been solved! Turns out this was the gotcha, I believe:

DMA_IT_TCIF1

I was using:

DMA_IT_TCIF
 As such I was not properly clearing the DMA and I suspect it was hanging.
 I am now good, and in debted to you both (again :)

kastein
Associate
Posted on June 12, 2014 at 01:20

Hi,

Thank you very much for posting this example - I'm not exactly sure how to proceed, however.  I am building a custom data logging system for my next offroad vehicle that will be used to log accelerometer readings, speed, GPS position, wheel speeds, suspension travel, engine operating parameters, etc.  I'm attaching a parallel ATA or CompactFlash (unsure which at this point, though they're logically very very similar) solid state storage unit of approximately 16-64GB size to an STM32F series MCU.  Port E is routed to the D0-D15 lines, #IORD/#IOWR to a few GPIO pins (since my fallback if I can't get DMA working is to use PIO mode) and now I'm trying to figure out how I should connect my DMARQ and #DMACK pins to Timer 8 on the STM32F so the DMA controller can handshake with the drive properly.  The way P-ATA/CF/IDE DMA handshaking works is that the controller initiates a DMA transfer command by writing command parameters to several registers over the bus, then the storage device requests the first word by activating DMARQ.  The microcontroller then needs to respond by driving data onto port E, waiting the setup time, then activating #DMACK and the appropriate #IORD or #IOWR signal (depending on which way the data is flowing... in my case, writing).  Once the #DMACK signal activates, the storage device receives or transmits the data, then reactivates DMARQ to request the next transfer as required.

I may need to add external glue logic for #IORD/#IOWR, I think.  But my major question is - which external signals on Timer 8 do I use as DMARQ/#DMACK so this will all work?  Is there any way to do it?  Reading the software reference manual and your example cleared things up a bit, but I'm still not really sure what signals I should be using here.  Once I know that, I can finish laying out my PCB artwork, build the board, and worry about writing the software if PIO mode ends up being a bottleneck.

Again, thank you very much for taking the time to write up that example - it answered many of my questions, just not all of them.