cancel
Showing results for 
Search instead for 
Did you mean: 

N-Pulse Generation Problem

martingrimm9
Associate
Posted on December 10, 2016 at 15:43

Hello,

I'm trying to get exact 2048 pulses with TIM4 on Channel 1 at PB6 with a frequency of around 3 MHz after an TRGO from TIM3. Sounds actually quite simple but I've tried already the following which dosn't lead to the correct result:

&sharp1. Timer Cookbook 6.2, Example Part 1: Is not working, here the TIM1 repetition count is used which is only able to generate 256 pulse.

&sharp2.

Timer Cookbook 6.3, Example Part 2: Because of the TRGO feedback from TIM1 into TIM2, TIM2 cannot triggered extern via another hardware trigger.

&sharp3. I've tried the following TIM3[Update]---ITR2---->[Trigger] TIM1[OC1REF]---ITR0--->[Gated]TIM4 --->Ch1 PB6. Which is working, but unfortunately TIM1 is tied to APB2 where TIM4 is to ABP1 and therefore the obtained pulses are not correct and they shifting. See the gif.

&sharp4. I've counted with TIM2 the TIM4 counts: TIM3[Update]---ITR2---->[Trigger] TIM4

[Update]

---ITR3--->

[Trigger]

TIM2

 and triggered an software interrupt after 2048 is reached and manually stopped TIM4. This is not working, because of the delay in the interrupt routine. I got a variation of 2 - 4 counts too much...

Are there any other suggestions how to solve this?

P.S. It would be really a pleasure if the Timer Cookbook examples would be available in HAL-Driver code...

0690X0000060MonQAE.gif

#n-pulse #timer
3 REPLIES 3
Seb
ST Employee
Posted on December 10, 2016 at 16:35

Well, if it is an available channel, I would use a DMA to dump the CC values for each toggle edge event.

The DMA points to a toggle table, ending with values higher than the overflow value of the counter (so if it goes too far, pulses stops even if the core is sleeping or its SYSCLK frequency is low to save power).

If not, the DMA can loop over the same pulse (Cyclic sweep) until the number of transfer (=toggle) is over: It is a 16 bit quantity, so it will be good up to 32k pulses. Dual buffer mode on the DMA is also possible to make things even more HW assisted. Then only a DMA done interrupt will tell the main loop that the job is done. This scheme is a bit future proof: If later you'd like to have 2048 pulses with various duty cycle or various frequencies, it will only be a longer table in RAM...

Advice: When playing with triggers, use a physical input pin so you can use it through the oscilloscope as trigger. Use internal trigger once everything is debugged to get the job done faster.

Hope this helps.

Posted on December 21, 2016 at 10:09

Hello,

Thanks for your reply Seb. Your idea sounds good. The only drawback is, that I block quite a lot of RAM with this solution. Is it possible to readout from FLASH with DMA?

Anyway, I got it working now. I can set a high amount of pulses (like 2048) and it is working fine. I count the number of pulses with TIM1 to check. My timer setup is:

TIM3[Update]--ITR2-->[Trigger]TIM2[OC1REF]--ITR1-->[Gated]TIM4[Update]--ITR3-->[Ext.Clock]TIM1

There were some pitfalls which I had to manage:

1. Don't use TIM2 and TIM4 in OCFastMode. So the setup has to be TIM_OCFAST_DISABLE, otherwise strange things like you see in the GIF will appear.

2. TIM2 is in OnePulseMode. The delay (Pulse) has to be very high to prevent strange behaviours with the TIM4 output pulses. If the delay is too short, in my case the first up to 10 pulses of TIM4 have a varying duty cycle.

3. The clock prescaler for TIM2 and TIM4 has to be zero (Prescaler = 0). On my STM32F446RE the clock prescaler caused a lot of jitter on the TIM4 output pulses. I had an inaccuracy of around plus minus 50 pulses by an amount of 2048 setting the prescaler unequal to 0.

Hope this will help someone else.

Posted on December 21, 2016 at 10:27

I had a pet project using different programming style than usual. One of the file is related to TIMER (16 or 32 bit).

Digging through it should give some clues on how to use DMA to drive CC for pulse generation.

https://github.com/STM32Catalyst/DynamicSTM32

 

This was created to follow Clojure's perspective of function using only local variables for multi-task/recursive/multi-core.

To it was also to use hooks (for interrupt vectors) which is made from a function pointer and a context (struct) pointer.