2017-05-16 02:35 PM
To run multiple STM32F7's as SPI Slaves I enable/disable their active control of MISO using:
/* Enable MISO to be actively driven (i.e., controlled by the SPI2 module). */
GPIO_InitStruct.Pin = SMCU_SPI2_MISO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;HAL_GPIO_Init( SMCU_SPI2_MISO_GPIO_Port, &GPIO_InitStruct );
...and:
/* Set MISO to be an input until it needs to be actively driven (only when I'm sending to the SPI Master). */
GPIO_InitStruct.Pin = SMCU_SPI2_MISO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init( SMCU_SPI2_MISO_GPIO_Port, &GPIO_InitStruct );
This works well...until it doesn't. ;) After some (highly variable) number of SPI transactions I see a Slave simply not drive MISO even though control of the pin has been given to the SPI module via the code above. A logic analyzer trace shows that the Slave appears to start driving MISO but then stops driving it after about 1 uS. (I can tell this because the Slaves are set to apply their pullups when their MISO pins are configured as inputs in the code above and the Slave-produced data begins and ends with 0's.) Here's a logic analyzer trace of a good SPI transaction followed by a failing one:
(I have no idea if anyone's going to be able to see that, so I'll attach it as well and hopefully that'll be more readable.)
The yellow/green pair of signals shows a successful transfer from a Slave. The bottom red trace (MISO) goes to 0 near the rising edge of the yellow signal, as expected and the correct data is clocked out of the Slave. The blue/violet pair of signals shows where the Slave starts to drive MISO near the rising edge of the blue signal but then abandons it and leaves the Master to clock in all those 1's. Note that the SPI data being produced by the Slaves are identical. Note also the position of the logic analyzer's timeframe scrolling marker (the gray circle at the bottom of the trace). Thousands of SPI transfers had occurred flawlessly for 3 Slaves until suddenly blue/violet decided to not play anymore.
By the way, there's no error returned from HAL_SPI_Transmit_DMA() and the SPI error callback isn't being called.
Any insights or recommendations would be eagerly received.
Thanks,
Dave
#spi-slave-miso2017-05-16 04:28 PM
To run multiple STM32F7's as SPI Slaves I enable/disable their active control of MISO using:
Upon what stimulus? How is NSS set?
Slave appears to start driving MISO but then stops driving it after about 1 uS. (I can tell this because the Slaves are set to apply their pullups when their MISO pins are configured as inputs in the code above and the Slave-produced data begins and ends with 0's.)
You can't tell the slave driving MISO high from releasing the pin, from a LA. Use a divider ('pull-mid') and an oscilloscope. You can't use the 'data begins and ends with 0' argument as clearly something goes wrong and you don't know what.
Also the red trace doesnt' appear to end in 0, but I admit an important detail might have lost in the low resolution.
If the 'freeze' is permanent, read out the relevant SPI/DMA/GPIO registers and compare to expected values.
JW
PS. I wonder why don't you use the native NSS signaling.
2017-05-17 09:02 AM
Hi Jan, thanks for replying. I'll try address your questions/concerns below:
Upon what stimulus? How is NSS set?
The Slaves are set to Software NSS management (SSM = 1). In the logic analyzer trace, the Slave NSS signals are the ..._CSn signals. Above each of them you'll see the ..._INTn signals, the rising edge of which is used to determine when the Slave MISO is set to be controlled by the SPI module. (It's returned to a GPIO input at the rising edge of NSS/CSn.)
You can't tell the slave driving MISO high from releasing the pin, from a LA. Use a divider ('pull-mid') and an oscilloscope. You can't use the 'data begins and ends with 0' argument as clearly something goes wrong and you don't know what.
You're right (and I was wrong in saying the data 'ends with 0' - sorry) but I do know that in this case the Slaves are each producing exactly the same data frames. So every Slave-produced SPI transaction should look exactly like the one shown for the yellow/green signal pair. In that transaction MISO is driven to 0 by the yellow/green Slave as soon as its control of MISO is enabled (rising edge of yellow) and then follows the data in the first 4 16-bit clock bursts. The blue/violet transaction should be identical through its first 4 clock bursts (at the very least, during the clock bursts).
It's probably a good idea to use the scope and divider to determine if MISO is being driven with a 1 or it's just been somehow released/tristated. However, if the configure the GPIO input to GPIO_PULLDOWN I get exactly the same type of failure, except with 0's instead of 1's.
If the 'freeze' is permanent, read out the relevant SPI/DMA/GPIO registers and compare to expected values.
I probably should have mentioned that - no problem was indicated in any of the registers. It appears the DMA/SPI is dutifully waiting for the next SPI clock burst(s) and the correct frame data is in the SPI DR.
PS. I wonder why don't you use the native NSS signaling.
I'm not completely sure I understand this. This approach is based on the Reference Manual's Figure 390 Note 2, except that an open-drain MISO is silly if you need a decent SCK rate. Might as well use I2C if that's a real restriction for a multi-Slave SPI configuration. Changing the MISO pin GPIO configuration should work.
Oh, this may not have been clear: this failure mode is not unique to Slave 3 (blue/violet). It'll happen on any of the 3 Slaves.
Thanks again for your time.
2017-05-17 09:16 AM
Is the 'freeze' permanent, i.e. the slave which threw the error does not communicate anymore?
JW
PS. Which STM32?
2017-05-17 09:28 AM
PS. I wonder why don't you use the native NSS signaling.
I'm not completely sure I understand this. This approach is based on the Reference Manual's Figure 390 Note 2, except that an open-drain MISO is silly if you need a decent SCK rate.
What?
I admit I have never used an STM32 SPI in multi-slave setup. Lucky me it appears.
So I looked it up... (in a randomly chosen 'F7 RM):
As MISO pins of the slaves are connected together, all slaves must have the GPIO configuration of their MISO pin set as alternate function open-drain
WTF??? NSS in slave does not threestate MISO??? Seriously???
Now, the SPI in STM32 is ***ed up in so many ways, that I am not surprised. Just sad.
Btw., RM0090 (STM32F4xx) does not appear to care to mention this at all.
Regardless, this does not explain your problem.
JW
[EDIT] Forked into
2017-05-17 02:37 PM
At this moment it doesn't really sound like an SPI-related problem.
._INTn signals, the rising edge of which is used to determine when the Slave MISO is set to be controlled by the SPI module. (It's returned to a GPIO input at the rising edge of NSS/CSn.)
Well, in the given erratic case it was apparently not upon the rising edge of that CSn signal, so I'd start to seek problems there - aren't there spurious noise spikes on that signal, isn't there some other mechanism of GPIO corruption (e.g. atomicity issues if the same GPIO registers are RMW-accessed in ISR).
I'd toggle an unused pin in the routine where the CSn rising edge is detected and observe that by the LA together with the rest.
JW
2017-05-17 04:54 PM
Funny you should mention the GPIO instrumentation...I added some to track when I was flipping the MISO signal to GPIO. It showed that in the failing SPI transaction I was indeed flipping it back to GPIO soon after giving it to the SPI. This was due to an early SPI receive or transmit completion indication. What causes that is still under investigation but at least I'm not doubting the hardware anymore.
Thanks again - I think I'm back in business.
2017-05-17 05:29 PM
SPI receive or transmit completion indication.
What's that?
JW
2017-05-18 07:58 AM
It's a HAL thing... ;)