driving steppers with timers.

hello all,

i've been working on stepper driver code for a while and now i think its time to take it to the next level and generate the stepping signals based on timer interrupts. i'll lay out my initial thoughts and then my questions and hopefully someone can give me some pointers.

  1. my standard usage case is going to be driving my 200-step motors in half-step mode (ie... 400 steps / revolution) Generally I think the speeds will be from 0-200 RPM, but the ability for higher speeds would be nice as well.

  2. Working from that, I've determined the range of delays I would need to get the desired speeds with this formula:

delay = 60 seconds / (RPM * steps)

so, here's some of the data i've come up with:

1500 RPM
(60 seconds) / (1500 * 400) = 100 microseconds

1000 RPM
(60 seconds) / (1000 * 400) = 150 microseconds

750 RPM
(60 seconds) / (750 * 400) = 200 microseconds

500 RPM
(60 seconds) / (500 * 400) = 300 microseconds

400 RPM
(60 seconds) / (400 * 400) = 375 microseconds

300 RPM
60 seconds / (300 * 400) = 500 microseconds

200 RPM
(60 seconds) / (200 * 400) = 750 microseconds

132 RPM
(60 seconds) / (132 * 400) = 1136.36 microseconds

100 RPM
60 seconds / (100 * 400) in microseconds

43 RPM
(60 seconds) / (43 * 400) = 3488.37 microseconds

1 RPM
(60 seconds) / (1 * 400) = 150000 microseconds

okay, so judging from that i should be able to decide how often i need to interrupt to generate accurate signals. obviously the higher the better, but that also means less time for the rest of the code.

i'm thinking every somewhere from 50-100 microseconds would be a decent speed. i'm not sure on the maths, but i came up with this formula to give me the number of instructions i can do per interrupt:

(1/16 000 000) second = 0.0625 microseconds (time per instruction)
50 / 0.0625 = 800 instructions
75 / 0.0625 = 1200 instructions
100 / 0.0625 = 1600 instructions

now in the interrupt i dont have to do much, so i think i should be able to do those speeds. here's what i need to do (for 3 or 4) stepper motors)

  1. check an int step counter to see if its > 1 (ie how many steps do we have left)
  2. do a modulus on the long counter with the int delay variable to see if its time to step again.
  3. do 2 digital writes to send a pulse
  4. decrement the int step counter

now that i've done a brain dump of what i've been thinking about... here are my questions:

  1. what timers do i have available? it would be nice to still have the PWM available, but i could probably live without them since i'm turning the arduino into a 3+ axis stepper controller.

  2. what speed do i set it to, and how do i set it up? i need to be able to do really slow speeds as well as fast, so i'm guessing i'll need to make some sort of counter that is a long to hold the number of ticks.

sorry about the novel, but hopefully someone reads through it and is able to help me.

okay, so i forged ahead and decided to give it a go. i'm using pretty much all of the digital pins for stepping, so i felt it was okay to use one of the timers dedicated to PWM for it. i went with TIMER2 for no particularly good reason. the biggest thing i'm confused about is how to set it up to work correctly. here's what i came up with:

      //output mode = compare output, non pwm clear OC2A on match
      TCCR2A |= (1<<COM2A1); 
      TCCR2A &= ~(1<<COM2A0); 

      //waveform generation = mode 2 = CTC
      TCCR2B &= ~(1<<WGM22);
      TCCR2A |= (1<<WGM21); 
      TCCR2A &= ~(1<<WGM20);
      
      //set our prescaler to 8. one tick == 0.5 microseconds.
      TCCR2B &= ~(1<<CS22);
      TCCR2B |= (1<<CS21);
      TCCR2B &= ~(1<<CS20);

      //set the max counter here.  interrupt every 50 microseconds. (0.5 micros * 100) = 50 micros
      OCR2A = 99;

what i want is for this to count from 0-99 (100 ticks) with each tick happening every 0.5 microseconds. the stepper handler gets called every 50 microseconds. then i can use this interrupt handler to generate stepping signals:

SIGNAL(SIG_OUTPUT_COMPARE2A)
{
//handle our stepping here.
}

does this look good? i havent been able to test it yet. hopefully i'll be able to get to the lab on friday to test it.

thanks in advance guys!

i read over your post, and i can be of no help. I find what you are trying to do quite interesting, and am going to keep what you are trying in mind for future projects. I wish you the best at it. keep us posted

Ryan

Sounds very cool to me too!

A tip: the digitalWrite() function is pretty slow. You might want to cache the registers and write to them directly in the interrupt. See pulseIn() in ARDUINO/hardware/cores/arduino/wiring_pulse.c for an example.

I didn't read through the register settings, but if they don't work, let us know and I'll take a look.