Introduction: $4.5 Better Stepper Driver

About: Recent graduate from CMU, now working at Northrop Grumman. Mostly inactive at this point, but still around occasionally.

In the last few years, 3D printers, personal CNC machines, and plotters have gained enormous popularity in the DIY community.  The powerhouse begind these is the stepper motor, which is capable of precise movement, and can be salvaged easily for next to nothing.  Driving these motors, however, is more complicated than almost any other motor, and though many options exist, a few stepper drivers can cost upwards of $40.  Enough to run a 3D printer can be the more expensive athan any other part. 
After I made a very cheap driver using the L293 and attiny 85 (https://www.instructables.com/id/5-stepper-driver/), I thought I had a good solution, but I quickly became dissatisfied with the speed, tendancy to lose steps, and lack of current regulation.  This stepper driver seeks to fix these issues, and for even less than the original project.  

Step 1: What You Need:

Most of the parts can be bought from Jameco.com, or most electronics suppliers.  The L6219 cannot, but more on that later. 
1xAttiny 2313 (or any arduino-compatable with at least 16 IO pins and 2 interrupts.  An uno or leonardo will work, but an attiny is just $3 from Jameco.com, roughly one tenth the cost of a normal arduino.  The 8 pin attinies (attinys?), such as the 85 will not work)
2xL6219
8x820pf capacitor
4x1k resistor
4x1ohm resistor
4x30K-60K resistor
4x100nf capacitors
2x100+uf capacitors
(I didn't use the last two as my power supply already has some big caps on it.  A good electronicist would put at least the 100nf caps on, but I just forgot to)

Step 2: An L2619, What Is That?

The L2619 is a rather unusual part, and is seldom used by hobbyists, despite several advantages it has over more common motor drivers.  It does require a small ammount of circuitry (though just 10 common components), but when operating correctly, it can regulate current, requires little or no heatsink, takes phase/current input, and doesn't make a high-pitched whine whenever the steppers are running.
Hook up all the parts as shown on page 6 of the datasheet here: http://pdf.datasheetcatalog.com/datasheet/SGSThomsonMicroelectronics/mXsqwuv.pdf
Test it first with some LEDs with 1k resistors, at 9V on Vs (Vss MUST remain at 5V), and note that the I0 and I1 pins set current, phase sets polarity, and that it recoginizes low signal (ground) as active.  Once you have established that it operates correctly, hook it up to a DC motor on each output, and connect the I0 and I1 pins separately.  The motor should speed up when you connect both and slow down (but not stop) when one pin is connected.  If it all checks out, then solder it, check it again, and make another one. 

When you have finially made it past the trials of the electronics gods and have two functional motor drivers, we move to the fun part.  Software. 

Step 3: Pre-software

I lied. No software yet.  Soon.  First, you need to set up that blue thingy with a magic thingy on it to get the magic stuff to the magic black caterpillar thingy.  Or you could setup your arduino to send code to the attiny.  Either way.
This has been written about something around ten billion times since the cores were released a few years ago, so just follow the directions here: https://www.instructables.com/id/Arduino-ATtiny2313-Programming-Shield/#intro You can just use a breadboard, as you only need to send the code once, though attiny2313s are great, so I would make a more permanent programmer for other projects.  Make sure you are using an arduino software of 1.0.3 or earlier, as 1.5+ does not work. 
Once you have an LED blinking on your attiny, or some other bit of test code, it's time to move to the fun part. 

Step 4: Software. That Thing That Makes Stuff Do Stuff.

Now, just copy and paste the software below to the IDE and click on...tools?
Yes, tools. Then go to "board" and select "attiny2313 @ 8Mhz". Yes, I know the other instrucable said to set it to 1MHz earlier.  This uses 8MHz becuase it makes it run 8 times faster, with absolutely no modification, software or otherwise.  Making sure than your normal arduino is configured to send programs to the attiny (it may wreck the arduino if it is not), click " tools>Burn Bootloader". Some lights should blink, and then it should say "done burning bootloader". If it did not return an error, then just upload the code normally. When the blinky lights stop, disconnect the arduino, pull out the attiny, and break out your breadboard once more.

//attiny 2313 stepper driver by Jduffy. Full instructions on instrucatables.
const byte I011=1;//the pins for each function.
const byte I111=2;//names ending in 1 are for stepper 1
const byte dr11=3;
const byte I021=8;
const byte I121=9;
const byte dr21=10;
const byte I012=11;//same for stepper 2
const byte I112=12;
const byte dr12=13;
const byte I022=14;
const byte I122=15;
const byte dr22=16;//for all of the following, 0 represents on "on" pin
// as the 2619 registers low as active.
//lists like this are used because they take very little of the
//chips memory, which for the attiny2313, is in short supply (just 2k!)
//It also greatly simplifies the code below.
boolean stp10[]={1,0,1,0,1,0,1,0,1,0,1,0};//output to LSB current limiting 1
boolean stp11[]={1,1,0,0,0,1,1,1,0,0,0,1};//output to MSB current limiting 1
boolean stpd1[]={1,1,1,1,1,1,0,0,0,0,0,0};//output to direction 1
boolean stp20[]={0,1,0,1,0,1,0,1,0,1,0,1};//output to LSB current limiting 2
boolean stp21[]={0,0,1,1,1,0,0,0,1,1,1,0};//output to MSB current limiting 2
boolean stpd2[]={0,0,0,1,1,1,1,1,1,0,0,0};//output to direction 2
byte stepp1;//step part for stepper 1
long pos1;//"actual" position of stepper 1
long dpos1;//desired position of stepper 1
byte in1=6;//direction input pin for stepper 1
byte stepp2;//same stuff for stepper 2
long pos2;
long dpos2;
byte in2=7;
void setup(){
DDRB = B11111111;//This is very important, as this is the
DDRD = B1000011;//same as "pinMode();, but takes very little space.
//If you use anything other than an attiny 2313, then you must change all of these to
//the standard "pinMode();" command.
DDRA = B011;//if you use pins 6 or 7 as outputs, you MUST change these lines
//
//If you don't know what these lines mean, there is an
//explanation at http://arduino.cc/en/Reference/PortManipulation
attachInterrupt(0,step1,RISING);//ALWAYS on digital 4 or 5 (0=4, 1=5), the interrupts cannot be
attachInterrupt(1,step2,RISING);//on ANY other pins, unless you use pcinterrupts, which offers little
}//to no advantage. The 0 and 1 are same for all avr boards, though the pin number itself will be different
void loop(){
if (pos1!=dpos1){//if the stepper isn't where it should be...
if (pos1<dpos1){//and it needs to go foward...
stepfwd1();//go foward!
}else{//otherwise
stepbck1();//go backward!
}
}

if (pos2!=dpos2){//do the same thing for stepper 2
if (pos2<dpos2){
stepfwd2();
}else{
stepbck2();
}
}
delayMicroseconds(3); //wait a little bit
}

void step1(){//if the "step" pin for stepper 1 was brought high
if(digitalRead(in1)==LOW){//and the "direction" pin is low
dpos1++;//tell the loop to step foward 1
}else{//otherwire
dpos1--;//step back 1
}
}

void step2(){//same for stepper 2
if(digitalRead(in2)==LOW){
dpos2++;
}else{
dpos2--;
}
}

void stepfwd1(){//if stepper 1 needs to go foward
stepp1++;//advance the step sequence 1
pos1++;//increase the percieved position by 1
if (stepp1 > 11){//if it finished a full step then
stepp1=0;//reset it to the beginning of the step sequence
}
out();//digitalWrite all the pins that need it.
}
void stepfwd2(){//same for stepper 2
stepp2++;
pos2++;
if (stepp2 > 11){//if it finished a full step then
stepp2=0;//reset it to the beginning of the step sequence
}
out();
}


void stepbck1(){//if it needs to go back
stepp1--;//move the step sequence back one
pos1--;//move the percieved position back one
if (stepp1 >12 ){//if it finished a full step then
stepp1=11;//reset it to the beginning of the step sequence
}
out();
}

void stepbck2(){//same for stepper 2
stepp2--;
pos2--;
if (stepp2 >12 ){//if it finished a full step then
stepp2=11;//reset it to the beginning of the step sequence
}
out();
}

void out(){
if(stepp1>11){//these keep the "stepp" byte from going out of the data
stepp1=0; //in the step lists.
}
if(stepp2>11){
stepp2=0;
}
digitalWrite(I011,stp10[stepp1]);//writes the values of each list to its pin.
digitalWrite(I111,stp11[stepp1]);
digitalWrite(dr11,stpd1[stepp1]);
digitalWrite(I021,stp20[stepp1]);
digitalWrite(I121,stp21[stepp1]);
digitalWrite(dr21,stpd2[stepp1]);
digitalWrite(I012,stp10[stepp2]);
digitalWrite(I112,stp11[stepp2]);
digitalWrite(dr12,stpd1[stepp2]);
digitalWrite(I022,stp20[stepp2]);
digitalWrite(I122,stp21[stepp2]);
digitalWrite(dr22,stpd2[stepp2]);
}

Step 5: Final Wiring. Finally.

We're almost done.  The final step is just connecting a few pins and testing it.  Going by the included pinout, attach the two motor drivers you made earlier to the attiny.  The I0, I1, and DIR indicate the pin on each motor driver.  The first digit after that indicates which half of the driver to connect it to, the seconds indicates which driver.  The step-# and dir-# pins are the inputs. Once the wires are all connected, I would add some LEDs on 2k2 resistors to ground on some pins (any pins will give you feedback, though the step and direction pins are especially useful).  Then, connect some controller (I used an UNO with grbl) to the four inputs, (make sure to connect the grounds!) and start some sweet, silent, simple stepper stepping.  If the motors vibrate, but do not step, check for loose connections, and ensure that the drivers are connected to the correct attiny pins.   

If it (somehow) works correctly when breadboarded, then transfer it all to PC board, and enclose it (I used an old speaker housing).  Test it again, and if it all checks out, congratulations! You're done. 

This is not an extremely fast, accurate, or powerful stepper driver, but it is a significant step up from using counters and decoders.  It has 1/3rd microstepping, which though an unusual number, (most are multiples of 2) still gives pretty good performace.  I've gotten it to step a NEMA23 motor at as high as 8300 steps per second.  Note that higher speeds require acceleration from the controller, the attiny does not slowly accelerate the motors itself.  As long as it can take at least 750mA, this can drive most motors very fast, as any voltage up to 40V can be applied without exceeding the current rating.  The supply voltage should be able to handle at least 1.5A RMS, and should be greater than 10V.       

Build My Lab Contest

Participated in the
Build My Lab Contest

Hardware Hacking

Participated in the
Hardware Hacking