cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F0- triggering DMA by a timer.

re.wolff9
Senior
Posted on October 24, 2015 at 15:37

  

I want to have a timer trigger a DMA transfer. I have a STM32F072RB processor. 

I currently have TIM1 as the timer. I have the timer running and reloading and that seems to work. It is currently also triggering an interrupt allowing me to count the reloads in software, verifying that the timer runs. 

I have set up the DMA controller and that seems to work except that it isn't seeing any DMA transfer requests. When I stop the CPU, disable the DMA channel, enable Mem2mem, enable the DMA again, then I can see a whole buffer get transferred at maximum speed (even though my destination is a peripheral). So, the DMA module is just waiting for requests. 

Dumping the timer (most numbers in hex): 

CR1: 5 : URS + CEN

CR2: 0x28: CCDS + MMS=2

SMCR:  0 Slave mode disabled

DIER: 0x4101: UIE + UDE  + TDE

SR 0x1F: CC4IF   CC3IF CC2IF CC1IF UIF (compares have triggerd, but interrupt has not been cleared: I don't expect those interrupts. UIF is not cleared as my CPU is halted.)

EGR: 0 : writeonly

CCMR1/2: 0  Capture compare off?

CCER: 0   Capture compare off?

CNT: 0x24  ''random'' value. 

PSC: 0x13 prescale at decimal 20, main clock / 20. 

ARR: 0x1f3: maximum value, 499, reload every 500 ticks. 

RCR: 0

CCR1-4: 0 

BDTR: 0

DCR: 0  DMA control: allows the DMA unit to DMA new values into TIM registers. Not used. 

DMAR: 5 I don't know how that came there. 

#stm32f0-timer-tirgger-dma-trgo
9 REPLIES 9
Posted on October 24, 2015 at 18:34

Post the relevant DMA register content.

Please do use 0x as prefix for hexadecimal values to avoid confusion.

JW

re.wolff9
Senior
Posted on October 24, 2015 at 23:18

CCR4: 0x00002591       <- PL=2, memsize = 16 bits. mem->periph, MINC, TEIE, EN. 

CNTDR4: 0x00000300  <- transfer size: 0x300. 

CPAR4: 0x48000814   <- GPIOC->DR

CMAR4: 0x20000f0c   <- memory buffer

All other DMA registers, including the flag and status registers are zero. 

Stopping the CPU and first disabling the DMA channel (CCR4 = 0x2590) and then enabling mem2mem  (CCR4 = 0x6291) shows external activity on the GPIOC pins, and decrements  CNTDR4 to zero. 

 
mikael239955_stm1_st
Associate III
Posted on October 25, 2015 at 01:38

Usually you enable DMA the last thing you do.Writing Timer and other peripheral values in hex is really to

convolute your own setup. Just use the ST's wierd register definitions and decimal so you at least can read your own code.

The TIMx ''update'' signal  is the preferred source for DMA request when using TIMers.if you se CNDTR values

changes you definitively have transfers going on and there is no need to turn CPU off. If  DMA try to fetch values

from flash at max speed you will starve CPU to an abrupt halt at some point.

re.wolff9
Senior
Posted on October 25, 2015 at 07:55

I do not fill the registers ''in hex'' in my source code. I'm using ''chibios'', and when I initialize a timer there are multiple ''low level drivers'' where it is difficult to find out which one I'm actually using. So while debugging this, I have resorted to dumping the register contents.  I find ''hex'' a much more useful format when dumping register contents. For example the ''2'' in 2951 is actually the priority level.  Can you see the priority level at a glance from 10577?

As to what is initialized last: I would think this depends on the data direction. If you have data coming from the peripheral it would be preferable to disable the peripheral, initialize DMA (no requests are coming in) and then initialize the peripheral. If the datadirection is the other way, you want the peripheral to be ready to handle the data with the right configuration before you start the DMA. 

In my case, with data going out on a timer, I think I would prefer initializing DMA before the timer, but after setting the GPIO correctly. The DMA would then wait without triggers while the timer is intialized. 

In various spots in the reference manual or ''using the F0 DMA controller'' it is said that I can software-trigger the DMA. I would like to do that, (to further debug what is wrong), but can't find how to do that. Is that a sentence that refers to an 'F4 DMA controller or maybe the mem2mem bit? (i.e. not one trigger, but ''don't wait for triggers at all''). 

Is the DMA module edge triggered? That would mean that indeed the wrong order would have a request pending while the ''enable'' goes high, which might lead to the DMA module thinking: ''no edge''. ... 

No the CNTDR value does NOT change. Unless I enable ''mem2mem''. 

I have (or at least tried to) selected the ''update'' to generate the DMA request. Looking at other projects with similar DMA requirements, they seem to use the PWM event. I am currently trying that, and again getting nowhere.

Thinking about it some more: I might need three DMA's going on at specific moments during each cycle of the timer. But first, having just one work would be nice. 

Posted on October 25, 2015 at 09:21

Use DMA Channel 5, triggered by Update events.

The TRIG event is not very well explained in the RM, but IMO corresponds to  TRGI signal coming from the slave-mode multiplexer (controlled by TIMx_SMCR.TS).

JW

re.wolff9
Senior
Posted on October 26, 2015 at 08:15

Thanks! That works!

It now runs once when I restart the CPU, at around 1MHz. This is going to be 2.4Mhz, there is going to be repetitiion, at 100Hz, etc etc, Now there is lots of other stuff to do that are trivial. 

I might, starting from this working example, try to figure out why this didn't work at first. I do have the distinct impression that I did tell the timer to use ''TRGO'' as the DMA request source and that the UPDATE event would route to TRGO. 
re.wolff9
Senior
Posted on October 27, 2015 at 12:20

Ok. Got two other DMA channels running off the same timer. 🙂 Happy!

The bad news: When the transfer completes, the timer gets in a new DMA request for the next iteration. 

So when it is time for the next batch, I disable both the timer and the DMA controller, setup the DMA transfers, enable the DMA controllers, initialize the timer, and then enable the timer. But at that point in time, the timer will quickly trigger a DMA request that was ''queued'' after the previous batch ended. No: i cannot disable the timer in time: it is running too fast to get to the interrupt routine before it hits another full cycle. 

So: My question is: How do I clear the DMA request in the timer or in the DMA controller, wherever it is buffered?

re.wolff9
Senior
Posted on October 27, 2015 at 21:03

Hi Jan, 

It seems you have been struggling with the same problem as I have. 

As I understand things, disabling DMA request bits in the DIER will clear the outstanding DMA request in the timer.

I had already tried that, putting the ''clear DIER'' command in the DMA finished interrupt but apparently at a moment when the ''DMA finished'' interrupt was not working (due to CCR->TCIE being 0). Aaargh!. Thanks for all your help!