ESP32 work with DRV8825 stepper motor driver?

Feasibility

A stepper motor program successfully runs from an Arduino Uno. When I change to an ESP32 development board, the motors make little sounds and do not move.

I troubleshooted with my DMM; all the pins are correct. The supply voltages and grounds are correct too. (The ESP32 outputs 3v3 instead of 5 V high.) The DRV8825 specifications say, "Can interface directly with 3.3 V and 5 V systems." The datasheet seems to accept 3v3 as logic HIGH since 2.2 V is the minimum:

From the ESP32 datasheet:

From the DVR8826 datasheet:

Is it feasible to use the ESP32 with the DRV8825 stepper motor driver? If the clocks and timing is off, is there a way to fix it?

Post your wiring diagram and code.

It seems that the ESP is so fast that, without a delay, the step pulse hold time is too short. The simple stepper code uses a 20us hold time and works with that OK (when enabled for both directions). I tried 1us for the hold time and it works so far (650ns minimum).

I wired up my ESP32 to a DRV8825 stepper driver and NEMA17 stepper motor. The wiring is done as shown with 2 exceptions. 1. the enable pin is wired to an output and set to low and 2. microsteps set to 8X* (M2 to ground).

Running the code from Robin2's simple stepper program tutorial the stepper runs just fine. I added the enable to the tutorial code and enabled the step pulse high delay for both directions.

// testing a stepper motor with a Pololu A4988 driver board or equivalent
// on an Uno the onboard led will flash with each step
// this version uses delay() to manage timing

byte directionPin = 22;
byte stepPin = 23;
byte enablePin = 21;
int numberOfSteps = 100;
byte ledPin = 2;  // change for ESP32
int pulseWidthMicros = 20;  // microseconds
int millisbetweenSteps = 250; // milliseconds - or try 1000 for slower steps


void setup()
{

   Serial.begin(115200);
   Serial.println("Starting StepperTest");
   digitalWrite(ledPin, LOW);

   delay(2000);

   pinMode(directionPin, OUTPUT);
   pinMode(stepPin, OUTPUT);
   pinMode(enablePin, OUTPUT);
   pinMode(ledPin, OUTPUT);


   digitalWrite(directionPin, HIGH);
   digitalWrite(enablePin, LOW);
   for (int n = 0; n < numberOfSteps; n++)
   {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(pulseWidthMicros); // this line is needed for ESP32
      digitalWrite(stepPin, LOW);

      delay(millisbetweenSteps);

      digitalWrite(ledPin, !digitalRead(ledPin));
   }

   delay(3000);

   digitalWrite(directionPin, LOW);
   for (int n = 0; n < numberOfSteps; n++)
   {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(pulseWidthMicros); //  this line is needed for ESP32
      digitalWrite(stepPin, LOW);

      delay(millisbetweenSteps);

      digitalWrite(ledPin, !digitalRead(ledPin));
   }
}

void loop()
{
}

Do not forget to set the driver's current limit. Instructions to do so are in the Pololu page (with video).

*my motor has a nasty resonance at 200 steps per second in single step mode. Microstepping minimizes the problem.

1 Like



//Arduino
//const int dirPinX = 4;
//const int stepPinX = 5;
//const int dirPinY = 2;
//const int stepPinY = 3;

//ESP32
const int dirPinX = 4;
const int stepPinX = 16;
const int dirPinY = 15;
const int stepPinY = 2;

//----------------------------ONCE---------------------------- 
void setup()
{
  Serial.begin(9600);
  while (!Serial);    // Needed for native USB port only, wait for serial port to connect.

  pinMode(stepPinX, OUTPUT);
  pinMode(dirPinX, OUTPUT);  
  pinMode(stepPinY, OUTPUT);
  pinMode(dirPinY, OUTPUT);
  
}

//----------------------------LOOP---------------------------- 
void loop()
{
  stepX();
}

void stepX()
{
  // Set motor direction clockwise
  digitalWrite(dirPinX, HIGH);

  digitalWrite(stepPinX, HIGH);
  delayMicroseconds(5);
  digitalWrite(stepPinX, LOW);
  delayMicroseconds(5);
}

Thanks GroundFungus.

This one works:

// This version uses delay() to manage timing.

byte directionPin = 4;
byte stepPin = 16;
//byte enablePin = 21;
//byte ledPin = 2;  // change for ESP32

int numberOfSteps = 400;
int pulseWidthMicros = 20;
int millisbetweenSteps = 5;


void setup()
{

   Serial.begin(115200);
//   digitalWrite(ledPin, LOW);
   delay(500);

   pinMode(directionPin, OUTPUT);
   pinMode(stepPin, OUTPUT);
//   pinMode(enablePin, OUTPUT);
//   pinMode(ledPin, OUTPUT);

   digitalWrite(directionPin, HIGH);
//   digitalWrite(enablePin, LOW);
   
   for (int n = 0; n < numberOfSteps; n++)
   {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(pulseWidthMicros); // probably unnecessary
      digitalWrite(stepPin, LOW);

      delay(millisbetweenSteps);

//      digitalWrite(ledPin, !digitalRead(ledPin));
   }

   delay(3000);

   digitalWrite(directionPin, LOW);
   for (int n = 0; n < numberOfSteps; n++)
   {
      digitalWrite(stepPin, HIGH);
      // delayMicroseconds(pulseWidthMicros); // probably not needed
      digitalWrite(stepPin, LOW);

      delay(millisbetweenSteps);

//      digitalWrite(ledPin, !digitalRead(ledPin));
   }
}

void loop(){}

I'm not sure what's wrong with the other minimal program and my much larger sketch, but at least I have piece of mind the hardware works!

digitalWrite(stepPinX, HIGH);
  delayMicroseconds(5);
  digitalWrite(stepPinX, LOW);
  delayMicroseconds(5);

The steps are much much much to fast (100,000 steps per second) to start the stepper from a dead stop. 4,000 steps is about the max for many motors and will need acceleration to get there.

The motor needs to have accelerations to reach high speeds. I would expect the motor to just buzz if anything.

The time the pulse is held high is fine (5us). I tried 1us and it worked.

The time that the pulse is held low determines the speed. Try some more reasonable delays there. On the order of, say, 50 milliseconds and go down till it starts missing steps. If you want to go faster, use the AccelStepper library and enable acceleration.

There is a gear ratio. Why do those delays work work for the Uno, but not the ESP32?

 digitalWrite(stepPinX, HIGH);
  delayMicroseconds(50);
  digitalWrite(stepPinX, LOW);
  delayMicroseconds(50);

and

 digitalWrite(stepPinY, HIGH);
  delayMicroseconds(50);
  digitalWrite(stepPinY, LOW);
  delayMicroseconds(50);

Does not work...

  delayMicroseconds(5000);

Doesn't work either.

Well. The clockwise

 digitalWrite(dirPinX, HIGH);

works. This sketch does the same when it should go in the opposite direction:

//Arduino
//const int dirPinX = 4;
//const int stepPinX = 5;
//const int dirPinY = 2;
//const int stepPinY = 3;

//ESP32
const int dirPinX = 4;
const int stepPinX = 16;
const int dirPinY = 15;
const int stepPinY = 2;

//----------------------------ONCE---------------------------- 
void setup()
{
  Serial.begin(9600);
  while (!Serial);    // Needed for native USB port only, wait for serial port to connect.

  pinMode(stepPinX, OUTPUT);
  pinMode(dirPinX, OUTPUT);  
  pinMode(stepPinY, OUTPUT);
  pinMode(dirPinY, OUTPUT);
  
}

//----------------------------LOOP---------------------------- 
void loop()
{
  stepX();
}

void stepX()
{
  // Set motor direction (should go counter clockwise)
  digitalWrite(dirPinX, LOW);

  digitalWrite(stepPinX, HIGH);
  delayMicroseconds(50);
  digitalWrite(stepPinX, LOW);
  delayMicroseconds(50);
}

adamelli:
Well. The clockwise

 digitalWrite(dirPinX, HIGH);

works. This sketch does the same when it should go in the opposite direction:

I can't help feeling that anything that works is doing so by luck.

You are trying to make the motor make one step every 100 microsecs. That is 10,000 steps per second which completely unrealistic without using acceleration to get the motor up to speed.

Start with a slower speed - say 100 steps per second. If that works then try increasing the speed gradually until you get to the point where the motor starts missing steps.

Have a look at the second example in this Simple Stepper Code. Just note that, because you are using an ESP32 (which is much faster then an Arduino Uno) that you need to add the line delayMicroseconds(10); between the HIGH and LOW of the pulse - like this

void singleStep() {
    if (curMillis - prevStepMillis >= millisBetweenSteps) {
            // next 2 lines changed 28 Nov 2018
        //prevStepMillis += millisBetweenSteps;
        prevStepMillis = curMillis;
        digitalWrite(stepPin, HIGH);
        delayMicroseconds(10);
        digitalWrite(stepPin, LOW);
    }
}

...R

...

...R

//Arduino
//const int dirPinX = 4;
//const int stepPinX = 5;
//const int dirPinY = 2;
//const int stepPinY = 3;

//ESP32
const int dirPinX = 4;
const int stepPinX = 16;
const int dirPinY = 15;
const int stepPinY = 2;

//----------------------------ONCE---------------------------- 
void setup()
{
  Serial.begin(9600);
  while (!Serial);    // Needed for native USB port only, wait for serial port to connect.

  pinMode(stepPinX, OUTPUT);
  pinMode(dirPinX, OUTPUT);  
  pinMode(stepPinY, OUTPUT);
  pinMode(dirPinY, OUTPUT);
  
}

//----------------------------LOOP---------------------------- 
void loop()
{
  for(int i = 0; i < 1000; i++)
    stepX();
  delay(1000);
  for(int i = 0; i < 1000; i++)
    stepXneg();
  delay(1000);
    
}

void stepX()
{
  digitalWrite(dirPinX, HIGH);

  digitalWrite(stepPinX, HIGH);
  delayMicroseconds(500);
  digitalWrite(stepPinX, LOW);
  delayMicroseconds(500);
}
void stepXneg()
{
  digitalWrite(dirPinX, LOW);

  digitalWrite(stepPinX, HIGH);
  delayMicroseconds(500);
  digitalWrite(stepPinX, LOW);
  delayMicroseconds(500);
}

Works fine. Thanks. Although, my bigger program still doesn't work with that same delay. One thing I don't understand:

one step every 100 microsecs. That is 10,000 steps per second

How did this work on the Uno and Mega?

Has anyone considered using the ESP32's MCPWM to run the stepper motor?

The MCPWM is a self contained module, that does not require CPU intervention to do its thing.
MCPWM API Motor Control Pulse Width Modulator (MCPWM) - ESP32 - — ESP-IDF Programming Guide latest documentation.

I use the MCWPM in an Arduino IDE sketch for a solar tracking project using servo motors.

Hi,


Sorry, but please draw a usable and serviceable schematic.
This may be okay for PCB development but is useless for trouble shooting.
Please draw a schematic that JOINS ALL the connections and includes power supply any other electronically connected hardware and the stepper motor.
Sorry but this may mean some thought about layout on the page.

Thanks.. Tom... :slight_smile:

It's a 12 V power supply as it says "12V" and "12VGND". The ESP32 dev board is connected to the PC via micro-USB for now.

It wouldn't provide any new information to create a schematic with wires instead of net labels. The problem has nothing to do with the hardware. Last, I'm not going to make a Fritzing diagram in the place of AutoDesk EAGLE:

Hi,
[soapbox]
Sorry but if you want to make a user serviceable schematic, not a PCB manufacturer schematic, then wiring will make it easier to read your circuit.
I call these circuits "Search a Word" schematics.
For example where does net 16 on the ESP32 go?
You have to go searching for other net 16 labels and you do not know how many there are, so you have to search the entire schematic to find ALL its connections.
Sorry but designers very rarely think that their designs will fail, or refuse to work in the first place and so time is wasted tracing "Search a Word" schematics.
[\soapbox]
Your schematic has no labels showing stepper connections or the stepper and no power supply hardware.

I'm glad you got your project working, however you may have to go back to previous versions of your code to find where you lost the stepper control.

You did write your code in stages and get each stage working before combining each stage one at a time and completed debugging before adding the next stage? ?

Tom.... :slight_smile:

It's an extremely basic schematic where only four terminals are relevant. Creating an artsy schematic will accomplish nothing.