Stepper Motor Oscillocope Synchronization: Arduino to the Rescue!

In order to get good scope pictures of the winding current in a stepper motor, the scope must sync to the step pulses. However, it must also sync to the groups of 32 step pulses that make up a single set of four full steps, because the winding current repeats for each of those groups. Triggering once per revolution and delaying for a fixed amount will get you where you need to be.

The sync wheel provides a once-per-revolution pulse, but there’s some jitter in the edge for all the usual reasons and you’d be better off with a sync based on the stepper driver’s step input. The general idea is to find the leading edge of the optical pulse, find the next step pulse, then produce output pulses based on the step signal. Assuming a regular step pulse stream (from a pulse generator, for example), the output will be both locked to the wheel rotation and to the step pulses.

Normally this calls for a tedious wiring session involving logic gates and counters, but an Arduino has all the requisite machinery built in. The trick is to generate the pulses using the ATmega’s hardware, rather than program instructions, thus eliminating the usual jitter caused by instruction execution time.

I set up Timer 1 in Mode 4 (CTC with OCR1A controlling the matches) to count step pulse inputs on its T1 external clock input pin and produce a once-per-revolution output pulse on the OC1A pin. Because the output changes on the rising edge of the input clock, its rising and falling edges will provide rock-solid stable scope synchronization.

The big picture goes a little something like this:

  • Tell the counter to set the output on match, load the duration of the output pulse
  • Wait for the once-per-revolution signal, then enable the external clock input
  • Wait for the comparison to happen and reset the match flag
  • Set a one-pulse delay and tell set the counter to clear the output on match
  • Wait for the compare, clear the flag, turn off the counter
  • Wait until the once-per-rev signal goes low
  • And then do it all over again

Which produces this:

Sync Wheel
Sync Wheel

Top trace = optical signal from interrupter, middle = 1/rev sync from Arduino OC1A pin, bottom = step pulses. The motor is turning 3.5 rev/s = 210 rev/min. The top half of the screen is at 2 ms/div, the bottom half at 200 μs/div.

You could synchronize the counter to the 1/rev input exactly once, then produce the output pulse just by counting stepper pulses. It’d also be nice to have a pulse that repeats for each group of 32 microsteps within each set of four full steps, perhaps settable to a particular microstep within the group. All that’s in the nature of fine tuning.

Of course, devoting an Arduino to this project would be absurd, but for a one-off effort it makes a lot of sense.

The Arduino source code:

// Stepper motor driver synchronization
// Ed Nisley KE4ZNU June 2011

//-- Pin definitions, all of which depend on internal hardware: do *not* change

#define PIN_REV	2					// INT0 = positive 1/rev pulse from optical switch
#define PIN_STEP 5					// T1 = positive 1/step pulse from stepper driver
#define PIN_TRIGGER 9				// OC1A = positive trigger pulse to scope

#define SYNC_OFFSET	15				// steps from 1/rev puse to start of first 4-full-step group

#define PIN_TRACE_A    10
#define PIN_TRACE_B    11
#define PIN_TRACE_C    12

#define PIN_LED		13

//---------------------
// Useful routines

//--- Input & output pins

void TogglePin(char bitpin) {
	digitalWrite(bitpin,!digitalRead(bitpin));    // toggle the bit based on previous output
}

//----------------
// Initializations

void setup() {

  pinMode(PIN_REV,INPUT);		// INT0 1/rev pulse from wheel

  pinMode(PIN_STEP,INPUT);		// T1 step pulse from stepper driver

  pinMode(PIN_LED,OUTPUT);
  digitalWrite(PIN_LED,LOW);

  pinMode(PIN_TRACE_A,OUTPUT);
  pinMode(PIN_TRACE_B,OUTPUT);
  pinMode(PIN_TRACE_C,OUTPUT);

//--- Prepare Timer1 to count external stepper drive pulses

  TCCR1B = B00001000;				// Timer1: Mode 4 = CTC, TOP = OCR1A, clock stopped

  pinMode(PIN_TRIGGER,OUTPUT);		// OC1A to scope trigger

}

//----------------
// The main event

void loop() {

//-- Wait for rising edge of 1/rev pulse from optical switch

  TCCR1A = B11000000;						// COM1A set on compare
  TCNT1 = 0;								// ensure we start from zero
  OCR1A = SYNC_OFFSET;						// set step counter

  while(!digitalRead(PIN_REV)) {			// stall until 1/rev input rises
	TogglePin(PIN_TRACE_A);
  }

//-- Got it, fire up the timer to count stepper driver pulses

  TCCR1B |= B00000111;						// enable clock from T1 pin, rising edge

  digitalWrite(PIN_LED,HIGH);				// show we got here
  digitalWrite(PIN_TRACE_A,LOW);

  while(!(TIFR1 & _BV(OCF1A))) {			// wait for compare
	digitalWrite(PIN_TRACE_B,digitalRead(PIN_STEP));
	continue;
  }
  TIFR1 |= _BV(OCF1A);						// clear match flag

//-- Scope sync pulse now active

  digitalWrite(PIN_LED,LOW);				// show we got here
  digitalWrite(PIN_TRACE_B,LOW);

//-- Wait for another step pulse to clear scope sync

  TCCR1A = B10000000;						// COM1A clear on compare
  OCR1A = 1;								// wait for another pulse

  while(!(TIFR1 & _BV(OCF1A))) {			// wait for compare
	digitalWrite(PIN_TRACE_B,digitalRead(PIN_STEP));
	continue;
  }
  TIFR1 |= _BV(OCF1A);						// clear match flag
  digitalWrite(PIN_TRACE_B,LOW);

//-- Shut down counter and wait for end of 1/rev pulse

  TCCR1B &= ~B00000111;						// turn off timer clock

  while(digitalRead(PIN_REV)) {				// stall until 1/rev pulse goes low again
	TogglePin(PIN_TRACE_C);
  }
  digitalWrite(PIN_TRACE_B,LOW);

}

11 thoughts on “Stepper Motor Oscillocope Synchronization: Arduino to the Rescue!

  1. I’m dying to find out why it’s so important to have the current waveform sync’d to the step pulse… is it for some sort of anti-resonance mid band compensation study? Or trying to detect when the load is too great on the motor, just before the rotor looses sync with the rotating magnetic field? Hmmm, all things I’ve been wondering about over the years….
    – Steve

    1. why it’s so important to have the current waveform sync’d to the step pulse

      You guys are reading too much into this!

      All I’m doing is taking pictures of the current waveform at some critical microsteps, so I can put actual pix into an upcoming Circuit Cellar column. If you believe the datasheets, you’d expect the current to rise and fall just like the charts predict; these pix will show what actually happens with variations in drive voltage, current, and speed.

      So I must take a bazillion pictures to cover all the cells in that 3D matrix, but only a the interesting ones actually make it into the column.

      But in order to get clean pix, I must sync the scope to the stepper drive pulses. Those repeat in groups of 32 as the rotor turns; there are 1600/32 = 50 groups. The optical switch provides an anchor to locate the rotor position, the Arduino code delays by a (hardcoded to suit) number of steps to locate the first zero crossing, then issues a sync pulse that’s exactly two microsteps wide. The scope triggers on that and displays a nice, stable picture of the current waveform. I push the Print Screen button and shazam a PNG image appears about two minutes later, due to the slow RS-232 interface.

      Absent stable scope sync locked to the 1/rev signal and then the step pulses, I can’t get good pix…

      That’s all there is to it!

  2. I probably would have just clocked a D flip-flop with the step input and hooked the opto to the data input, which would have locked the sloppy opto signal to the step timing, unless things really got wonky. Using an Arduino is a little overkill, but it’s quick, very flexible, and a ready made part you can probably just grab and use.

    1. a little overkill

      Absolutely!

      I looked at the solderless breadboard, my IC stash, the box o’ little wires, thought “The first part is easy. The second part will be really annoying…”, then pulled out the Arduino.

      Wrong hammer for a product. Right hammer for a quick-n-dirty one-off where you’re not sure quite what you want, but you’ll know it when you see it.

  3. Just so’s you know, I hate the new style, with the paginated comments and the more-screwed-up-than-usual HTML markup which means I can’t actually click in the box I’m typing in here but have to click before it and tab down until I hit it… :)

    1. WP just improved the comments and I think I turned on the pagination option while I was wrestling the improvements to a standstill. It’s back off again and I cut the nesting down a bit. I don’t have a strong feeling one way or the other, but the layout & markup are pretty much what WP allows… and I am not getting the Custom CSS upgrade so I can spend time futzing with the layout.

      They continue to introduce wonderful new themes with fixed-width columns that put an inch or three of text down the middle of the monitor. I keep not embracing that sort of thing. It’s a standoff. [grin]

  4. Yup, looks like you fixed the pagination, but the rest is still as it was yesterday. Oh how I hate “progress”!

    1. Oh how I hate “progress”!

      You realize, of course, that’s an early symptom of fuddy-duddyhood? I can loan you the t-shirt… [sigh]

Comments are closed.