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?
...
#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.
@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
#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
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:
/* 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);
}
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.