2009-11-22 07:33 PM
Has anyone successfully used timer input capture with DMA?
2011-05-17 04:30 AM
Hello: I have no problem performing output compare, with or without DMA, but input compare seems to be a different challenge -- I am having a lot more difficulty with this than I expected. I ultimately need to use the DMA to buffer timer3 input captures, but I cannot even get the input capture to work at all.
The application notes that make examples of input capture are very special-purpose, and they do not seem to produce working code. I feel that there must be some settings I am overlooking. Does anyone have a working example? I have tried using the function calls from the FWlib and setting the registers directly. Should I use Floating input? Pull-up? I am completely lost on this one.2011-05-17 04:30 AM
What's that special on library example code? Eg. OnePulse contains initialization of IC channel. The associated pin must be in Input Floating (or w-pu or w-pd) mode, both timer, AFIO and the GPIO unit clocked!!!
Don't forget to allow the DMA generation from that CCx channel and set-up properly the DMA (ICx address as source register, TIMx_CCx as trigger source - be aware the DMA channels are limited in trigger combinations, DMA mode PeripheralSrc).2011-05-17 04:30 AM
See my post on Nov. 9 regarding a capture compare race condition. It doesn't do DMA, but should help you get capture working.
Cheers, Hal2011-05-17 04:30 AM
Thanks for the input guys. I think I am on the right path.
My timer input capture, it turns out, has always been working. I had set the ''period'' value to a low number because I don't have long pulses. So I was seeing what appeared to be random data in my DMA. I increased the period to a very large value (FFFF), and now I realize that my problem is that the timer CNT is not resetting to 0000 after each capture event. I thought it would reset on the CCR event. I am now reading the reference manual to see if there is a bit I can flip in some timer register that will clear CNT after each capture. Unfortunately I have an ultra-low power budget so I cannot just do this in software at each CCR interrupt (which I have actually disabled). But I'll figure something out. Thanks for the link raptorhal, even if all it did was inspire me to be crazy and set ''period'' to an outrageous number.2011-05-17 04:30 AM
OK, I have things working. What I have done is definitely a hack, but it works!
I have kept the input capture setup exactly the same, but I have activated the slave mode in addition. The DMA still accesses the CCR1 register and the CC1 event is what triggers the DMA. Here are my settings for the SMCR slave register. As it turns out, by changing some of the values here, you can do really cool stuff with input capture. In fact, you can get almost all of the functionality of the advanced timers (TIM1, TIM8), such as PWM input, even with the normal timers (2-5). SMCR setting to measure rising edge to rising edge: 0x05D4 SMCR.ETP [b15] = 0 (non inverted) SMCR.ECE [b14] = 0 (external clock disabled SMCR.ETPS [b13:12] = 00 (prescaler) SMCR.ETF [b11:8] = 0101 (filter, this setting can be changed to whatever) SMCR.MSM [b7] = 1 (master/slave mode enabled. This is important. Disable for PWM behavior) SMCR.TS [b6:4] = 101 (filtered TI1 edge detector) SMCR.SMS [b3:0] = 0100 (Reset mode. This is important. It resets the counter on each edge) [ This message was edited by: jpnorair on 19-11-2009 07:49 ]2011-05-17 04:30 AM
Indeed, that's what PWM Input example does, except the DMA :)
2011-05-17 04:30 AM
The problem with the PWMI example is that it occupies two timer channels with measuring frequency and pulse length. Therefore the isr code is more simple than the example measuring frequency only. For known frequency inside PWM demodulation, you can easily remove the frequency channel with own code not using the pwmi example. Channel 1 requires edge detect mode for slave reset, channel 2 works without edge detect and channel 3 + 4 is unfortunately not possible becouse input mux is a XOR and result changes with level at other input pins. Here is my initalisation for timer 2 channel 2 (using DMA1 Channel5)
TIM2->CCMR1 = 0x00000102; // Mux to IC1->CCx TIM2->CCER = 0x00000013; // Capture Compare Enable, Capture LH Edge TIM2->SMCR = 0x000000e4; // Slave Mode Reset TIM2->DIER = 0x00000202; // enable DMA Request TIM2->CR1 = 0x00000001; // timer enable DMA_Init and NVIC_Init has been used from the periph lib. First I used DMA circular mode. Becouse of sync problems, I later changed to normal mode with DeInit-Init sequence for each PWM Pulse train to decode. Be carefull, considering ''dirty'' PWM signals with unknown number of edges requires re-synch of DMA pointers. The above example enables Interrupts and DMA and they trigger slightly diffrent. If number of incoming edges are higher than DMA transfer count, the pending DMA request will trigger immediately after next DMA_Init. To avoid this and achieve proper re-sync, you have to issue a DMA disable-enable sequence in TIM2->DIER before each DMA_Init. This will reset pending dma requests from previous telegrams and avoid a one bit shift inside actual telegram.