How to run two stepper motors simultaneously?

How to run two stepper motors simultaneously with CNC shield mounted along with drivers A4988 using Nucleo f767zi. I can run them consecutively i.e one after another but not able to run both at a time. I have tried single-stepping but it didn’t give us favourable results. Are there any libraries that can make two-steppers running simultaneously?

Thanks.

Hello,

One way could be to use Mbed’s PortOut API to control the A4988 stepper drivers.

For example:

Wiring

-------------------------------------
 NUCLEO_F767ZI | A4988 #0 | A4988 #1
-------------------------------------
     PD_4      |   STEP   |    
     PD_5      |   DIR    |
     PD_6      |          |   STEP
     PD_7      |          |   DIR
-------------------------------------

Code

...

#define STEP0  4  // step pin position of stepper #0 within selected port
#define DIR0   5  // direction pin position of stepper #0 within selected port
#define STEP1  6  // step pin position of stepper #1 within selected port
#define DIR1   7  // direction pin position of stepper #1 within selected port
#define MASK   ((1 << STEP0) | (1 << DIR0) | (1 << STEP1) | (1 << DIR1))

PortOut portOut(PortD, MASK);  // use pins PD_4, PD_5, PD_6, PD_7 as parallel port

...

/**
 * @brief  Make one step with both steppers simultaneously
 * @note
 * @param step0: If true then rotate stepper #0 one step. Otherwise don't rotate.
 * @param dir0 : If false then stepper #0 rotation will be clockwise else counter clockwise
 * @param step1: If true then rotate stepper #1 one step. Otherwise don't rotate.
 * @param dir1 : If false then stepper #1 rotation will be clockwise else counter clockwise
 * @retval
 */
void step(bool step0, bool dir0, bool step1, bool dir1)
{
    int steps = (step0 << STEP0) | (step1 << STEP1); // bitwise OR
    int dirs = (dir0 << DIR0) | (dir1 << DIR1);      // bitwise OR

    portOut = 0;               // reset all port pins
    portOut = dirs;            // set direction pins prior to step pins
    wait_us(2);                // LOW pulse width
    portOut = portOut | steps; // set step pins
    wait_us(2);                // HIGH pulse width
    portOut = 0;               // reset all port pins
}
...

Another method could use the BusOut API. That allows to combine pins from various ports into a common bus but at a cost of considerable slower write operation than in case of a PortOut.

Best regards, Zoltan

@hudakz We have tried running the code below with two stepper motors with A4988, but they are stuttering. They are only making a few micro steps only when we wiggling them. We have checked for loose connections but they aren’t. With the same connections, we tried another code they are working fine.
Thanks

#include “PortNames.h”
#include “mbed.h”
#include “platform/mbed_thread.h”

#define STEP0 PD_4 // step pin position of stepper #0 within selected port
#define DIR0 PD_5 // direction pin position of stepper #0 within selected port
#define STEP1 PD_6 // step pin position of stepper #1 within selected port
#define DIR1 PD_7 // direction pin position of stepper #1 within selected port
#define MASK ((1 << STEP0) | (1 << DIR0) | (1 << STEP1) | (1 << DIR1))

PortOut portOut(PortD, MASK); // use pins PD_4, PD_5, PD_6, PD_7 as parallel port

int step0;
int step1;
int dir0;
int dir1;

void step(bool step0, bool dir0, bool step1, bool dir1)
{
int steps = (step0 << STEP0) | (step1 << STEP1); // bitwise OR
int dirs = (dir0 << DIR0) | (dir1 << DIR1); // bitwise OR

portOut = 0;               // reset all port pins
portOut = dirs;            // set direction pins prior to step pins
wait_us(2);                // LOW pulse width
portOut = portOut | steps; // set step pins
wait_us(2);                // HIGH pulse width
portOut = 0;               // reset all port pins

}
int main()
{
step(true,true,true,true);
}

Although according to the A4988 datasheet the minimum pulse with is 1 microsecond, in real life it should be probably longer. Try 8 milliseconds, as in this example, or similar:

...
wait_us(8000);                // LOW pulse width
portOut = portOut | steps;    // set step pins
wait_us(8000);                // HIGH pulse width
...

NOTE: To display formatted code in your post put a line containing three back-ticks (```) at the begin and end of the code section.

Hello @hudakz,
We have tried changing the pulse either way but it’s happening the same way as mentioned before.
Thanks

what is the stepping frequency? The example shows just a single step.
The pulsewidth with a few microseconds is ok.

Full Stepping
This is the code we used.

/* mbed Microcontroller Library
 * Copyright (c) 2019 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 */
#include "PortNames.h"
#include "mbed.h"
#include "platform/mbed_thread.h"


#define STEP0  PD_4  // step pin position of stepper #0 within selected port
#define DIR0   PD_5  // direction pin position of stepper #0 within selected port
#define STEP1  PD_6  // step pin position of stepper #1 within selected port
#define DIR1   PD_7  // direction pin position of stepper #1 within selected port
#define MASK   ((1 << STEP0) | (1 << DIR0) | (1 << STEP1) | (1 << DIR1))

PortOut portOut(PortD, MASK);  // use pins PD_4, PD_5, PD_6, PD_7 as parallel port

int step0;
int step1;
int dir0;
int dir1;

/**
 * @brief  Make one step with both steppers simultaneously
 * @note
 * @param step0: If true then rotate stepper #0 one step. Otherwise don't rotate.
 * @param dir0 : If false then stepper #0 rotation will be clockwise else counter clockwise
 * @param step1: If true then rotate stepper #1 one step. Otherwise don't rotate.
 * @param dir1 : If false then stepper #1 rotation will be clockwise else counter clockwise
 * @retval
 */
void step(bool step0, bool dir0, bool step1, bool dir1)
{
    int steps = (step0 << STEP0) | (step1 << STEP1); // bitwise OR
    int dirs = (dir0 << DIR0) | (dir1 << DIR1);      // bitwise OR

    portOut = 0;               // reset all port pins
    portOut = dirs;            // set direction pins prior to step pins
    //wait_us(8000);                // LOW pulse width
    wait(0.008);
    portOut = portOut | steps; // set step pins
    //wait_us(8000);                // HIGH pulse width
    wait(0.008);
    portOut = 0;               // reset all port pins
}
int main()
{
    step(true,true,true,true);
}

this is still a single step. main starts, produces one step and finishes.
You need a loop for a continous movement:

The motors are rotating with both codes mentioned above, but the motor speed is the same irrespective of changing from wait(0.008) to wait(0.001)

  portOut = dirs;            // set direction pins prior to step pins
 wait(0.008);
  portOut = portOut | steps; // set step pins
 wait(0.008);
  portOut = 0;
    portOut = dirs;            // set direction pins prior to step pins
   wait(0.001);
    portOut = portOut | steps; // set step pins
   wait(0.001);
    portOut = 0;

but where is a loop for generating the steps? step() produces one pule and is called once in main. When the A4988 gets one pulse, it makes one step, not more.
So you may have some motor movement because of undefined outputs, but not controlled by the software.

This code is working but not able to modify speeds irrespective of changing wait time from 0.008 to 0.001

/* mbed Microcontroller Library
 * Copyright (c) 2019 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 */
#include "PortNames.h"
#include "mbed.h"
#include "platform/mbed_thread.h"


#define STEP0  PD_4  // step pin position of stepper #0 within selected port
#define DIR0   PD_5  // direction pin position of stepper #0 within selected port
#define STEP1  PD_6  // step pin position of stepper #1 within selected port
#define DIR1   PD_7  // direction pin position of stepper #1 within selected port
#define MASK   ((1 << STEP0) | (1 << DIR0) | (1 << STEP1) | (1 << DIR1))

PortOut portOut(PortD, MASK);  // use pins PD_4, PD_5, PD_6, PD_7 as parallel port

int step0;
int step1;
int dir0;
int dir1;

/**
 * @brief  Make one step with both steppers simultaneously
 * @note
 * @param step0: If true then rotate stepper #0 one step. Otherwise don't rotate.
 * @param dir0 : If false then stepper #0 rotation will be clockwise else counter clockwise
 * @param step1: If true then rotate stepper #1 one step. Otherwise don't rotate.
 * @param dir1 : If false then stepper #1 rotation will be clockwise else counter clockwise
 * @retval
 */
void step(bool step0, bool dir0, bool step1, bool dir1)
{
    int steps = (step0 << STEP0) | (step1 << STEP1); // bitwise OR
    int dirs = (dir0 << DIR0) | (dir1 << DIR1);      // bitwise OR

    portOut = 0;               // reset all port pins
    portOut = dirs;            // set direction pins prior to step pins
    //wait_us(8000);                // LOW pulse width
    wait(0.008);
    portOut = portOut | steps; // set step pins
    //wait_us(8000);                // HIGH pulse width
    wait(0.008);
    portOut = 0;               // reset all port pins
}

   int main()
{
    while(true) {
        step(true,true,true,true);
        wait_us(10000); // 10 ms
    }

}

then the frequency / speed depends on the wait_us(10000) of course. in the step() function, the wait_us(2) was ok, the pulses doesn’t need to be longer.