MotorDriver / L6474

Stepper motor driver library for Arduino Uno using X-NUCLEO-IHM01A1 shield (based on L6474 component)
10 stars 7 forks source link

Inconsistencies #1

Open J-Dunn opened 9 years ago

J-Dunn commented 9 years ago

There is no indication of how multiple boards need to be wired for this library to work.

There is some mention of "the daisy-chain" in comments but this may be misuse of the term. No explanation is given.

The description of required resources here, contains the following:

SS | 10 | SPI Slave select | All MOSI | 11 | SPI Master Out Slave IN | All MISO | 12 | SPI Master IN Slave Out | All SCK | 13 | SPI serial clock | All

to believe this, all chips are connected identiacally so all will move identically. This will not work, neither is it a "daisy-chain".

Michel-F commented 9 years ago

To use this library with multilple boards:

J-Dunn commented 9 years ago

Thanks Michel. I have three such boards.

However, that document only adds to the confusion since figs 3 and 4 have the same title , the same column headings but seem to refer to two different things in the text. Too much copy/paste and not enough proof reading it would seem.

Am I correct in thinking that fig 4 should be entitled "Clock line selection" and the column heading should be "SCK line" ??

Also it does not mention that the two extra pins are cross-over connections and there is no circuit diagram for the board. As a potential user I find many of these documents at st.com too brief and incomplete to be much use. ( For example the stm32F4 discovery board presentation forgets to even mention that there is an ADC capability and seems more excited about the presence of two LEDs ! )

The chip datasheet is only proper technical document and also mentions "daisy-chain" but there is not explanation other than saying that the chips can be connected in a daisy-chain : see fig 14. , which shows the MISO-MOSI chaining

Now your libraries look very thorough and I'm sure it will compile and run but if I'm going to use the chip in anything more than a canned demo, I need to understand how it works.

I don't see clear documentation of how the "propagation of the SPI signal " happens and how I can , for example, get the status from the second board in a three board configuration.

I may be overlooking something in the L6474 datasheet but some additional explanation would be most useful.

Best regards.

J-Dunn commented 9 years ago

I've had another look at the L6474 datasheet to see whether I had overlooked some section dealing with this feature. It seems not. Indeed it adds more confusion.

AFAICS, the only information provided is the one sentence:

Multiple devices can be connected in a daisy-chain configuration, as shown in Figure 14.

And the crude timing diagram shown in that figure.

fig 14 shows the daisy-chain linking of MISO and MOSI and includes a crude timing diagram ( which does not even include the clock signal ) showing the SDI and SDO apparently identical in timing. This seems to suggest that inputs at SDI are reproduced immediately at SDO, though I don't think that is the case. But again I'm guessing in the absence of clear, explicit documentation.

fig 13 , the detailed timing diagram, shows SDO apparently changing BEFORE SDI , so this is presumably two separate timings for input and slave response output shown on the same diagram and is not related to the echoing of SDI on SDO during input.

This seems to imply two different modes of behaviour of the SDO line, one on input and one on output, though this is not documented.

It could also be that when data is sampled on rising SCK on SDI, it is later latched onto SDO on the following falling edge. This would mean figure 14 is incorrect. Since fig 14 is the ONLY information we are given on this feature, that is unhelpful.

If figure 14 included the clock signal and correctly showed the relative timing of SDI and SDO it would be an improvement.

If you could confirm some of my guesses and point out any errors, it would be great help.

Thanks again.

Michel-F commented 9 years ago

"Am I correct in thinking that fig 4 should be entitled "Clock line selection" and the column heading should be "SCK line" ?? Yes, you are correct fig 4 is related to the clock line selection.

By the way, on my side, I used the default configuration for both CS anc clock lines (I let R25 and R23 mounted).

Indeed, the daisy chaining is not clearly detail in the L6474 datasheet. But I found another document which allows to understand how daisy-chaining protocol works. For this, you can have a look of this application note (still from ST): http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/DM00082126.pdf and specifically at figure 9 where there is a time diagram with the clock and several devices! Hope, it will help you.

But, to summarize daisy chaining:

If you have only one device, if you want to transmit a command of one byte and get in return an answer of two bytes (case of the Get status command):

All this steps are automatically handled by the library. So, that you only have to write the following line: uint16_t statusRegister = myL6474.CmdGetStatus(0);

If you have three devices, if you want still to transmit a command of one byte to the second shield and get in return an answer of two bytes (case of the Get status command) :

All this steps are also automatically handled by the library. So, that you only have to write the following line: uint16_t statusRegister = myL6474.CmdGetStatus(1); to get the status of the second shield

J-Dunn commented 9 years ago

Many thanks for such a full reply. The application note is the key. Much of that is basic specification information , not an application example.

I can't imagine why they did not include full information in the datasheet for the chip.

It's neat the way your library simplifies that to one line, but I want to try to get these boards to work with GRBL , so I need to move pins around and strip it down to a bare minimum: there's very little code space left with GRBL. This means I need a good understanding of how it works.

I will have a thorough read of that application note, many thanks for your help ;)

J-Dunn commented 9 years ago

That application note is not even referenced from either the chip product page nor the board's product page at ST. http://www.st.com/web/en/catalog/tools/PF260715 http://www.st.com/web/catalog/sense_power/FM142/CL851/SC1794/SS1498/LN1724/PF252762?s_searchtype=partnumber

Presumably these boards are aimed at increasing discovery and adoption of ST hardware solutions. If they want people to use their kit, they need get their documentation together. I expect to find ALL necessary information to use a chip in its data sheet, not to need to trawl forums and github and have the good fortune bump into helpful characters like Michel_F.

Michel, it would be useful if you added something the readme file of library explaining the wiring needed more explicitly and possibly linking to the relative pdfs. Thanks for all your help. I've set up the null resistors and have three boards stacked on top of a Uno.

Michel-F commented 9 years ago

J-Dunn, This is done: I added paragraphs 7 and 8 to the readme to give more details about the boards wiring and the daisy chaining.

J-Dunn commented 9 years ago

That's great help. Nice one.

One error: "When the CS is released, the L6474 will interpret the available byte at the SDI and insert the answer at the SDO"

The byte is already internal to the chip when CS goes high. It no longer has anything to do with SDI but it is at this stage that it is latched and decoded. The result is put in the output register ready to be sent out via SDO but this does not happen until later when CS again goes low and the clock input it used to output the data.

Michel-F commented 9 years ago

You're right. I made the changes.

J-Dunn commented 9 years ago

Great. There are a few language errors in your text that you may like to correct too. I guess English may not be your first language, though it's damned good and I have to say better than the vast majority of native speakers, so respect ! Some are typos anyway.

"the user can modifies the L6474 " : can modify "interrupt handler depending of the actions " : depending on "(till using the " : still using " run till reception " : run until "targeted position Else, if the target" : Otherwise, if ...

"one X-NUCLEO-IHM01A1 shield by motor. " : one .... per motor. " one timer and its corresponding ISR by shield. " : one .... per shield

It does not prevent it being perfectly understandable but you seem to be a meticulous and rigorous character, so I think you would like it to be right.

I think this library is a good illustration of how these boards work. It has certainly been useful to me. So thanks for uploading it to github.

Michel-F commented 9 years ago

Thanks for your remarks J-Dunn. I made the corrections.

J-Dunn commented 9 years ago

Hi, I've started getting properly into the code to extract what I need for GRBL. That means fully understanding it to strip it to bare minimum. Unless I'm being dumb I think there is an error.

  1. In L6474::CmdGetStatus(uint8_t shieldId) , it sets up the send data buffers and clears the recv buffer but then it seems like the actual send only gets status for the single shield config , not as advertised, for any one.
 for (i = 0; i < L6474_CMD_ARG_NB_BYTES_GET_STATUS + L6474_RSP_NB_BYTES_GET_STATUS; i++)  // 1+2 bytes resp
  {
     WriteBytes(&spiTxBursts[i][0], &spiRxBursts[i][0]);
  }
  status = (spiRxBursts[1][spiIndex] << 8) | (spiRxBursts[2][spiIndex]);

Doesn't this Write loop need to repeat for all shields to chase the response down the daisychain before trying to extract the relevant status byle?

  for (i = 0; i < numberOfShields; i++)

Hope I'm not being slow ;)

J-Dunn commented 9 years ago

My bad, it's WriteBytes() that loops over the boards. No problem.

J-Dunn commented 9 years ago

While most of the SPI interaction is intialisation of the chip, responding to an input on the error flag by doing at GetStatus() or a non resetting GetParam() seems rather slow on a stack of three cards.

Each SPI send of 8bits at half clock speed takes 1us. So CmdGetStatus(uint8_t shieldId) will take 3*3 plus some loop and fn call overhead. Perhaps 11us to get (and clear) the status of one shield. This all has to happen within a period with interrupts disabled. That adds signifcant jitter to whatever else is running.

It seems that a better strategy may be simply not to call any SPI I/O fns from within ISRs ( eg. set an error variable in the callback, if needed). This would avoid the need to disable interrupts.

If there's a need to change one of the chips' settings , eg lower the current limit, this does not need to be done in time critical path of an ISR.

AFAIK, the SPi hardware runs separtely. There is no real reason to disable interrupts.

Please correct me if I'm wrong but 11us is something I'd want to avoid in a system that has to run three stepper motors on an arduino.

It should be noted that these boards are intended for stm32, not Atmel on a UNO ;)

J-Dunn commented 9 years ago

OK, I've stripped out the essentials to integrate with GRBL. Your lib was a great help in understanding how the daisy chain thing works. Many thanks.

I also found that it is a lot more compact to just clear the Tx and Rx buffers with memset() rather than do exactly what is needed. I defined Tx as twice the size and made Rx point half way down the arrary.

memset(spiTxBursts,L6474_NOP,sizeof(spiTxBursts)); // = 28bytes of object code

The piecemeal code takes about 90 bytes.

I'd like to eliminate all the "if preempted" stuff, so as to minimise the impact on GRBL timing.

Unless I'm missing something, we just need to ensure that nothing in the ISR routines touches the Tx, Rx buffers and it all becomes a lot cleaner and there's no need to block the interrupts for 12us each time.

Am I missing something ??

J-Dunn commented 9 years ago

/* Eventually deactivate motor */

faux ami: eventually != éventuellement

This is confusing, eventually (in Englsh) means after a long wait, but something that will happen. I suggest: /* deactivate motor, if necessary */