SPI with stepper driver

Hello everyone,

Over the past few days I’ve been working with the STMicro l6470 microstepping motor driver and attempting to interface it with the atmega328 via the arduino SPI library. So far I have been unsuccessful in getting the driver to respond to commands I send it and I believe the problem is due to my limited experience with SPI and would like some guidance.

Before i get too far here’s what I’ve got so far:

l6470 [datasheet

SPI interface:

-communication starts when CS is forced low

-The SDO is latched on the falling edges of the CK

-After each byte transmission the CS input must be raised and be kept high for at least tdisCS

in order to allow the device to decode the received command and put into the shift register

the return value.

-8 bit communication

Arduino Setup:

5v to MCU and to logic lines of l6470

12v to motors

pin10 → Slave Select

pin11 → SDI

pin12 → SDO

pin13 → CLK

The circuit i’m using is the same as on the datasheet, to keep things simple. And I know that all my power supplies are within specs. I manually set the SS (or cs) pin on setup and then toggle it low before sending the byte commands, however the driver itself does not respond in any fashion to any command I have sent so far. Originally I believed that my problems were stemming from commands that were wanting to have large (bigger than 8bit) registers set like on the run command (which i’ll talk about later), but when I tried to use simple single Byte commands I was still failing to get any result.

I’ve written and re-written the sketch a few different times with no success. Below I’ve included the code I have most recently used. I should note that on here you see that the CS pin is NOT toggle back high after each byte is sent. I originally set up the code incorrectly because my experience with other SPI devices expected multple bytes to be shifted per command. According to the datasheet this is the incorrect way to communicate with the driver. The code pasted below was specifically for debugging and I feel is the easiest to read version for others. I HAVE set up this exact code with the missing cs pin toggles and get the exact same result . For now just assume that each byte is shifted individually in the code. I also raise and lower CS for receiving bytes.

#include <SPI.h>
int  cs=10; //chip select 

void setup() {
  Serial.begin(9600);                  //setup serial communication for feedback
  SPI.begin();                         //let the SPI library handle mosi, miso, and ck.
  SPI.setBitOrder(MSBFIRST);           //in accordance with datasheet for l6470. MSBFIRST
  pinMode(cs,OUTPUT);
  
  digitalWrite(cs, LOW);               //pull cs low to send command
  SPI.transfer(0xD8);                  //reset pos via byte command
  digitalWrite(cs, HIGH);              //pull it high because datasheet says aftter every byte to pull high
  delay(1);                            //give the l6470 some time to think about what we just sent it.
   
}

void loop(){
  
  //== get sttus byte command ==//
  digitalWrite(cs, LOW);
  SPI.transfer(0xD0); //get status command in hex
  unsigned int n = 1; //set these are variables jus to make sure recieve signal is changing to something else
  unsigned int m = 1;
  n = SPI.transfer(0x00);  //status Most sig byte.
  m = SPI.transfer(0x00);  //status Least sig byte.
  digitalWrite(cs, HIGH);  
  Serial.println(n);      // output status return to see
  Serial.println(m);
  
  //set max_speed register
  digitalWrite(cs, LOW);
  unsigned int maxSpeed = SPI.transfer(0x07);        //initial command byte
  unsigned int maxSpeed1 = SPI.transfer(0x00);       //MAx speed is a 10 bit register. This needs to be shifter twice to fill correct?
  unsigned int maxSpeed2 = SPI.transfer(0x00);
  digitalWrite(cs, HIGH);                            //Toggle back up
  Serial.print("Speed: ");
  Serial.println(maxSpeed);
  Serial.println(maxSpeed1);
  Serial.println(maxSpeed2);
  
  
  digitalWrite(cs, LOW);
  unsigned int elpos = SPI.transfer(0x02);
  unsigned int elpos1 = SPI.transfer(0x02);
  digitalWrite(cs, HIGH);
  Serial.print("elpos: ");
  Serial.println(elpos);
  Serial.println(elpos1);
  
  
  
  //test command
  digitalWrite(cs, LOW);
  SPI.transfer(0xD8); //reset pos
  digitalWrite(cs, HIGH);
  digitalWrite(cs, LOW);
  unsigned int speed = 0;
  SPI.transfer(0x14); //reset pos
  digitalWrite(cs, HIGH);
  
    //test command
  digitalWrite(cs, LOW);
  SPI.transfer(0x51); //Run command
  SPI.transfer(0x00);
  SPI.transfer(0x34);
  SPI.transfer(0xBC);
  digitalWrite(cs, HIGH);
   delay(1000);
   
 // HardHiz
  digitalWrite(cs, LOW);
  SPI.transfer(0xA8); //HIZ STOP
  digitalWrite(cs, HIGH);
  
  delay(1000);
  

}

I"m going to keep playing with the code to see how simple I can make the program. I will post any updates to it as a progress.

Specific questions:

-Am I transferring bytes in the correct format? Or should I define a byte variable first and send that in the SPI.transfer function? or should I convert each byte to decimal or binary?

-certain commands and registers are larger than 8bits and require multiple bytes. I have no bitwise experience with shifting bytes and would like an example of setting the run command. starting on line 61 of the code I I did try send the run command. I believe I have it set up to set the “speed” to 13,500 which should translate to about 20 steps a second. but it still didn’t work and the device was never “holding” the motor. page 57 of the datasheet covers the run command structure but i wasn’t sure how to send half a byte, and I believe this is where I went wrong. Did i set it up correctly and if not what should the sequence look like?

-The datasheet does not specifically lay out how to receive data that the driver is sending back to the host (the atmega). Based on my past experience with the DeadOn RTC you would shift the command byte and for each byte you were expecting you would then shift a 0x00 byte and the “SPI.transfer(0x00);” function would return the Byte transmitted by the slave. I test this setup first thing in the main loop() function of the above code (line 19) and initially set the variables = to 1. after sending the get status command and using the above described method to receive the byte, i then push it out to serial so i can review the variable which is shown as 0. So i know that the variable is getting changed somehow, but is it changing the way it should? or is my code just wrong, causing me to believe the ic is resetting the value?

Thank you again in advance for any help you can provide.

~Poent](http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00255075.pdf)

Hi,

Just found this looking around the forum. I’ve used this devive quite a bit , so was wondering if you’ve moved on or got it going?

-chaz

Hi Techsupport Team,

We ran into problems reading ABS_POS on Arduinio Board… maybe you already know about this problem It seems to be the 8th Bit from the 22 bits Position register is always Low other reset… All the other functions are working good but of course I don´t be able to read the Position values correctly

In Order to find the solution i´ve tried following:

I tested all the possible solutions (taked from: https://www.sparkfun.com/products/10859) that other users have suggested with any succes.

I tried to implement new methods of the Autodrive library (https://github.com/sparkfun/L6470-AutoD … AutoDriver) in the old Arduino code and it has not worked

I Consulted/Posted on the ST microelectronics Forum about my Problem but I could not find a solution (You will see that other custumers experimented the same issue even with the evaluation board EVAL6470H).

Im need to ask if you could reproduce this error in your labs, it looks as many costumers have experimented the same situation. We need to be shure that your code works or we need to find other Hardware options at right time.

Thanks !

Poent,

Did you find a way to get ABS_POS to behave with an Arduino?

Edgar, have you made any headway?