cancel
Showing results for 
Search instead for 
Did you mean: 

Is there a better way to generate a variable frequency using DMA and TIM2 than what is described in AN2820 Paragraph 2.2.1 Page 13/14?

KiptonM
Lead

It is doing exactly what I want, It is ramping up the frequency at the start, staying steady for some period of time, and then ramping down.

In my case, I need up to 38400 steps. And I want to count steps, not time.

My first thought was to have a big array (my STM32L443 has 64k RAM) and just load each step time in it so it ramps up at the start, keeps loading the same data through the middle and then ramps down at the end with one array.

I was having problems trying to figure out how they kept the clock symmetrical. (I am not really familiar with TIM2.) After wading through the code, I found the output was toggled, and they had 2 identical data points for each cycle. One for the low part and one for the high part. So now my data set just doubled in size. That will not work. I do not have enough memory with 64k.

I am driving the STCK pin on the L6474 and it can go to 2 MHz max, The datasheet does not say anything about whether it has to be symmetric (whether the high time must be the same as the low time). If it does not, then I think I can do it with a PWM and adjust the PWM frequency as opposed to the duty cycle. My maximum frequency is probably 32 kHz or less. So maybe I could make it a fixed high for 16 us and vary the low from 15.25 us to however slow I need it to go. Do you think that will work?

Is there a better way to do this?

Thanks in advance.

1 ACCEPTED SOLUTION

Accepted Solutions
Piranha
Chief II

Indeed using DMA and huge amounts of memory for this purpose is wasteful and limits possibilities of dynamic speed recalculation etc. You can get the implementation idea from my posts in these topics:

https://community.st.com/s/question/0D53W00001vqbgbSAA/c-stepper-motor-code-behaving-different-15-times-using-timers-and-state-from-while-loop

https://community.st.com/s/question/0D53W00001JA8GWSA1/timer-pwm-mode-driving-stepper-motor-how-to-soft-start-or-acceleration-time

And take a note that on that MCU only TIM1 and TIM15/TIM16 have a repetition counter and break features, if you decide to use those.

For stepper drivers there is no need for 50% or any other specific pulse width. From L6474 datasheet:

"At each step clock rising edge, the motor is moved by one microstep..."

Though this datasheet lacks the data about the minimum pulse width. But one can estimate that the maximum 2 MHz step frequency means that it is capable of handling at least 250 ns short pulses.

View solution in original post

11 REPLIES 11
MasterT
Senior III

I think, that using DMA for 800 Hz clock is pure "perfectionism". Even 32k much easier to work with interrupt, set one for TIM over-flow than inside ISR have "static" variable that increments each cycle for necessary number of "pixel". Load 2C (TIM_ARR -> frequency) register as you like and TIM_CCR1/4 by half of the variable to keep 50% exact duty cycle. Last things, set "preload" for all registers updated.

Piranha
Chief II

Indeed using DMA and huge amounts of memory for this purpose is wasteful and limits possibilities of dynamic speed recalculation etc. You can get the implementation idea from my posts in these topics:

https://community.st.com/s/question/0D53W00001vqbgbSAA/c-stepper-motor-code-behaving-different-15-times-using-timers-and-state-from-while-loop

https://community.st.com/s/question/0D53W00001JA8GWSA1/timer-pwm-mode-driving-stepper-motor-how-to-soft-start-or-acceleration-time

And take a note that on that MCU only TIM1 and TIM15/TIM16 have a repetition counter and break features, if you decide to use those.

For stepper drivers there is no need for 50% or any other specific pulse width. From L6474 datasheet:

"At each step clock rising edge, the motor is moved by one microstep..."

Though this datasheet lacks the data about the minimum pulse width. But one can estimate that the maximum 2 MHz step frequency means that it is capable of handling at least 250 ns short pulses.

In my case I have a stepper spinning at 400 RPM and it has 200 steps / rev, and I was using 16 microsteps per step. So that means 21333.33 steps per second. Or 46.875 us per step.

That is what started me down this path. Then I discovered that while that speed gives the best torque for the stepper, it was too fast for the end result. They really want it to take 60 seconds because they are watching a meter and looking for a peak in the signal. So they may or may not change the gear box and if they have higher gearing then we can use a smaller cheaper stepper, running at the higher speed. So I am trying to leave my options open.

And since I have a STM32L443 running at 64 MHz I guess I could do that, but I also have a CAN bus running that I have to manage. And I do not know how much that needs processor intervention since I have never used one before.

And I forgot the 25-bit EnDat encoder that has to be bit-banged to read with signal timing requirements.

Thanks for the response.

KiptonM
Lead

Your second link

  • Set output channel to PWM mode 1 and set CCR for an active pulse width.
  • Set timer to a downcounting mode and do not enable ARR preload.
  • Use update interrupt to count full steps and adjust speed by modifying ARR.
  • Use repetition counter for micro-steps, if necessary.
  • At initialization and after stopping the counter, set the CNT to a value of CCR + 1 so that output is inactive and, when starting, timer doesn't have to do useless downcounting before the first pulse.

 

ARR period can be recalculated as follows:

  1. nPeriod = (nPeriod * 15) / 16; // Acceleration
  2. nPeriod = (nPeriod * 21) / 16; // Deceleration

Of course you have to replace the ratio constants with your specific ones. Just take a note that the divider is recommended to be a power of 2, as that will be optimized to a simple and fast bit shift instruction.

Looks real promising.

And I missed the line "At each step clock rising edge, the motor is moved by one microstep..."

So I am sure you are right I could use a fixed PWM as long as the pulse was at least 250 ns. (Mine will be many times that to be safe.)

Thanks, I will look at that approach.

I was reading app note, and amazingly they use only 10 (!) "pixels" of motor speed to make it up/down.

I have little knowledge in mechanics, but 38400 "pixel" resolution for motors is seems very high, and may be justified in extremely heavy machinery where inertial force dictates conditions. But they don't use steppers in those domains.

Anyway, common practice - for example audio CODEC running at 768 kHz (ksps) in real time, is that you assign data array that uCPU could afford, like 2k-16k, than generate half-complete / full complete DMA interrupts. Some newer uCPU has double buffer support feature especially to this mode of operation. Older one use software . During time when DMA fetching/streams data of one half of the array, uCPU has some time to jump into interrupt and prepare /recalculate /refill new data in another half.

P.S.: " The maximum clock frequency of the L6208 is 100 kHz and the minimum clock low and high times are of 1 μs." AN2820, page 14/23.

I was coming to the same conclusion of using a circular DMA for the step values.

When it is in the flat stretch, I do not have to update the values, just keep track of the count. I can probably make it big enough so I can just load the acceleration table and deceleration table into 1 or 1/2 of the DMA Buffer.

L6474 maximum clock frequency is 2 MHz. I am not using the L6208 which as you said is 100 kHz

I am looking at the repetition counter. Unfortunately I already built the board using TIM2 because that is what the app that I was following said to use. I am going to have to look at the board to see if I have a pin I am using as a GPIO that has a TIM1. It looks like the STM32L443 does not have TIM15 or TIM16.

I think by changing 3 pins I can bring out TIM1_CH4. The advantage is I would have the repetition counter.

I do not understand the logic behind counting down versus counting up. When counting up the pulse goes high at the rollover. When counting down the pulse goes high in the middle, in my case 50 pulse width counts or 25 us before the end. Is there an advantage that I am not seeing?

> It looks like the STM32L443 does not have TIM15 or TIM16.

I don't know even from where some people grab all those wrong conclusions.

> When counting up the pulse goes high at the rollover. When counting down the pulse goes high in the middle

These depend on PWM mode 1/2 or other modes in OCxM configuration.

You can use TIM2 for step pulse generation and chain TIM1 as a slave for repetition/microstep counting. Then, of course, do the processing in TIM1 interrupt, but update the ARR register of TIM2.

Think about what happens in up-counter mode when you set the ARR register to a value, which is lower than CNT value at that moment - the CNT goes up until it overflows. That's a bug and on a 32-bit timer (TIM2) even at 64 MHz the full period takes 67 seconds. To solve that, one can use ARPE (ARR preload) feature or down-counter mode.

All the advantages of a down-counter mode and other fine details are written in my post in the first link I gave.

I understand now why you count down. Since I normally update at roll over and the steps are so slow (relatively) 64 MHz processor, 2 million timer clocks per second, and the minimum stepper microstepstep is about 50 clocks (and most of the time is much much more) which gives the interrupt a minimum of 25 us (or 1600 instructions) to get the value updated.

I also always keep my interrupts as short as possible, just moving data, and setting a flag for later processing. But I understand a lot of people do not do that.

Seeing the wisdom in your approach, I will count down.

Thanks for the response.

I am waiting for the HW from ST to work on this. The board is in, and all the other parts are in. In the meantime, I am getting familiar with TIM1 and TIM2 on my Nucleo-F446RE which I am running at 64 MHz and my Saleae logic analyzer.