Learn
Driving a Stepper Motor with an A4988 Driver on a Raspberry Pi 4B
Wire a stepper motor and an A4988 driver to a Raspberry Pi 4B, drive it with real STEP/DIR pulses, select a microstep resolution with MS1/MS2/MS3, and see what ENABLE, RESET, and SLEEP each actually do to the motor.
Note: the A4988 Stepper Driver is a VIP-tier component in the simulator — you’ll need a VIP plan to use it there.
Try this directly in the free Raspberry Pi 4B simulator — no hardware or signup required. New to the GPIO header? Start with the interactive pinout guide.
What you’ll need
- Raspberry Pi 4B
- A4988 Stepper Driver
- Stepper Motor
- DC Power Supply
Step by step
- Drag Raspberry Pi 4B, the A4988 Stepper Driver, the Stepper Motor, and a DC Power Supply onto the Canvas.
The driver is a real 16-pin breadboard-mounted module with two rows of 8 pins. The top row is the control side (all digital logic, wired to the Pi); the bottom row is the power/coil-output side. Hover over its pins to confirm the labels, left to right:
| Row | Pins, left to right |
|---|---|
| Top (control) | ENABLE, MS1, MS2, MS3, RESET, SLEEP, STEP, DIR |
| Bottom (power/output) | VDD, GND, 1B, 1A, 2A, 2B, VMOT, GND |
- Wire the motor's 4 coil leads (A-, A+, B+, B-) straight to the driver's matching coil-output pins:
| Stepper Motor pin | Driver pin |
|---|---|
| A- | 1B |
| A+ | 1A |
| B+ | 2A |
| B- | 2B |
- Power the logic side (this is what runs the chip's own internal control circuitry): VDD → a Pi power pin (3.3V or 5V), GND (the logic GND, next to VDD) → a Pi GND pin.
- Power the motor side (this is what actually drives the coils, and is a completely separate supply from VDD/GND above — real A4988 boards work exactly this way): VMOT → the DC Power Supply's + pin, GND (the second GND, next to VMOT) → the DC Power Supply's − pin.
- Wire STEP and DIR to two Pi GPIO pins you'll drive from your own script (e.g. physical pins 37 and 35).
Leave ENABLE, RESET, SLEEP, MS1, MS2, and MS3 unwired for now — a real A4988 board has onboard pull resistors, so a floating pin isn't undefined, it has a real default: ENABLE is pulled LOW (enabled/driving), SLEEP and RESET are both pulled HIGH (awake, not held in reset), and MS1/MS2/MS3 are all pulled LOW (000 = full step, 1.8° per pulse, 200 pulses per full revolution).
- Go to the Code tab and write a script that steps the motor one full revolution forward, then one full revolution back:
import RPi.GPIO as GPIOimport asyncio GPIO.setmode(GPIO.BOARD)STEP = 37 # adjust to match your wiringDIR = 35 # adjust to match your wiring GPIO.setup(STEP, GPIO.OUT)GPIO.setup(DIR, GPIO.OUT) GPIO.output(DIR, GPIO.HIGH) # forward for _ in range(200): # 200 full steps = one revolution at the default 1.8 deg/step GPIO.output(STEP, GPIO.HIGH) # each rising edge advances one microstep await asyncio.sleep(0.002) GPIO.output(STEP, GPIO.LOW) await asyncio.sleep(0.002) GPIO.output(DIR, GPIO.LOW) # reverse for _ in range(200): GPIO.output(STEP, GPIO.HIGH) await asyncio.sleep(0.002) GPIO.output(STEP, GPIO.LOW) await asyncio.sleep(0.002)- Click Start and watch the motor's shaft rotate — one full turn forward, then one full turn back.
- Now try microstepping: wire MS1 to a Pi power pin (a plain wire, no GPIO.output() needed — a hardwired MS pin works exactly like a floating one, just resolved to HIGH instead of the default LOW) to select half-step (2x). The same 200-pulse script above now only turns the shaft a quarter revolution, since each pulse now moves half as far.
| MS1 | MS2 | MS3 | Resolution | Degrees per pulse |
|---|---|---|---|---|
| LOW | LOW | LOW | Full step (1x) | 1.8° |
| HIGH | LOW | LOW | Half step (2x) | 0.9° |
| LOW | HIGH | LOW | Quarter step (4x) | 0.45° |
| HIGH | HIGH | LOW | Eighth step (8x) | 0.225° |
| any, with MS3 HIGH | — | HIGH | Sixteenth step (16x) | 0.1125° |
- Finally, try wiring ENABLE to a Pi GPIO pin and driving it HIGH from your script before the step loop (GPIO.setup(ENABLE_PIN, GPIO.OUT); GPIO.output(ENABLE_PIN, GPIO.HIGH)) — the motor no longer moves at all, even though the exact same STEP pulses are still arriving. SLEEP driven LOW or RESET driven LOW do the same thing.
What “working correctly” looks like
- Each rising edge on STEP advances the shaft by exactly one microstep — the shaft's rotation in the Canvas matches your pulse count times the current MS1/2/3 resolution.
- DIR's level sets the direction of the next pulses — flip it mid-script and the very next pulses reverse.
- The driver's own small status readout shows RUN·1/N (N = the current microstep resolution) while it's actually driving, or a short reason it isn't: EN (disabled), SLP (asleep), RST (held in reset), or NO PWR/NO VMOT (logic or motor supply not reachable).
- ENABLE driven HIGH, SLEEP driven LOW, or RESET driven LOW each independently stop the motor from moving — STEP pulses still arrive but are simply ignored for position purposes while any of the three is asserted.
- Changing MS1/MS2/MS3 mid-script (even mid-run) immediately changes how far each subsequent pulse moves the shaft, without needing to Stop and Start again.
If something’s wrong
- The motor never moves at all → confirm BOTH power sides are wired: VDD/GND (logic) to a real Pi power/ground pin pair, AND VMOT/GND (motor) to a real DC Power Supply — the driver's own status readout on the Canvas will read NO PWR or NO VMOT if either is missing.
- The motor is powered but still won't move → check the status readout for EN/SLP/RST — one of ENABLE/SLEEP/RESET is wired the wrong way (remember all three are active-LOW: ENABLE must be LOW to drive, SLEEP and RESET must both be HIGH for normal operation).
- The motor spins the wrong direction → check your DIR wiring/level, or simply swap the A+/A- (or B+/B-) leads at the driver — reversing one coil's polarity reverses that half of the motor's own physical rotation, same as on real hardware.
- The motor moves a different amount than you expected for the same number of pulses → check MS1/MS2/MS3 — a higher microstep resolution means MORE pulses are needed for the same amount of rotation, and vice versa.
- STEP pulses seem to do nothing even with everything wired → confirm your script actually toggles STEP HIGH then LOW (a rising edge is what counts, not just setting it HIGH once) and that GPIO.setmode(GPIO.BOARD) with the correct physical pin numbers is being used.