cancel
Showing results for 
Search instead for 
Did you mean: 

SPI Master/Slave (both STM32 controllers) communication errors

beeran
Associate

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!

6 REPLIES 6
Ozone
Lead

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.

Thanks!

I've tried it with baudrate-prescaler 256 (=> 312,5kHz) and 128 (=> 625kHz). Same, wrong result.

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).

berendi
Principal

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).

S.Ma
Principal

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.

S.Ma
Principal

And for the slave, try SPI_BAUDRATEPRESCALER_16