2020-10-22 06:55 PM
Hello,
I am experiencing some weird patterns on one of the 3 SPI buses on CLK and MOSI.
This project was initially developed off a nucleo H743ZI3. I am using 3 SPI ports, 2 of which I have no problem with. These 2 are used to communicate with another MCU (F3) and a motor driver. All these are now on the same PCB.
The third SPI port is used to communicate with an external sensor with relatively short wires. The issue only takes place when the motor is active, so I initially thought it was switching noise and thought once the custom board would be made, with careful grounding and shielding, that the issues would go away.
Well it's not the case, so the issue is occurring both with the development board and the custom board.
When the motor idles, communication with the sensor is great.
However the motor is active, the number of failed CRC verification goes through the roof and communication stops (sensor goes into error state).
I spent a bunch of time looking at switching noise on 5V, 3.3V, etc. And today, I started to take a closer look at what is going on the SPI bus itself. Maybe I should have done earlier.
At this point I don't think the issue is coming from switching noise, but rather a strange behavior on the CLK and MOSI line of that SPI bus.
As you can see on the screenshot, when CS is brought low, it takes a few micro seconds before CLK starts generating its clock. Between the time CS goes low and CLK starts its clock, they should be both pulled down. However, there is a strange pattern on both of these lines. That pattern is causing the sensor to believe a command is coming and tries to interpret it. But since everything is junk (from the number of bytes that the sensor thinks is coming to the bytes themselves), and per datasheet after a certain number of failed communication attempts the sensor will enter its error state.
I think this "junk pattern" is what's causing communication to fail. I can't really understand why, though.
I don't have a good way of modifying the custom board to try to add a hardware pull down. Setting the SPI pins (CLK and MOSI) as pull down does help a little but the pattern can still be seen. During the actual time where CLK is generating its clock, the pattern is not there, however, data will be corrupted due to the sensor has already started interpreting data BEFORE CLK starts its square wave.
Lastly, the pattern doesn't look random to me.
Has anyone ever seen anything like that? I've been scratching my head on this one for a while and I just can't figure it out.
80: idle - with pull down on CLK/MOSI in cubeMX
81: motor active - with pull down on CLK/MOSI in cubeMX
82: idle - without pull down on CLK/MOSI in cubeMX
83: motor active - without pull down on CLK/MOSI in cubeMX
Cheers!
2020-10-22 10:45 PM
That's obviously induced noise on threestated lines. If this is so bad with pull-ups switched on, you still have things to do to eliminate this.
But first thing is, don't disable the SPI between transactions. Using any "library" is no excuse.
JW
2020-10-23 07:57 AM
Hi JW and thanks for your message.
Can you elaborate on the things that I could try to eliminate this? hardware pull-downs?
Also, I'm a bit confused by what you mean about disabling the SPI between transactions.
I don't think I am, that SPI port is on dedicated pins which aren't used for anything else, and SPI is started once and that's it. I'm sending my commands to the sensor once every 125 us off a timer interrupt, and using the receive complete DMA callback.
2020-10-23 11:43 AM
I think the issue is triggered from mosfets switching noise; ripples can be seen on all 4 lines of the SPI bus. But somehow only on CLK and MOSI the ripples cause these lines to "float" which is rather strange.
2020-10-23 12:31 PM
> Can you elaborate on the things that I could try to eliminate this?
I don't think there's one single thing which would eliminate the interference. It's more a broader topic of proper circuit layout. I don't primarily design hardware and even if I would, In not sure if there is one single concise source of relevant information, it's more like lifetime of learning it. Try to ask somebody who does hardware design as primary job, for an opinion.
> Also, I'm a bit confused by what you mean about disabling the SPI between transactions.
> I don't think I am,
Show.
JW
2020-10-23 12:53 PM
I'll post some code shortly.
Generally speaking, how does the STM32 deal with the SPI pins outside of a transaction though? Are they tristated? or are they automatically turned into GPIO's? I assumed once pins are set up as SPI I/O they remain like this until assigned otherwise. And since I am not changing their assignment, I am assuming they remain assigned to SPI even in between transactions. One thing is sure is that I do not call out any function to disable SPI in between transactions.
SPI2 Init:
static void MX_SPI2_Init(void)
{
/* USER CODE BEGIN SPI2_Init 0 */
/* USER CODE END SPI2_Init 0 */
/* USER CODE BEGIN SPI2_Init 1 */
/* USER CODE END SPI2_Init 1 */
/* SPI2 parameter configuration*/
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 0x0;
hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
hspi2.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi2.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI2_Init 2 */
/* USER CODE END SPI2_Init 2 */
}
SPI Start transaction:
void spiStartTransaction() {
HAL_GPIO_WritePin(SPI2_NCS_GPIO_Port, SPI2_NCS_Pin, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive_DMA(&hspi2, (uint8_t*)spi_dma_tx_, (uint8_t*)spi_dma_rx_, 6);
}
SPI Callback:
void spiCallback() {
HAL_GPIO_WritePin(SPI2_NCS_GPIO_Port, SPI2_NCS_Pin, GPIO_PIN_SET);
//data processing
}
2020-10-23 01:31 PM
Hello Smon.1,
Try setting AFCNTR in SPI_CFG2 (bit # 31). I used "LL_SPI_EnableGPIOControl" in the LL library for this. This will let the SPI retain control of it's outputs between/after transmissions. I find the reference manual description a bit limited - suggest you test for yourself.
Regards,
Dave
2020-10-23 02:10 PM
Hi David
very good insight, thank you.
In cubeMX I found a setting with similar meaning to the one you proposed and it's called "Master Keep IO State", by default it was disabled. I set it to enabled, flashed.
in idle I could immediately a improvement (the steps on CLK/MOSI) are gone. That idle looks close to perfect.
With the motor active, the weird pattern is gone (thank you!) and we're left with a bit of excessive switching noise.
The results are better, though it is still a bit too high for correct operations, with too many CRC error on these SPI transactions.
here is what the screenshot looks like while the motor is active.