SPI Master/Slave (both STM32 controllers) communication errors
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2019-12-12 5:39 AM
I'm using two STM32 controllers and the CubeMX-HAL. The two controllers can communicate trough SPI (STM32L476 as Master, STM32F410 as Slave).
The master sends the data correctly (this has been proved with a logic analyzer), but the slave is receiving something very different.
Has anyone an idea what can be the purpose of this behavior?
Hardware-Setup:
Both controllers are powered via 3.3V. GND is connected. SPI1 is used on both controllers.
MOSI is connected to MOSI (Master PA7 -> Slave PA7)
MISO is connected to MISO (Master PA6 -> Slave PA6)
SCLK is connected to SCLK (Master PA5 -> Slave PA5)
CS is connected, but currently used for another purpose (Master PA4 -> Slave PA4).
There is no other device on the SPI, therefore CS is not needed from my point of view.
Master SPI-Init:
SPI_HandleTypeDef hspi1;
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
//Enable Clocks
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
//Init SPI-Pins
GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
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_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//Init SPI
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 15;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK) {
Error_Handler();
}
Slave SPI-Init:
SPI_HandleTypeDef hspi1;
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
//Enable Clocks
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
//Init SPI-Pins
GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
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_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//Init SPI
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_SLAVE;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 15;
if (HAL_SPI_Init(&hspi1) != HAL_OK) {
system_debugMessage(DEBUG_PREFIX "Cannot init SPI");
NVIC_SystemReset();
}
Master-RX/TX:
uint8_t rxData[10], txData[10];
// ==> Fill txData with data to send
if (HAL_SPI_TransmitReceive(&hspi1, txData, rxData, 10, 100) != HAL_OK) {
Error_Handler();
}
Slave-RX/TX:
uint8_t rxData[10], txData[10];
// ==> Fill txData with data to send
//Transmit the data
if (HAL_SPI_TransmitReceive(&hspi1, txData, rxData, 10, 100) != HAL_OK) {
system_debugMessage(DEBUG_PREFIX "Communication error");
NVIC_SystemReset();
}
Some additional informations:
- Both RX/TX-Functions return HAL_OK.
- System-Clock on master is higher than on slave (master 80MHz, slave 16MHz). For this reason I used a 64 as prescaler at master-SPI-init.
- Master uses FreeRTOS while slave has no RTOS.
Thanks in advance!
- Labels:
-
SPI
-
STM32CubeMX
-
STM32L4 Series
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2019-12-12 5:44 AM
If clock polarity and phase are the same, try reducing the clock significantly (at least factor 10).
Might be impedance and/or propagation delay issues.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2019-12-12 6:00 AM
Thanks!
I've tried it with baudrate-prescaler 256 (=> 312,5kHz) and 128 (=> 625kHz). Same, wrong result.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2019-12-12 6:33 AM
Have you checked with a scope, and does it look ok ?
> hspi1.Init.NSS = SPI_NSS_SOFT;
Long time ago when I last messed with SPI, but I think it means "Slave Select (a.k.a. CS) controlled by software".
You would need to set it accordingly (see reference manual).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2019-12-12 9:08 AM
Without CS the slave has no reliable way to determine when the master has started (and stopped) to transmit.
If the slave comes online when the master has already started transmitting (which is quite likely because the slave is slower), it will start shifting in (and out) bits whenever the clock is pulsed.
Even if you ensure that the master starts sending when the slave is ready to receive, the slave might detect a false clock pulse when the master initializes the SPI port, and all received data will be shifted by one bit.
Find a way to free up the PA4 pins to use as a proper NSS signal (perhaps incorporate whatever it does in the SPI data). Configure PA4 as a plain GPIO output on the master, set it low before starting to transmit, and high afterwards (otherwise it would be somewhat tricky to manage properly).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2019-12-12 11:05 AM
Alas,why is there a start and stop bit on I2C? If they would not be needed, so is NSS.
True, you need a start and stop even for the slave to synchronize. Use EXTI on NSS in slave mode to know what is happening.
And as slave, you don't know when the transaction starts and end. So use DMA on SPI to buffer in circular mode.
Ideally use a header which contains the payload length and a header to make sure the data is valid.
Then some rugged communication can take place.
Advice: use 4 wire SPI interface. Others maybe problematic.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2019-12-12 4:00 PM
And for the slave, try SPI_BAUDRATEPRESCALER_16
