Stepper motor turns only one direction when using Nodemcu

I am using a Nema 23 Stepper with a DM542T driver and it works fine on an Arduino Uno (spins both clockwise and counter-clockwise. However, when I use the same script on my Nodemcu it only spins one direction. What is the difference in the pins on the Uno vs the Nodemcu that would be causing this? I've also tried and ESP32 but have same issue. Is it something to do with attachinterrupt enabled on the Uno but not the Nodemcu? Here's the sketch:

#include <Stepper.h>

const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 7, 6);
//Changing the pins to (stepsPerRevolution, D4, D3) on the Nodemcu only spins the motor in one direction.

void setup() {
  // set the speed at 60 rpm:
  // initialize the serial port:

void loop() {
  // step one revolution  in one direction:

  // step one revolution in the other direction:

The DM542T driver supports a pulse/dir interface and not the phase sequencing generated by stepper.h

See this simple demonstration code from Robin2 about how to run a pulse/dir motor driver without the use of a library.

The mystery to me is why the code using stepper.h worked with the DM542T on a Uno.

Th ESP8266 nodeMCU and ESP32 are 3,3V devices. It might be that this voltage is just not sufficient for the control-input of the driver.

Do you have the GND of the microcontroller connected to GND of the driver?

What IO-pins of the nodeMCU/ESP32 did you use? Some of them have pull-up / some of them do have a pull-down-resistor.

In the program the instance is created with three parameters

I assume creating it with three parameters tells stepper.h it is a pulse/dir-interface.
from where should the library know which are the third and forth IO-pin for direct phase-sequencing?

best regards Stefan

I don't think so. Check out the Stepper.h source code. When a two pin constructor is given, there is a step sequence of 4 with the two pins.

void Stepper::step(int steps_to_move)
  int steps_left = abs(steps_to_move);  // how many steps to take

  // determine direction based on whether steps_to_mode is + or -:
  if (steps_to_move > 0) { this->direction = 1; }
  if (steps_to_move < 0) { this->direction = 0; }

  // decrement the number of steps, moving one step each time:
  while (steps_left > 0)
    unsigned long now = micros();
    // move only if the appropriate delay has passed:
    if (now - this->last_step_time >= this->step_delay)
      // get the timeStamp of when you stepped:
      this->last_step_time = now;
      // increment or decrement the step number,
      // depending on direction:
      if (this->direction == 1)
        if (this->step_number == this->number_of_steps) {
          this->step_number = 0;
        if (this->step_number == 0) {
          this->step_number = this->number_of_steps;
      // decrement the steps left:
      // step the motor to step number 0, 1, ..., {3 or 10}
      if (this->pin_count == 5)
        stepMotor(this->step_number % 10);
        stepMotor(this->step_number % 4);

void Stepper::stepMotor(int thisStep)
  if (this->pin_count == 2) {
    switch (thisStep) {
      case 0:  // 01
        digitalWrite(motor_pin_1, LOW);
        digitalWrite(motor_pin_2, HIGH);
      case 1:  // 11
        digitalWrite(motor_pin_1, HIGH);
        digitalWrite(motor_pin_2, HIGH);
      case 2:  // 10
        digitalWrite(motor_pin_1, HIGH);
        digitalWrite(motor_pin_2, LOW);
      case 3:  // 00
        digitalWrite(motor_pin_1, LOW);
        digitalWrite(motor_pin_2, LOW);

The ESP8266 nodeMCU and ESP32 are 3,3V devices. It might be that this voltage is just not sufficient for the control-input of the driver.

This is a very good point. The specs for the driver indicate that the pulse needs to be 4-5v.

I have the Dir+ and Pul+ pins routed to an Arduino Uno to supply 5 volts but still same results.

What the code of the stepper.-library does show is:
it is not a step/direction interface because the two IO-pins are switched in a sequencing manner 01, 11, 10, 00

a step/direction-interface would just toggle the one single IO-pin (the step-pin) LOW/HIGH
Both IO-pins are switched LOW/HIGH

this is that part of the code that does the IO-pin switching.

For driving steppers I would recommend the MoBaTools-library

In contrast to a lot of other libraries the documentation of the mobatools is good

best regards Stefan

Here is the mobaTools stepper example 3

////////// Example 3 for MoToStepper - attaching a bipolar stepper with step/dir and enable ////////////

/*  Example for the control of a bipolar stepper with 4 buttons and a potentiometer ( for the speed ).
    In this example, besides the stepper class (MoToStepper), the classes MoToButtons and MoToTimebase 
    are also used.
    The stepper current is switched off, if the stepper is not moving.
    The buttons must switch to Gnd, no resistors are needed.
    Button1: Rotates right as long as the button is pressed and held
    Button2: Rotates left as long as the button is pressed and held
    Button3: One turn to the right
    Button4: One turn to the left

/*  Beispiel für die Ansteuerung eines bipolaren Steppers über 4 Taster und 
    ein Poti ( für die Geschwindigkeit )
    In diesem Beispiel werden neben der Stepperklasse (MoToStepper), auch die MoToButtons
    und der MoToTimebase genutzt.
    Der Spulenstrom wird abgeschaltet, wenn der Stepper nicht läuft.
    Die Taster müssen gegen Gnd schalten, es sind keine Widerstände notwendig 
    Button1:  Dreht rechts, solange Taster gedrückt
    Button2:  Dreht links, solange Taster gedrückt
    Button3:  1 Umdrehung rechts
    Button4:  1 Umdrehung links

#define MAX8BUTTONS // spart Speicher, da nur 4 Taster benötigt werden (saves RAM)
#include <MobaTools.h>
// Pindefinitions - change to your needs
const byte dirPin       = 5;
const byte stepPin      = 6;
const byte enaPin       = 7;
const byte button1Pin   = A1;
const byte button2Pin   = A2;
const byte button3Pin   = A3;
const byte button4Pin   = A4;

const byte potPin       = A0;   // must be an analog input

const int STEPS_REVOLUTION = 800;
//Stepper einrichten ( 800 Schritte / Umdrehung - 1/4 Microstep )
MoToStepper myStepper( STEPS_REVOLUTION, STEPDIR );  // 800 Steps/ Umdrehung

// Taster einrichten 
enum { Button1=0, Button2, Button3, Button4 } ; // Den Tasternamen die Indizes 0...3 zuordnen
const byte buttonPins[] = { button1Pin, button2Pin, button3Pin, button4Pin };    // muss als byte definiert sein, damit ein enfaches sizeof funktioniert
MoToButtons button( buttonPins, sizeof(buttonPins), 20, 500 );

MoToTimebase speedIntervall;    // Zeitinterval zum Auslesen des Speedpotentiometers
                                // the speed pot ist read only every 'speedintervall' ms

int vspeed = 0;                 //Steppergeschwindigkeit in U/min*10

void setup()
  myStepper.attach( stepPin, dirPin );
  myStepper.attachEnable( enaPin, 10, LOW );        // Enable Pin aktivieren ( LOW=aktiv )
  myStepper.setSpeed( 200 );
  myStepper.setRampLen( 100 );                       // Rampenlänge 100 Steps bei 20U/min
  speedIntervall.setBasetime( 100 );                  // 100ms Tickerzeit

void loop() {
  button.processButtons();          // Taster einlesen und bearbeiten

  // Speed alle 100ms neu einlesen und setzen
  if ( speedIntervall.tick() ) {
    // wird alle 100ms aufgerufen ( Tickerzeit = 100ms im setup() )
    vspeed = map((analogRead(potPin)), 0, 1023, 20, 1800);  //Poti mappen auf 2 ... 180 Umdr/Min
    //min speed =2 and max speed =180 rpm
    myStepper.setSpeed( vspeed );

  // Drehen rechtsrum
  if (button.pressed(Button1) ) {
    //Taster1 gedrückt
    myStepper.rotate( 1 );          // Stepper dreht vorwärts
  if ( button.released(Button1) ) {
    //Taster1 losgelassen
    myStepper.rotate(0);             // Stepper stoppt

  //Drehen linksrum
  if (button.pressed(Button2) ) {
    //Taster2 gedrückt
    myStepper.rotate( -1 );         // Stepper dreht rückwärts
  if ( button.released(Button2) ) {
    //Taster2 losgelassen 
    myStepper.rotate(0);            // Stepper stoppt

  // 1 Umdrehung rechts {
  if (button.pressed(Button3) ) {
    //Taster3 wurde gedrückt

  // 1 Umdrehung links 
  if (button.pressed(Button4) ) {
    //Taster4 wurde gedrückt

best regards Stefan

I am using a Nema 23 Stepper with a DM542T driver and it works fine on an Arduino Uno (spins both clockwise and counter-clockwise.

Please explain. Does the posted code work to rotate the motor in both directions with a Uno or not?

Did you try a Uno without using Stepper.h but instead the simple step/dir code from Robin2's posting or from StefanL38's link?

To clarify, yes, the original code posted does turn the motor both directions when used with an Arduino Uno when Pul+ and Dir+ on the motor driver are connected to 5V and Pul- and Dir- are connected to 6 & 7 on the Uno.
I understand that Pul+ and Dir+ require 5v. So, I keep these pins connected to an Uno for power and switch the 6, 7 pins to an ESP8266 (D3, D4) but it only goes in one direction (clockwise) although it is turning. I have tried Robin2 script but still one direction. I have also tried connecting the ground of the DM542T to the ground on the ESP8266 as mentioned but that didn't work. I've also tried switching to other pins on the ESP8266 (D5, D6) for example, but regardless of what I do, I cannot get it to turn counter clockwise. I have also tried the AccelStepper library - it works well with the Uno only, but not with the ESP8266 or ESP32 - turns but only one direction.

the problem is the step-input and the dir-input of the driver need to see minimum 4V.
Any IO-pin of any ESP (ESP8266, ESP32 ) can "deliver" a maximum of 3.3V
These 3.3V are too less for the DM542T-driver-inputs to switch HIGH.
at 3.3V the DM542T still sees a LOW.

So you need a voltage-level converter 3.3V up to 5V
The minimum circuit for only outputting a signal looks like this

Those modules can do both direction input/output
3.3V ----->to-------> 5V
5V ----->to-----> 3.3

best regards Stefan

Thank you Stefan for the explanation. I have ordered these and will report back - DAOKI 2 Channel Logic Level Converter 3.3V to 5V TTL Bi-directional Module

Pin current capability is also and issue.

This has AFAIK been a topic several times on this forum.
Connect the opto +5volt inputs of the drivers to 5volt,
and use transistors (2N2222 with 330 ohm base resistor) to switch the other side of the opto to ground.

I received my logic level shifter today and tested. It works!!! Thanks very much. I have spent many hours trying to resolve this.