Go Down

Topic: interrupt for multiple stepper motors - optimized approach (Read 592 times) previous topic - next topic

titous

Oct 13, 2013, 08:09 pm Last Edit: Oct 13, 2013, 08:17 pm by titous Reason: 1
Hi everyone in the fellow arduino community!   :smiley-mr-green:

I was hoping i get could some thoughts/improvements on the way I'm approaching this code.  For the last year or so, I've been working on a project which involves being able to control up to 5 stepper motors in real time.  Each of the stepper motors require a digital pin to be toggled high/low at upwards of about 100kHz.  Given the fact this is is relatively fast (max interrupt speeds for a single ISR I've ready about are 1MHz on the Due) and that the timing of the motors is time sensitive, I want to make sure I'm approaching things in an optimized way.

I'm about to take another fresh go at the code and am thinking of the following structure; for each motor we are doing two time specific things:
1) toggling the step pin HIGH/LOW, the frequency of which is changed based on the stepper speed we want -- dictates as velocity.
2) adjusting the frequency with which we toggle the step pin HIGH/LOW; this is done at equal intervals -- dictates as acceleration.

point 1) is taken care of as follows:
- I've written up my own little library (named from here on as Engine) that keeps track of information for each declared motor.
- using the very excellent DueTimer library I setup an ISR that calls a step() function in my library, the step() function being simply defined along the lines of:
Code: [Select]
void Engine::step() {
  digitalWriteDirect(_stepPin, toggle = !toggle); // fast write to our step pin, alternates between HIGH/LOW
}


where digitalWriteDirect is defined as:
Code: [Select]
inline void digitalWriteDirect(int pin, boolean val){
 if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
 else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}


This gives me a nice way of stepping motors at my required frequencies; however, in order to change the speed of motors, I have to adjust the frequency with which the step() function is called.



point 2) is handled as follows:
at this point, we've already used upwards of 5 timers (1 for each motor) which leaves us with only 4 left (correct me if I'm wrong). So we will have to do things the manual way by defining an accelerate function within my Engine library which adjusts speed and gets checked all the time (here is where we start slowing down); we'll need to accelerate for each motor (M) with something that looks like this:
Code: [Select]
void loop() {
  M1.accelerate();
  M2.accelerate();
  M3.accelerate();
  M4.accelerate();
  M5.accelerate();
}


with accelerate() being pseudo defined as something like:
Code: [Select]
void Engine::accelerate() {

  time = micros();

  if (time >= previousTime + _updateInterval) { // only update speeds after equal time intervals (_updateInterval) have passed: manual implementation of ISR

     given some condition, adjust our ISR call frequency for step(); // adjust our stepper speed
     update the proper ISR timer registry // update our ISR frequency which adjusts our stepping speed
     previousTime = time;

  }

}



here is where your smart brains come in; does anyone see an alternate approach?  weakness to my approach?  where can i speed things up?  would you do anything differently?  thanks everyone ahead of time!

Go Up