View previous topic :: View next topic |
Author |
Message |
julienm
Joined: 28 Jul 2020 Posts: 31
|
Speed up a loop driving a stepper motor |
Posted: Thu Oct 20, 2022 7:47 am |
|
|
Hello, I'm trying to speed up a loop in charge of generating pulses to a stepper motor. The goal was to achieve 6ms for one loop on a 18F6722.
I started from this
Code: | int32 step;
int16 ramp;
int16 delay;
int16 pin;
for( step = 0; step < ramp; step++ )
{
output_high(pin);
delay_us(delay);
output_low(pin);
delay_us(delay);
} |
Then read the doc that explains output_high/low are much slower when using variables;
Went to
Code: | int32 step;
int16 ramp;
#define PIN_A1 30000
for( step = 0; step < ramp; step++ )
{
output_high(PIN_A1);
delay_us(delay);
output_low(PIN_A1);
delay_us(delay);
} |
Then noted the mix of int16/int32 was slower than 2 int32
Code: | int32 step;
int32 ramp;
#define PIN_A1 30000
for( step = 0; step < ramp; step++ )
{
output_high(PIN_A1);
delay_us(delay);
output_low(PIN_A1);
delay_us(delay);
} |
Now I have noticed that
1. delay_us is also slower when using a variable
2. the loop itself takes a few msec (increment + comparison + code jump I suppose)
3. ++step is slower than step++
Where can I improve the code? Point 1. is the most problematic right now. I cannot hardcode the delay. How can I avoid delay_ms(delay) to take 4msec instead of 1 when delay=1 ?
Thanks in advance |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Thu Oct 20, 2022 11:42 am |
|
|
Start by telling us what clock rate your chip is running?. Critical data.
Then what you actually want to do?. Obviously you actually want the speed
to be changeable (otherwise you would not be using a variable), and you
also appear to want to be able to drive more than one pin. These are all
things we need to know before we can help.
Honestly, if you are just pulsing a few pins, use hardware. PWM or CCP.
Both are capable of doing pulses accurately, and hundreds of times faster
than software can manage. |
|
![](templates/subSilver/images/spacer.gif) |
julienm
Joined: 28 Jul 2020 Posts: 31
|
|
Posted: Thu Oct 20, 2022 3:36 pm |
|
|
THe PIC runs at 20MHz.
I want to program a trapezoid stepper command (with customisable ramp up and ramp down) that can run on 2 different motors (hence the original variable for the PIN). |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Thu Oct 20, 2022 8:27 pm |
|
|
Seriously, reevaluate your approach and use CCP (PWM mode) or a dedicated PWM peripheral. Bit-banging it, as you've discovered, has its limitations. |
|
![](templates/subSilver/images/spacer.gif) |
julienm
Joined: 28 Jul 2020 Posts: 31
|
|
Posted: Thu Oct 20, 2022 11:56 pm |
|
|
Well thanks for the comments but
- I have to work with this hardware, redesigning is not possible
- would PWM allow me to vary linearly vary the frequency at high speed? I don't want a stable pwm |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Fri Oct 21, 2022 12:34 am |
|
|
Yes, and much easier.
Key problem with the variable delay approach, is that the delay is changing
with each loop. Result it becomes really hard to give a linear speed change.
With the PWM, all you do is have a timer interrupt at (say) 100Hz, and a
table of speed values, and if the stepper state is 'ACCELERATING', each
time this interrupts you load the next faster value from the table to the
PWM. Result, lovely smooth acceleration. For 'DECELERATING', you do the
same except moving to slower values.
Most PIC's have at least two PWM's. If you can use the pins for these, a
much better solution.
I've got systems here using 'up market' PIC's with more PWM's and giving
STOP, ACCELERATE_TO_SPEED, STEADY_SPEED, DECELERATE_TO_STOP,
on six motors at a time (CNC mill with X,Y,Z, rotary table, dividing head,
and spindle speed, done exactly this way. |
|
![](templates/subSilver/images/spacer.gif) |
julienm
Joined: 28 Jul 2020 Posts: 31
|
|
Posted: Fri Oct 21, 2022 1:44 am |
|
|
I understand I really need a training on PIC programmation. Because the moment you mention using timers, I'm scared.
Also right now the 4 PWM output are used to drive some LEDs.
Long story short, there's no way to bit-bang faster by telling the compiler my variables should be stored somewhere else for faster access? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Fri Oct 21, 2022 5:26 am |
|
|
There are things you can do.
For example, on the pins, don't use a variable, but use a case.
So have a variable 'pin', and something like:
Code: |
#inline
set_pin(int pin)
{
switch (pin) {
case 0:
output_high(PIN_A0);
break;
case 1:
output_high(PIN_A1);
break;
case 2:
output_high(PIN_A2);
break;
case 3:
output_high(PIN_A3);
break;
}
|
Also your pin output will be faster if you setup fast_io on the port you
are using.
Do this and 'set_pin(val)' will code about 20 instructions faster than
using the standard output_high(variable) approach.
You are still going to have real problems getting linear acceleration.
Now I'm going to say immediately, use a timer!....
The point is that delay_us, as you have found has minimum times that
can be handled with variables, and also does not know about time that
is being used by the other operations. So, simply use a system timer.
Use #use timer, and it's default 1uSec tick. Then set_ticks(0); before
you turn the pin on, and afterwards, while(get_ticks() < 6000) will
wait 6mSec (6000 1uSec ticks). If you use an array of values to wait
for, you have your variable times.
However much better to use the PWM's.
Seriously, LED's only need slow PWM's. A single 100Hz timer interrupt,
and you could give yourself the LED's all being handled.
You then have the PWM's available for what they are designed for. Fast
pulses. The same timer interrupt can also handle the acceleration and
deceleration. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9174 Location: Greensville,Ontario
|
|
Posted: Fri Oct 21, 2022 6:02 am |
|
|
a comment....
One potential problem with 'stepping motors' is trying to step them too fast ! You must read the mfrs specs for your motors and code as needed for both maximum speed and pulse widths.
Agree , 'timers' are the way to go.....if you code with 'delay_ms(xxx)', the PIC is stuck doing the delay ,can't do ANYTHING else except twiddle bits until delay is done. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Fri Oct 21, 2022 6:43 am |
|
|
Yes. This depends massively on the controller (if it supports microstepping),
the endpoint drive voltage, and the motors themselves. Understand that
to step fast with high power, you probably need a supply that is perhaps
10* the actual rating of the motor to maintain current when stepping fast
into their massive inductance. The 'rule', is usually between 5*, and 24* their
plate voltage.
Have a look at:
[url]
https://www.e-jpc.com/stepper-motor-voltage-explained/
[/url] |
|
![](templates/subSilver/images/spacer.gif) |
|