Pololu High-Power Stepper Motor Driver 36v4 with Raspberry pi 5 issue!

Hi
I am trying to connect the Pololu High-Power Stepper Motor Driver 36v4 with rasperry pi 5. so far not succeed.
i was using 24V for motor supply and programming in Python. I can write the spi register and read from it. but still not hold or mostion from the steppemotor.
Sleep and reset set to high and using jumper between v5 and VOREF.
VM is 24VDC.

Any ideas?

Thank you.

Hello.

The Raspberry Pi 5 is a 3.3V device; it is not 5V tolerant and can be permanently damaged by voltages above 3.3V. So, you should be connecting a 3.3V source to IOREF.

Please note that setting the RESET pin high resets all internal logic, including the indexer and device registers, and disables the driver outputs. I recommend just leaving it disconnected for now, and just driving the nSLEEP pin high as shown in the typical wiring diagram on the product page.

If that does not help, could you post more details about what you have tried? For example, what registers have you tried setting and what did you set them to? Also, please post some pictures of your setup that show all of your connections.

Brandon

Hi Brandon,
I have removed the reset connection and tried again. but with the same result.
I am using the following python code to test the drive.

import spidev
import RPi.GPIO as GPIO
import time
import threading

# Pin setup
STEP_PIN   = 17
DIR_PIN    = 27
SLEEP_PIN  = 23
# RESET_PIN  = 24

GPIO.setmode(GPIO.BCM)
GPIO.setup(STEP_PIN, GPIO.OUT)
GPIO.setup(DIR_PIN, GPIO.OUT)
GPIO.setup(SLEEP_PIN, GPIO.OUT)
# GPIO.setup(RESET_PIN, GPIO.OUT)

# Enable driver (SLEEP/RESET HIGH)
GPIO.output(SLEEP_PIN, GPIO.HIGH)
# GPIO.output(RESET_PIN, GPIO.HIGH)

# SPI setup
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1000000
spi.mode = 0b00

def drv8711_write(register, value):
    high_byte = (register << 1) & 0x7F
    low_byte = value
    spi.xfer2([high_byte, low_byte])

def drv8711_read(register):
    high_byte = ((register << 1) | 0x01) & 0x7F  # Read flag set
    resp = spi.xfer2([high_byte, 0x00])
    # The register value is in resp[1]
    return resp[1]

# Configure outputs for 1.5A/phase
drv8711_write(0x00, 0x11)   # CTRL: EN_OUT=1, full step
drv8711_write(0x01, 0x6F)   # TORQUE: ~1.5A/phase

def move_steps(steps, direction="CW", delay=0.01):
    GPIO.output(DIR_PIN, GPIO.HIGH if direction == "CW" else GPIO.LOW)
    for _ in range(steps):
        GPIO.output(STEP_PIN, GPIO.HIGH)
        time.sleep(delay)
        GPIO.output(STEP_PIN, GPIO.LOW)
        time.sleep(delay)

# Motion loop and register check
running = True

def run_motion():
    count = 0
    while running:
        print(f"\nMove 200 steps CW")
        move_steps(200, "CW")
        time.sleep(1)
        print(f"Move 200 steps CCW")
        move_steps(200, "CCW")
        time.sleep(1)
        count += 1
        # Every second loop, read back key registers for status
        if count % 2 == 0:
            ctrl_val   = drv8711_read(0x00)
            torque_val = drv8711_read(0x01)
            print(f"[Readback] CTRL: 0x{ctrl_val:02X}, TORQUE: 0x{torque_val:02X}")

print("Driver enabled with ~1.5A/phase. Motor should hold and move.")
print("Press [Enter] at any time to exit.")

motion_thread = threading.Thread(target=run_motion)
motion_thread.start()
input()  # wait for Enter key
running = False
motion_thread.join()

spi.close()
GPIO.cleanup()
print("Driver disabled and GPIO cleaned up.")

It looks like there are many problems with that code, including the structure of the SPI communication and the data bits you are sending; where did you get it from? I recommend using our High-Power Stepper Motor Driver Arduino Library as a reference for fixing your Python code (HighPowerStepperDriver.h in particular). While it is in a different programming language, the process should be similar.

Brandon

Hi Brandon,
I have created this script to test it with the driver. But, it doesn’t work. Then I have tried the Arduino Nano with your example. it works fine. However i am not able to get it work with the raspberry pi 5. My last test script as follows: still no luck.

import spidev
import RPi.GPIO as GPIO
import time

print("=== ARDUINO NANO 3.3V SPI EXACT REPLICA ===")
print("Using Pi 5 with 3.3V IOREF - matching Arduino timing exactly")
print("VMOT=24V, IOREF=3.3V, SLEEP=3.3V confirmed")

# Pins (same as your Arduino Nano setup)
SCS_PIN = 22  # Arduino Nano CS pin equivalent
DIR_PIN = 17
STEP_PIN = 27

GPIO.setmode(GPIO.BCM)
GPIO.setup(SCS_PIN, GPIO.OUT)
GPIO.setup(DIR_PIN, GPIO.OUT)
GPIO.setup(STEP_PIN, GPIO.OUT)

# Arduino Nano 3.3V boot sequence
GPIO.output(SCS_PIN, GPIO.HIGH)  # CS inactive at start
time.sleep(0.001)  # Arduino delay(1)

# Arduino SPI setup - exact equivalent
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 250000  # Arduino Nano typical SPI speed at 16MHz / 64
spi.mode = 0b00
spi.bits_per_word = 8  # Arduino default

def arduino_spi_transfer(data16):
    """EXACT Arduino SPI.transfer16() replica"""
    # Arduino sends 16-bit word: high byte first, then low byte
    high_byte = (data16 >> 8) & 0xFF
    low_byte = data16 & 0xFF
    
    # Arduino: CS HIGH → transfer → CS LOW
    GPIO.output(SCS_PIN, GPIO.HIGH)
    time.sleep(0.000001)  # 1us setup (Arduino overhead)
    
    # Transfer high byte
    spi.xfer2([high_byte])
    time.sleep(0.000002)  # Arduino clock period ~4us at 250kHz
    
    # Transfer low byte
    spi.xfer2([low_byte])
    time.sleep(0.000001)  # 1us hold time
    
    # Arduino: CS LOW after transfer
    GPIO.output(SCS_PIN, GPIO.LOW)
    time.sleep(0.001)  # Arduino delay between transfers

def arduino_write_reg(reg, value):
    """Arduino library writeReg() exact replica"""
    data16 = ((reg & 0b111) << 12) | (value & 0xFFF)
    arduino_spi_transfer(data16)

def arduino_read_reg(reg):
    """Arduino library readReg() exact replica"""
    data16 = ((0x8 | (reg & 0b111)) << 12)
    arduino_spi_transfer(data16)
    
    # Arduino reads response during transfer - simulate with delay + read
    time.sleep(0.0001)
    resp = spi.xfer2([0x00, 0x00])
    return ((resp[0] << 8) | resp[1]) & 0xFFF

print("\n=== Arduino Nano 3.3V Initialization Sequence ===")

# 1. Arduino library: sd.resetSettings() + sd.clearStatus()
print("1. Resetting settings and clearing status...")
arduino_write_reg(0x07, 0x000)  # Clear STATUS
time.sleep(0.01)  # Arduino delay

# 2. Arduino defaults from HighPowerStepperDriver constructor
print("2. Writing Arduino library default registers...")
arduino_write_reg(0x00, 0xC10)  # CTRL
time.sleep(0.001)
arduino_write_reg(0x01, 0x1FF)  # TORQUE
time.sleep(0.001)
arduino_write_reg(0x02, 0x030)  # OFF
time.sleep(0.001)
arduino_write_reg(0x03, 0x080)  # BLANK
time.sleep(0.001)
arduino_write_reg(0x04, 0x110)  # DECAY
time.sleep(0.001)
arduino_write_reg(0x05, 0x040)  # STALL
time.sleep(0.001)
arduino_write_reg(0x06, 0xA59)  # DRIVE

# 3. Arduino example configuration: sd.setDecayMode(AutoMixed)
print("3. Setting AutoMixed decay mode...")
decay_val = (0b101 << 8) | 0x10  # bits 10:8 = 101
arduino_write_reg(0x04, decay_val)

# 4. Arduino example: sd.setCurrentMilliamps36v4(1000)
print("4. Setting current limit 1000mA (36v4)...")
# ISGAIN = 3 (11 binary), TORQUE = 0x50 for 1000mA at 3.3V IOREF
arduino_write_reg(0x00, 0xC30)  # CTRL with ISGAIN=3
time.sleep(0.01)
arduino_write_reg(0x01, 0x50)   # TORQUE for 1000mA

# 5. Arduino example: sd.setStepMode(MicroStep32)
print("5. Setting MicroStep32 mode...")
ctrl_val = arduino_read_reg(0x00)  # Read current CTRL
step_mode = 0b0101  # MicroStep32 (bits 6:3)
ctrl_val = (ctrl_val & 0b111110000111) | (step_mode << 3)
arduino_write_reg(0x00, ctrl_val)

# 6. Arduino example: sd.enableDriver()
print("6. ENABLING DRIVER OUTPUTS...")
time.sleep(0.01)
final_ctrl = ctrl_val | 0x001  # Set ENBL bit 0
arduino_write_reg(0x00, final_ctrl)

print("\n=== TORQUE VERIFICATION ===")
print("Motor should IMMEDIATELY resist turning by hand")
print("This matches your working Arduino Nano 3.3V setup exactly")

# Wait for manual test
time.sleep(5)
holding = input("Does motor hold torque? (y/n): ").lower()

if holding == 'y':
    print("\n🎉 SUCCESS! Pi 5 + 3.3V IOREF working!")
    print("Now testing STEP/DIR motion...")
    
    # Motion test
    print("Testing CW 200 steps...")
    GPIO.output(DIR_PIN, GPIO.HIGH)  # CW
    time.sleep(0.001)
    
    for i in range(200):
        GPIO.output(STEP_PIN, GPIO.HIGH)
        time.sleep(0.002)  # Arduino Nano step period / 2
        GPIO.output(STEP_PIN, GPIO.LOW)
        time.sleep(0.002)
    
    print("CW complete")
    time.sleep(1)
    
    print("Testing CCW 200 steps...")
    GPIO.output(DIR_PIN, GPIO.LOW)  # CCW
    time.sleep(0.001)
    
    for i in range(200):
        GPIO.output(STEP_PIN, GPIO.HIGH)
        time.sleep(0.002)
        GPIO.output(STEP_PIN, GPIO.LOW)
        time.sleep(0.002)
    
    print("CCW complete - motor should be back to start")
else:
    print("\n No torque - Pi 5 SPI still incompatible")
    print("Even with exact Arduino 3.3V replication")
    print("\nSolutions:")
    print("1. Arduino Nano bridge (Pi serial → Arduino SPI)")
    print("2. Different Pi model (Pi 4/3)")
    print("3. Commercial SPI buffer IC")

# Cleanup
GPIO.output(SCS_PIN, GPIO.HIGH)
spi.close()
GPIO.cleanup()
print("Test complete.")

I still see several errors with the values you are writing to the registers. For example, you are hard-coding the CTRL register to 0xC30 when trying to set the ISGAIN bits to 0x11, but the ISGAIN bits are bits 8 and 9 of the CTRL register, which are both 0 in 0xC30 (0b110000110000). Is there a reason you are hard-coding those values instead of making them like the Arduino library does? It looks like some other portions of your code do it that way.

Also, your TORQUE value also does not seem correct for setting the current limit to 1000mA. However, at this point, instead of continuing to troubleshoot the code line-by-line, I recommend simplifying it down as much as possible by trying to just write to a register and read back the change. Once you can confirm that is working, then we can work out the proper values.

Brandon

Hardcoding is for testing purpose only. Anyway, You are right, I need to fine tune and simplify the code for testing.

I got it working finally.

import os
os.environ["RPI_LGPIO_CHIP"] = "0"
import RPi.GPIO as GPIO
import time
from HighPowerStepperDriver import HighPowerStepperDriver, HPSDStepMode, HPSDDecayMode


GPIO.setmode(GPIO.BCM)   
CS_PIN = 4           # Chip select pin (use your available output GPIO)
STEP_PERIOD_US = 5  # microseconds
noofsteps = 64000 # steps
# Set up the stepper driver
sd = HighPowerStepperDriver(CS_PIN)


def setup():
    
    time.sleep(0.001)  # 1 ms wait for driver power-up


    # Reset and clear
    sd.reset_settings()
    sd.clear_status()


    # Set decay mode (AutoMixed is recommended for most)
    sd.set_decay_mode(HPSDDecayMode.AutoMixed)


    # Set current limit (change value as needed)
    sd.set_current_milliamps_36v4(500)


    # Microstepping (e.g. 32 microsteps per full step)
    sd.set_step_mode(HPSDStepMode.MicroStep32)


    # Enable motor outputs
    sd.enable_driver()


def loop():
    while True:
        # Step 1000 times in one direction.
        sd.set_direction(False)
        for _ in range(noofsteps):
            sd.step()
            time.sleep(STEP_PERIOD_US / 1_000_000.0)
        time.sleep(0.3)


        # Step 1000 times in the other direction.
        sd.set_direction(True)
        for _ in range(noofsteps):
            sd.step()
            time.sleep(STEP_PERIOD_US / 1_000_000.0)
        time.sleep(0.3)


if __name__ == "__main__":
    try:
        setup()
        loop()
    except KeyboardInterrupt:
        pass
    finally:
        sd.disable_driver()
        GPIO.cleanup()
import spidev
import RPi.GPIO as GPIO
from enum import Enum
import time

class HPSDRegAddr(Enum):
    CTRL = 0x00
    TORQUE = 0x01
    OFF = 0x02
    BLANK = 0x03
    DECAY = 0x04
    STALL = 0x05
    DRIVE = 0x06
    STATUS = 0x07

class HPSDStepMode(Enum):
    MicroStep256 = 256
    MicroStep128 = 128
    MicroStep64 = 64
    MicroStep32 = 32
    MicroStep16 = 16
    MicroStep8 = 8
    MicroStep4 = 4
    MicroStep2 = 2
    MicroStep1 = 1

class HPSDDecayMode(Enum):
    Slow = 0b000
    SlowIncMixedDec = 0b001
    Fast = 0b010
    Mixed = 0b011
    SlowIncAutoMixedDec = 0b100
    AutoMixed = 0b101

class HPSDStatusBit(Enum):
    OTS = 0
    AOCP = 1
    BOCP = 2
    APDF = 3
    BPDF = 4
    UVLO = 5
    STD = 6
    STDLAT = 7

class DRV8711SPI:
    def __init__(self, cs_pin, bus=0, device=0):
        self.cs_pin = cs_pin
        self.spi = spidev.SpiDev()
        self.spi.open(bus, device)
        self.spi.max_speed_hz = 500000
        self.spi.mode = 0
        self.spi.bits_per_word = 8
        GPIO.setwarnings(False)
        GPIO.setup(self.cs_pin, GPIO.OUT)
        GPIO.output(self.cs_pin, GPIO.LOW)

    def transfer(self, value):
        tx_bytes = [(value >> 8) & 0xFF, value & 0xFF]
        GPIO.output(self.cs_pin, GPIO.HIGH)  # Assert CS
        rx_bytes = self.spi.xfer2(tx_bytes)
        GPIO.output(self.cs_pin, GPIO.LOW)   # Deassert CS
        return (rx_bytes[0] << 8) | rx_bytes[1]

    def read_reg(self, address):
        # Always use address.value if passed an enum
        if isinstance(address, Enum):
            address = address.value
        data_out = self.transfer((0x8 | (address & 0b111)) << 12)
        return data_out & 0xFFF

    def write_reg(self, address, value):
        # Always use address.value if passed an enum
        if isinstance(address, Enum):
            address = address.value
        self.transfer(((address & 0b111) << 12) | (value & 0xFFF))

    def cleanup(self):
        self.spi.close()
        GPIO.cleanup([self.cs_pin])

class HighPowerStepperDriver:
    def __init__(self, cs_pin, bus=0, device=0):
        self.driver = DRV8711SPI(cs_pin, bus, device)
        self.ctrl = 0xC10
        self.torque = 0x1FF
        self.off = 0x030
        self.blank = 0x080
        self.decay = 0x110
        self.stall = 0x040
        self.drive = 0xA59

    def reset_settings(self):
        self.ctrl = 0xC10
        self.torque = 0x1FF
        self.off = 0x030
        self.blank = 0x080
        self.decay = 0x110
        self.stall = 0x040
        self.drive = 0xA59
        self.apply_settings()

    def verify_settings(self):
        torque_verify = self.driver.read_reg(HPSDRegAddr.TORQUE.value) & ~(1 << 10)
        return (self.driver.read_reg(HPSDRegAddr.CTRL.value) == self.ctrl and
                torque_verify == self.torque and
                self.driver.read_reg(HPSDRegAddr.OFF.value) == self.off and
                self.driver.read_reg(HPSDRegAddr.BLANK.value) == self.blank and
                self.driver.read_reg(HPSDRegAddr.DECAY.value) == self.decay and
                self.driver.read_reg(HPSDRegAddr.STALL.value) == self.stall and
                self.driver.read_reg(HPSDRegAddr.DRIVE.value) == self.drive)

    def apply_settings(self):
        self._write_torque()
        self._write_off()
        self._write_blank()
        self._write_decay()
        self._write_drive()
        self._write_stall()
        self._write_ctrl()

    def enable_driver(self):
        self.ctrl |= (1 << 0)
        self._write_ctrl()

    def disable_driver(self):
        self.ctrl &= ~(1 << 0)
        self._write_ctrl()

    def set_direction(self, value):
        if value:
            self.ctrl |= (1 << 1)
        else:
            self.ctrl &= ~(1 << 1)
        self._write_ctrl()

    def get_direction(self):
        return (self.ctrl >> 1) & 1

    def step(self):
        self.driver.write_reg(HPSDRegAddr.CTRL.value, self.ctrl | (1 << 2))

    def set_step_mode(self, mode):
        if isinstance(mode, HPSDStepMode):
            mode = mode.value
        sm = 0b0010
        if mode == 1: sm = 0b0000
        elif mode == 2: sm = 0b0001
        elif mode == 4: sm = 0b0010
        elif mode == 8: sm = 0b0011
        elif mode == 16: sm = 0b0100
        elif mode == 32: sm = 0b0101
        elif mode == 64: sm = 0b0110
        elif mode == 128: sm = 0b0111
        elif mode == 256: sm = 0b1000
        self.ctrl = (self.ctrl & 0b111110000111) | (sm << 3)
        self._write_ctrl()

    def set_decay_mode(self, mode):
        if isinstance(mode, HPSDDecayMode):
            mode = mode.value
        self.decay = (self.decay & 0b00011111111) | ((mode & 0b111) << 8)
        self._write_decay()

    def read_status(self):
        return self.driver.read_reg(HPSDRegAddr.STATUS.value) & 0xFF

    def clear_status(self):
        self.driver.write_reg(HPSDRegAddr.STATUS.value, 0)

    def set_current_milliamps_36v4(self, current):
        if current > 8000: current = 8000
        self.set_current_milliamps_36v8(current * 2)

    def set_current_milliamps_36v8(self, current):
        if current > 16000: current = 16000
        torque_bits = ((384 * current) // 6875)
        isgain_bits = 0b11
        while torque_bits > 0xFF:
            isgain_bits -= 1
            torque_bits >>= 1
        self.ctrl = (self.ctrl & 0b110011111111) | (isgain_bits << 8)
        self._write_ctrl()
        self.torque = (self.torque & 0b111100000000) | torque_bits
        self._write_torque()

    def _write_ctrl(self):
        self.driver.write_reg(HPSDRegAddr.CTRL.value, self.ctrl)

    def _write_torque(self):
        self.driver.write_reg(HPSDRegAddr.TORQUE.value, self.torque)

    def _write_off(self):
        self.driver.write_reg(HPSDRegAddr.OFF.value, self.off)

    def _write_blank(self):
        self.driver.write_reg(HPSDRegAddr.BLANK.value, self.blank)

    def _write_decay(self):
        self.driver.write_reg(HPSDRegAddr.DECAY.value, self.decay)

    def _write_stall(self):
        self.driver.write_reg(HPSDRegAddr.STALL.value, self.stall)

    def _write_drive(self):
        self.driver.write_reg(HPSDRegAddr.DRIVE.value, self.drive)

    def cleanup(self):
        self.disable_driver()
        self.driver.cleanup()