Stepper Motor Driver for A4988 and Similar Devices

by Gilissen Erno in Circuits > Arduino

714 Views, 3 Favorites, 0 Comments

Stepper Motor Driver for A4988 and Similar Devices

Screenshot 2023-08-01 131037.png

This software can drive up to 4 stepper motor(s) using a A4988 driver or similar device that generates stepper motor pulses. The A4988 is an integrated driver that basically requires a direction and step inputs to control the motor.

This driver can control up to one (Arduino Uno) or 4 (Arduino Mega 2560) motors.

Different vs. my other stepper motor driver (L298 Motor Shield Interrupt Driven).

  • The A4988 has internal hardware to drive the motor steps in 1, 1/2, 1/4, 1/8 or 1/16th of a motor step.
  • Interrupts are only required if the motor must be stopped after reaching a certain position.
  • The Arduino AVR core is completely free to run other software while the motor(s) are spinning. The hardware AVR timers - once configured - provide for accurate step timing regardless of other software running.
  • There is virtually no so called overhead on driving the motor(s). The main function will almost never be delayed because of motor step pulses (only if motor stop position is used, to count the actual step / postion).
  • The A4988 requires two Timer Output Compare Matches for a single transition on the STEP pin. As a result, the step rate is 50% of my other driver. Since no stepper motor can follow the maximal step rate possible, this still makes slower stepping possible using this driver.

Supplies

  • Arduino Uno or Mega 2560
  • A4988 Stepper Motor controller or compatible.
  • Power Supply (ex. 12V for stepper motor and 5V for the Arduino)
  • Bipolar Stepper motor compatible with A4988.

Hardware

Screenshot 2023-08-01 131801.png

As shown in above image, the A4988 or similar device interfaces between the microcontroller - in our case an Arduino Uno or Mega 2560 - and the stepper motor.

The most important A4988 inputs:

  • MS1 ... MS3: select the step size (full, 1/2, 1/4,... 1/16th of a step). See above image
  • DIR: motor direction (application specific).
  • STEP: for every rising edge, an "MSx" controlled step is generated on the motor coils (ex. 1/4th step).

The Outputs OUT1A/B and OUT2A/B drive the two motor coils.

Software

Screenshot 2023-08-01 133125.png

Similar to my other stepper motor driver, the hardware timers are used to drive the motor. Above images shows how the software is built around the hardware:

  • The main oscillator is assumed to be 16MHz (other clock rates can be used as well).
  • The AVR CLKPR register allows to divide the 16MHz by certain values (consult datasheet if interested). In this case / most common Arduino use, the division is 1 so it has no effect.
  • The resulting value is divided by the Timer prescaler (see my other driver for more info).
  • Finally, every time the Timer counts out, it inverts the timer output that is connected to the STEP input pin. This must be D9 for Uno, D11, D5, D6 or D46 for Mega 2560 since these pins are hardwired by chip design.
  • The AVR also has 8bit timers, like Timer 2, these are not used because they limit the minimal RPM (with minor changes to existing code, such timer might be used as well. On request I might provide such code).

The driver use is very similar to my previous stepper motor driver AVR L298 Motor Interrupt Driven Stepper Motor (have a look there if things are not 100% clear since there it's explained more detailed).

Driver Configuration

Screenshot 2023-08-01 134345.png

Above statements must be used when adding the driver to your project. Note on a Uno, TIMER 3, 4 and 5 are not available. Suppose you have a Mega2560 and you only need 2 motors, connected to Timer 3 and Timer4 outputs, comment out the defines related to the other 2 timers. These timers can still be used by other libraries / implementations.

Why the Driver Has a Timer Update Sync

Screenshot 2023-08-01 133653.png

One should keep in mind the driver configures hardware that runs independent from the software. Once a certain motor speed is programmed and the user wants to change this speed, the hardware may be in a state that is invalid for the updated configuration (ex. the Timer has already surpassed the newly updated overflow value). As a result, weird stepping frequency may be seen on the output (see above).

Therefore, the timer update function has an automatic Sync feature. If the timer is already running, Sync is set. This will force the driver to wait for the Timer hardware till it has toggled the motor STEP pin and right after, re-configures the hardware. When a motor is started from a stopped position / timer, there is no requirement to wait (aka sync) and the function will return faster (worst case, changing the motor speed requires ~50% of the duration of a step pulse).

MotorTimerRPMtoTimerTop32 (float Rpm, Unsigned Int Steps_s);

Screenshot 2023-08-01 134648.png

MotorTimerGetIOclocksPerSecond ()

Returns an unsigned long that reflects the amount of IO Clocks that are input to the Timer prescaler register. This function can be used for all motors, since the 4 possible timers share the same base clock and it only involves a calculation.

StepMotorInit ()

Initializes all output pins & timer functions for all enabled Timers (there's only one function to initialize all motors at once). The above #define from Step 3 are taken into account for setting the proper output pins. The return parameter is (signed) char: any negative value is an error, zero means no error. Positive is used as indicator.

Functions to Drive the Motor

Screenshot 2023-08-01 142513.png

stepMotor?SetStepMode (MOTORSTEPSELECTION sl)

Step Selection can be any of the step sizes supported by the A4988.

  • MOTORSTEP_FULL
  • MOTORSTEP_HALF
  • MOTORSTEP_QUARTER
  • MOTORSTEP_EIGHT
  • MOTORSTEP_SIXTEENTH

Writes the desired mode to the A4988_x_MS1 /2/3 pins. The return parameter is (signed) char: any negative value is an error, zero means no error. Positive is used as indicator. The A4988 pins are only driven when defined. If the driver has no access to these A4988 MSx pins, the user is responsible to hard-wire these A4988 pins and only select the modes that matches the hardware configuration.

stepMotor?Direction (uint8_t dl)

Sets the A4988 direction pin (0 if dl is 0x00, 1 in all other cases).

stepMotor?TimerUpdate (uint32_t timTop32)

This function updates the AVR hardware Timer top register.

StepMotor?Status

The return value:

  • -2 = A4988 is not enabled (ENABLE pin inactive; only when pin is defined).
  • -1 = A4988 is sleeping (SLEEP pin active; only when pin is defined).
  • 0 = A4988 enabled, motor stopped.
  • 1 =A4988 enabled, motor stopped because end position is reached.
  • 10 = A4988 enabled, motor spinning.

Motor Position Functions

stepMotor?EndPointEnable (int32_t endpoint)

  • For every full step the motor has taken, a position counter is incremented if the A4988 DIR pin is 0. Similar, the counter is decremented when the A4988 DIR pin is 1. If the motor is configured for 1/4 steps, a total of 4 STEP pulses must be sent to the A4988 before this internal counter is updated.
  • The endpoint allows to stop sending STEP pulses to the A499 when the present position counter matches the endpoint value. The user is responsible to make sure the programmed endpoint can be reached (taking into account if the internal counter counts up or down). Note calling the A4988 reset function also clears this internal motor position counter.
  • For instance, if the motor drives a linear stage at 0.01mm/step, it's 31.23cm away from the start position if the position counter is 3123 (or -3123 depending on the DIR pin).

stepMotor?EndPointDisable ()

  • Disables above endpoint detection. The motor must be stopped by software.

stepMotor?GetPosition ()

  • Returns the actual position counter since the last A4988 reset.

Other Controlling Functions

  • stepMotor?Sleep ()
  • stepMotor?WakeUp ()
  • stepMotor?DriverEnable ()
  • stepMotorxDriverDisable ()
  • stepMotor?Reset ()

Sleep or Driver Enable can be used to prevent the A4988 from overheating. Reset will erase the position counter and disables STEP pulses to the A4988 (the A4988_?_RESET digital I/O must be defined for this function to perform this)

How the AVR Timer Is Used

Screenshot 2023-08-01 133422.png

Above image shows the AVR IO Timer registers that are used by the driver (gray bits are not used). The user has to make sure these timer(s) are not used by other libraries used in the same project. The Mega AVR2560 has 3 extra timers vs. the Arduino Uno. This driver combined with libraries intended for the Uno ensures Timers 3, 4 or 5 are free to drive up to 3x A4988's.

Sources & Use Case Example