Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

SPI.configuration and L6470 Stepper Driver


  • Please log in to reply
12 replies to this topic

#1 Kristoffer

Kristoffer

    Advanced Member

  • Members
  • PipPipPip
  • 37 posts

Posted 12 June 2012 - 09:13 PM

Hi

I'm trying to connect to one of these: L6470 Stepper Motor Driver, a stepper motor driver controlled over an SPI link.

It comes with an Arduino example sketch, which runs fine. So I'm trying to port it to my Netduino using the SPI.Configuration and SPI types described in the wiki, so far no luck.

Below is an excerpt of the L6470 datasheet:

Maximum SPI clock frequency: 5 MHz
Chip select setup time: min. 350 ns
Chip select hold time: min. 10 ns
Deselect time: min. 800 ns
Data input setup time: min. 25 ns
Data input hold time: min. 20 ns

"When CS is high the device is unselected and the SDO line is inactive
(high-impedance).

The communication starts when CS is forced low. The CK line is used for synchronization of
data communication.
.....
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."


So I'm setting the SPI configuration like this:
opSS = new OutputPort(Pins.GPIO_PIN_D10, true);

var device1 = new SPI.Configuration(Pins.GPIO_NONE, // SS-pin
     				    false,          // SS-pin active state
                                    350,            // The setup time for the SS port.[b] What resolution is this?[/b]
                                    10,             // The hold time for the SS port. [b]What resolution is this?[/b]
                                    true,           // The idle state of the clock
                                    false,          // The sampling clock edge
                                    5000,           // The SPI clock rate in KHz
                                    SPI_Devices.SPI1// The used SPI bus (refers to a MOSI MISO and SCLK pinset)
                );

spi = new SPI(device1);
And the write routine:
static void SendBytes(byte[] bWrite, byte[] bRead)
{
    opSS.Write(false);
    spi.WriteRead(bWrite, bRead);
    opSS.Write(true);
}

But I'm not getting the same reponses as the Arduino example, far from.

If I i.e. send a0x38 byte via Arduino example, then I get a single byte back value 1. Doing the same from Netduino gives also 1, however, no matter how large I make the read buffer (i.e var bRead = new byte[40]; ) the first byte is 1 and the rest is 121 (decimal). And after that responses are not comparable.

Unfortunately I don't have an oscilloscope, so I can't measure what actually happens. Would that actually be possible to measure a byte with an oscilloscope?

I have tried to set SS port setup time and hold time in the SPI.Configuration constructor to 0 and it gives the same result.

If anybody can see anything that might cause trouble in my SPI setup, please let me know.

Thank you
Kristoffer

#2 nakchak

nakchak

    Advanced Member

  • Members
  • PipPipPip
  • 404 posts
  • LocationBristol, UK

Posted 12 June 2012 - 10:28 PM

Hi Kristoffer

In order to write arrays instead of a single byte at a time you need to toggle the CS line after each byte has been sent, this can either be done with a hardware fix, or a modified firmware. The default netduino behaviour is for the CS line to be asserted for the entire write operation, i.e. if you configure CS to be active low, and try and write a 8 byte array it will stay low for the duration of writing the 8byte array, where as what you want is for the CS line to go high after each byte is written and then low as soon as the next byte is written.

You can just send a single byte at a time as that will toggle the CS line, however its not half as fast as it can be if you can get the CS line to toggle.

Im currently in the process of designing a 3 axis stepper motor driver module for the GO which uses the same dspin chip as your driver, does look like a very capable bit of kit :)

Nak.

#3 Kristoffer

Kristoffer

    Advanced Member

  • Members
  • PipPipPip
  • 37 posts

Posted 13 June 2012 - 05:15 AM

You can just send a single byte at a time as that will toggle the CS line, however its not half as fast as it can be if you can get the CS line to toggle

Isn't that what I'm doing if I do like this:
{
var writebuffer = new byte[]{0x38};
var readbuffer = new byte[1];

SendBytes(writebuffer, readbuffer);
}


#4 nakchak

nakchak

    Advanced Member

  • Members
  • PipPipPip
  • 404 posts
  • LocationBristol, UK

Posted 13 June 2012 - 09:55 AM

Yes, but if you wanted to send

var writeBuffer = new byte[]{0x01,0x02}

all you would see is on your driver is 0x01 being sent.

You are effectively half bit banging the transmission, which is quite a slow way of doing it, if you are getting acceptable performance then its not a problem, but you may find when you try and send some of the larger config commands to the L6470 that the transmission is too slow and it wont work as expected, especially when your code base becomes larger/more complicated.

By using the managed output port object you are effectively tripling the amount of work the micro has to do, as unlike the arduino, which has a pretty thin abstraction layer the netduino and netmf in general has several layers of abstraction (secret labs assemblies-->netmf core runtime-->Hardware abstraction layer--> device specific low-level drivers) to get from c#/vb to op codes, which does lead to a hit in performance when you try and bit bang unless you do it at the lowest level, i.e. search the forum for bitbanging here and you will find there are some customised firmwares to do what you are doing in a more efficient manner..

To my mind the stock SPI implementation is wrong in netmf is so much that you cannot explicitly tell the SPI object to toggle the CS line after each byte is sent (some spi devices need this some don't), that said depending on how the firmware has been written if the CS pin you define is one of the MCU's hardware SPI CS lines sometimes toggles after each byte, i.e. on the nd+ GPIO_PIN_D5 i believe is the hardware CS pin but i haven't checked to see if default behaviour is asserted by the netduino firmware.

Nak.

#5 Kristoffer

Kristoffer

    Advanced Member

  • Members
  • PipPipPip
  • 37 posts

Posted 15 June 2012 - 08:44 AM

Hi Nak

Thanks for all your help.

My first problem was that I couldn't send understandable commands to the L6470 driver via SPI, I solved this by changing the initial SPI.Configuration (see first post) to this:
var device1 = new SPI.Configuration(Pins.GPIO_PIN_D10, // SS-pin
                                    false,             // SS-pin active state
                                    0,                 // The setup time for the SS port
                                    0,                 // The hold time for the SS port
                                    false,             // The idle state of the clock
                                    true,              // The sampling clock edge
                                    5000,              // The SPI clock rate in KHz
                                    SPI_Devices.SPI1   // The used SPI bus (refers to a MOSI MISO and SCLK pinset)
                );
The problem was the Idle state of the clock and the sampling clock edge parameters, and it didn't make any difference if I toggled the SS-pin in code or it was automatically toggled when calling WriteRead(...).

This still doesn't give me the expected responses in the read buffer when I execute a spi.WriteRead(...);, but I've chosen not to be concerned about that at the moment. When the NetduinoGo ShieldBase is out of Beta all my code is going to be ported to the NetduinoGo, so I'll wait and see what new challenges lies ahead.

Im currently in the process of designing a 3 axis stepper motor driver module for the GO which uses the same dspin chip as your driver, does look like a very capable bit of kit

Indeed :), can I sign up for a newsletter or something? Please let me know when you expect to have something ready, I'm very eager to use the NeduinoGo.

I've been using the BigEasyDriver, which is very easy to get started with, but for my needs, I found it very difficult to configure and make proper acceleration/deceleration and the motors had this bzzz sound all the time.

Kristoffer

#6 nakchak

nakchak

    Advanced Member

  • Members
  • PipPipPip
  • 404 posts
  • LocationBristol, UK

Posted 15 June 2012 - 10:15 AM

Once I get the components and basic schematic sorted I plan on starting a project thread and refining the design based on community feedback from there as well as using it for content for my site when i get it ready for a relaunch. As always time is the enemy and i have a very busy month or 2 ahead of me but hopefully i will have something to show before too long. Nak.

#7 Igor Kondrasovas

Igor Kondrasovas

    Advanced Member

  • Members
  • PipPipPip
  • 105 posts
  • LocationPorto, Portugal

Posted 17 October 2012 - 11:31 PM

Hi Kristoffer, Can you please give us some update about how the usage of this driver L6470 is going? I am planning to use it in a new project with Netduino Classic and would like to know how was your experience. Did you develop some kind of driver or library for it? Thank you, Igor.

Igor Kondrasovas

www.inovativatec.com


#8 Kristoffer

Kristoffer

    Advanced Member

  • Members
  • PipPipPip
  • 37 posts

Posted 18 October 2012 - 09:57 AM

Hi Kristoffer,
Can you please give us some update about how the usage of this driver L6470 is going?
I am planning to use it in a new project with Netduino Classic and would like to know how was your experience.
Did you develop some kind of driver or library for it?
Thank you,
Igor.


Hi Igor

Certainly I will.

I'm using it and it works fine, it has been a little up-hill, mostly because of my lack of knowledge in electronics, but I managed to get it to work.

This guy, Kurtnelle, has developed a .NET L6470 driver which should be fine, and here's a link to a discussion about it.

If you use the the sparkfun L6470 Breakout board, I'd recommend you read the comments at the Sparkfun L6470 product page, and pay attention to 4 specific advices:

  • An user suggest downloading ST dSpin evaluation software (evaluation software is found at the bottom of tab page “Design support”), it will help you figure out how to set some essential and motor specific parameters.
  • Another user links to a ST presentation of the L6470, watch it, I didn't notice it until today and it makes a lot of things clear to me that I didn't understand earlier.
  • Read the important section in the Arduino example - dSPIN_example.ino, it suggest inserting a SOFTSTOP between motion commands, I found that usefull and saved me some time.
  • There's a known problem about VReg at the Sparkfun L6470 Breakout board

Based on the Arduino example sketch at the Sparkfun L6470 product page and the parameters from the dSpin evaluation software my motorspecific setup looks like this:

private void Setup_MAE_210_24V()
{
	//opReset = L6470 Reset Pin
	opReset.Write(true);
	Thread.Sleep(1);
	opReset.Write(false);
	Thread.Sleep(1);
	opReset.Write(true);
	Thread.Sleep(1);

	SendByte(Constants.dSPIN_SET_PARAM | Constants.dSPIN_STEP_MODE);
	SendByte(Constants.dSPIN_STEP_SEL_1);

	SendByte(Constants.dSPIN_SET_PARAM | Constants.dSPIN_MAX_SPEED);
	SendBytes(MaxSpdCalc(600), 2);

	SendByte(Constants.dSPIN_SET_PARAM | Constants.dSPIN_MIN_SPEED);
	SendByte(0x10);
	SendByte(0x00);

	SendByte(Constants.dSPIN_SET_PARAM | Constants.dSPIN_KVAL_HOLD);
	SendByte(0xC);

	SendByte(Constants.dSPIN_SET_PARAM | Constants.dSPIN_KVAL_ACC);
	SendByte(0x21);

	SendByte(Constants.dSPIN_SET_PARAM | Constants.dSPIN_KVAL_DEC);
	SendByte(0x21);

	SendByte(Constants.dSPIN_SET_PARAM | Constants.dSPIN_KVAL_RUN);
	SendByte(0x21);

	SendByte(Constants.dSPIN_SET_PARAM | Constants.dSPIN_ST_SLP);
	SendByte(0x18);

	SendByte(Constants.dSPIN_SET_PARAM | Constants.dSPIN_INT_SPD);
	SendByte(0x1A);
	SendByte(0xFF);

	SendByte(Constants.dSPIN_SET_PARAM | Constants.dSPIN_FN_SLP_ACC);
	SendByte(0x2D);

	SendByte(Constants.dSPIN_SET_PARAM | Constants.dSPIN_FN_SLP_DEC);
	SendByte(0x2D);

	//These three commands prevented a small but consistent steploss when I called MOVE the first time after initialization
	//I haven't found an explenation nor have I dug into why, actually I don't think you need all three commands, maybe a SOFTSTOP would do.
	SendByte(Constants.dSPIN_RESET_POS);
	SendByte(Constants.dSPIN_GO_HOME);
	SendByte(Constants.dSPIN_HARD_STOP);
}

Notice a significant difference from the Sparkfun Arduino example, I do not set the config register, the default values worked for my setup, so I haven't really dug into the Config parameters (maybe the steploss issue metioned in code is found here :mellow: ).

My success criteria was a precise movement including:
  • no step loss
  • control of acc and dec
  • control of speed
  • control of holding torque

And that's what the L6470 fullfilled. I can see there's a bunch of other possibilities with the chip like attaching a switch, use more complex movement commands based on the position knowledge in the chip and so on.

Let me know if you run into problems or if you have further questions, I might be able to help you.

Regards
Kristoffer

#9 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 18 October 2012 - 11:40 AM

Sorry guys, but why put brakes to the Netduino SPI, being soooo fast? Handshaking the SPI using the managed code is *really* painful: maybe slower than a turtle. Have a look a this trick, with uses any binary counter (e.g. 74HC4040) to generate the CS pulse automatically. At that point, you will have to put brakes to the Netduino just because the driver chip is actually slower! http://highfieldtale...s-is-for-speed/ Cheers
Biggest fault of Netduino? It runs by electricity.

#10 Kristoffer

Kristoffer

    Advanced Member

  • Members
  • PipPipPip
  • 37 posts

Posted 19 October 2012 - 10:39 AM

Thanks Mario, I think I get your point.

I just need to get something clarified

Handshaking the SPI using the managed code is *really* painful: maybe slower than a turtle.

do you refer to the togling of the SS pin (opSS.Write(false) and opSS.Write(true)) in the SendBytes method?
static void SendBytes(byte[] bWrite, byte[] bRead)
{
    opSS.Write(false);
    spi.WriteRead(bWrite, bRead);
    opSS.Write(true);
}
Actually that's and old implementation, my current SendByte method looks like this:
static void SendByte(byte bWrite)
{
    var bRead = new byte[1];
    spi.WriteRead(new byte[] {bWrite}, bRead);
}
But that should almost be the same since the spi.WriteRead(...) automatically toggles the SS pin.

The L6470 needs the SS pin to toggle (...After each byte transmission the CS input must be raised ....)

So the problem is the spi.WriteRead(...) is slow when it toggles the SS pin it's not slow writing bytes?

And what you say, is that this can be done much faster by implementing the hardware fix (just like nakchak suggests earlier in this thread)?

I haven't had any performance issues with my approach and setup so far, and it hasn't been a show stopper. But I can see that it's not "fast" when I send many bytes like in the Setup motor method.

So I will definitely look into your very thoroughly described hardware fix, thanks a lot for you input, it's very much appreciated :)

Regards
Kristoffer

#11 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 19 October 2012 - 11:55 AM

Kristoffer, in my article I show the huge waste of (precious) time avoiding the hardware way. If you like, a simple hardware trick can save amounts of machine-time.

Some consideration...

=== wasting time for GC:
This way is surely better than commanding the CS explicitly:
static void SendByte(byte bWrite)
{
    var bRead = new byte[1];
    spi.WriteRead(new byte[] {bWrite}, bRead);
}
However, every time you call this function the system must create two brand-new byte-arrays, then trashing them. All that for just one byte?
Moreover, the function call itself takes time: a little, but it's still a waste.

=== byte interleave
The Netduino SPI works like a charm. It's blazing fast, because you could take its speed up to 48 MHz (I think). Moreover, since the transfer is managed by the internal hardware, you haven't almost any delay between a byte and the next one.
Take a look at my article, first half. It's the intuitive-, software-only-way, but even using a tight loop (very first code), the board yields a byte delay of about 370us.
Apparently it's not so much, but...
- the machine is totally busy for doing a so simple task;
- multiplying that delay for *many* bytes, you'll get *many* millisecs

=== let the hardware helping you
The second half of the article shows a (possible) way for taking advantage of the SPI full-speed capability. The counter (74HC4040) does what is designed for: count the pulses. Every 8 pulses, you have a whole byte, thus the counter tells you that.
The rest of the circuit is just a edge detector for creating a pulse, upon the counter overflow.
Advantages:
- you can use a single byte-array, because one-byte means one-command;
- the delay time between one byte and the next one has decreased to 5.5us.

That article was more a demonstration showcase, other than a practical one.
This one uses a similar trick for speeding-up the LCD driver of x12.
Please note that the speed had to be limited because the LCD itself wasn't able to run faster. Netduino+trick could get much faster leaving your app free to "breathe"!

Cheers
Biggest fault of Netduino? It runs by electricity.

#12 Dave M.

Dave M.

    Advanced Member

  • Members
  • PipPipPip
  • 53 posts

Posted 03 July 2013 - 03:55 PM

So.... how are things going, Kristoffer?  :)

 

It turns out that I'm trying to get my L6470 eval kit working with both the Netduino Plus and mbed LPC1768, and I have had no luck with either.  I actually posted here recently: http://forums.netdui...h-time/?p=50999

 

I'm glad I found your post because it might help me to get further along.  One thing that might be tripping me up is the issue with CS having to be toggled after each byte.  It does say that in the text, but when I implemented mine, I used Figure 18 (timing diagram) instead.  This timing diagram says the exact opposite, if I'm reading it correctly -- that you can clock the MSB to LSB out with CS kept low.  How confusing!

 

I also have a different SPI configuration than you.  From the datasheet, I interpreted the clock's idle state to be high, and to look for a low-high clock transistion for the data.  Therefore, my config looks like this:

SPI.Configuration l6470 = new SPI.Configuration( Pins.GPIO_PIN_D2,                                                 false,                                                 1,                                                 1,                                                 true,                                                 true,                                                 100,                                                 SPI_Devices.SPI1);

Note that I am purposely running at 100kHz because my logic analyzer doesn't have enough memory to be able to reliably capture data.

 

On the mbed side, everything I send to the L6470 gets echoed back, which is weird.  On the NP, I get weird bit shifting effects where a bit shifts from the MSb to the LSb when I just send NOPs continuously.

 

If you have gotten yours to work, then I'm going to try using your config parameters to see if I get better results.  It would be great to hear how your L6470 project is going now!



#13 Dave M.

Dave M.

    Advanced Member

  • Members
  • PipPipPip
  • 53 posts

Posted 03 July 2013 - 04:22 PM

I'm an idiot.  I misread the timing diagram and blindly interpreted MSB as MS BYTE, even though the CK line clearly implies that this is MS BIT.  :)  Ok, things are getting better now on my end.  I'll look into the special hardware hack mentioned earlier.






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.