A4988 microstepping

Evening folks,

I am trying to run a tachometer from the CAN bus off a 1.8 turbo Golf (transplanted into a Corrado)

I have it working but I’m still not happy with it.

The stepper is the same used by VW in their golf 4 clusters (havent found the exact spec yet but appears to be 180 steps)
The stepper drive is an A4988 (cheap from UK ebay)
The CAN sheild is from sparkfun
Arduino board is a mega

As part of the motor setup the dial does a full sweep when switched on.
Full sweep (0 - 8000 rpm) takes 125 steps and I have set the driver to 1/16 so the sweep command is +2000 steps then -2000 steps. This makes me think the micro stepping works because it doesnt hit the stops.

But, when the program loop is running the needle moves every 65 rpm which looks like the driver is running 1/1 !

I need a bit of help to work out why it isnt micro stepping :slight_smile:

The code below is a cut down version of my full cluster display code but it does the same :frowning:

#include "Arduino.h"
#include <mcp_can.h>
#include "A4988.h"

const int SPI_CS_PIN = 53; //53 for the mega -- 10 (on uno )

/*********CAN masking and filters*******/
#define CAN_MASK_1 			0x81
#define CAN_MASK_2			0x81

#define TACHO				0x280

#define ACCEPT1				TACHO
#define ACCEPT2				0x000
#define ACCEPT3				0x000
#define ACCEPT4				0x000
#define ACCEPT5				0x000
#define ACCEPT6				0x000

#define MOTOR_STEPS 		180
#define RPM 				60
#define DIR 				8
#define STEP 				9
#define ENABLE 				13
#define MS1 				10
#define MS2 				11
#define MS3 				12
int MOTOR_ACCEL = 500; // Acceleration and deceleration values are always in FULL steps / s^2
int MOTOR_DECEL = 500;
#define MICROSTEPS 16// Microstepping mode 1/16
A4988 stepper(MOTOR_STEPS, DIR, STEP, ENABLE, MS1, MS2, MS3);

static void setUpCAN(void);
static void setUpStepper(void);
static void processRPM(const unsigned char MSB, const unsigned char LSB);
static void processCANMessage(void);

void setup() {

	Serial.begin(9600); //serial comms for USB

void loop() {

	if (CAN_MSGAVAIL == CAN.checkReceive())
	static void setUpCAN(void)
		/*setup CAN controller -- We need to light a LED or something if its stuck in this loop*/
		while (CAN_OK != CAN.begin(CAN_500KBPS))

		/* load CAN masks */
		CAN.init_Mask(0, 0, CAN_MASK_1);
		CAN.init_Mask(1, 0, CAN_MASK_2);
		/* load CAN acceptance filters */
		CAN.init_Filt(0, 0, ACCEPT1);
		CAN.init_Filt(1, 0, ACCEPT2);
		CAN.init_Filt(2, 0, ACCEPT3);
		CAN.init_Filt(3, 0, ACCEPT4);
		CAN.init_Filt(4, 0, ACCEPT5);
		CAN.init_Filt(5, 0, ACCEPT6);

	static void processCANMessage(void) {

		static uint16_t ID;
		unsigned char len = 0;
		unsigned char buf[8];
		/* there is data in the buffer so read it */
		CAN.readMsgBuf(&len, buf);
		/* Get the ID */
		ID = CAN.getCanId();
		/* now we can switch to process that data */

		switch (ID)

		case TACHO:
			processRPM(buf[3], buf[2]); //

	static void setUpStepper(void)
		stepper.begin(RPM, MICROSTEPS);
		stepper.setSpeedProfile(stepper.LINEAR_SPEED, MOTOR_ACCEL, MOTOR_DECEL);
		stepper.move(2000);    // forward revolution 16*125steps
		stepper.move(-2000);   // backward revolution to zero point


	static void processRPM(const unsigned char MSB, const unsigned char LSB)
		uint16_t EngineSpeed;
		uint16_t tacho;
		static uint16_t old_tacho = 0;
		int16_t result;

		EngineSpeed = (uint16_t) (((MSB << 8) + LSB)/4); //standard input scaled for VW cluster
		tacho = (uint16_t)(EngineSpeed)/4; //scaled for stepper motor
		result = tacho - old_tacho; //delta to move stepper motor
		stepper.move(result); //send to stepper
		old_tacho = tacho; //update tacho value

		Serial.println (result);

I have not come across a library called A4988.h previously. What does it do? Where does it come from?

If the micro-step pins on the A4988 board are correctly set it will microstep. There is no need for the Arduino code to do anything. You can control them with software but it is seldom necessary.

Stepper Motor Basics
Simple Stepper Code

Thanks for your answer

Typically, after putting this on here I thought about it a bit more and then adjusted down the current supply on the A4899 which seems to have improved it.

There is still a small amount of sudden jumps almost as if it sends a larger negative value so I would appreciate it if anyone has any suggestions to improve the code

The CAN message is being sent every 10ms, Is there a way to average the rpm over say 250ms then out put that ?

I got the A4988.h from github

Have you tried the AccelStepper library that is more widely used?


Sure. Wait for 25 CAN messages and then change your output to the average of what you got.

Typically, after putting this on here I thought about it a bit more and then adjusted down the current supply on the A4899 which seems to have improved it.

The current limit must be adjusted correctly for microstepping to work.

What motor and power supply are you using, and to what value did you set the current limit?