cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 SPI slave TX/RX error: how to reset SPI?

dvd
Associate II

Hi, I'm using an STM32F413RG MCU as SPI full-duplex slave, initialization is done in Cube. Every 500ms the master activate the SPI_CLK (1MHz) and the MCU outputs 16 bytes of data while receiving other 16 bytes from the master (using HAL_SPI_TransmitReceive_IT). The problem is that after some time (from seconds to hours) the communication is broken since the data sent by MCU are shifted of 1 byte (the last byte from previous transfer appears as the first one in the current transfer) and the MCU does not enter anymore in the HAL_SPI_TxRxCpltCallback when it receive data even if the data arrive correctly (the 16 bytes buffer I use as input buffer is filled with the data I send from master and they are correct, but there is no interrupt callback).

Using HAL_SPI_ErrorCallback() I saw that after the first error all the subsequent transfer generate an error, which is always HAL_SPI_ERROR_FLAG.

For what I understood from other users having similar issue this is due to the SPI FIFO not being fully empty.

Which is the way to resolve this issue? It seems there is no way to flush the SPI FIFOs on STM32F4 MCUs (I tried with HAL_SPI_DeInit and then re-initialize, but it has no effect). Also it would be nice not to have this error at all.

SPI init code:

/* SPI2 init function */
void MX_SPI2_Init(void)
{
 
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_SLAVE;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
 
}
 
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */
 
  /* USER CODE END SPI2_MspInit 0 */
    /* SPI2 clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();
  
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**SPI2 GPIO Configuration    
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    PC7     ------> SPI2_SCK 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15;
    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(GPIOB, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = 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_SPI2;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
    /* SPI2 interrupt Init */
    HAL_NVIC_SetPriority(SPI2_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(SPI2_IRQn);
  /* USER CODE BEGIN SPI2_MspInit 1 */
 
  /* USER CODE END SPI2_MspInit 1 */
  }
}

2 REPLIES 2

There's no FIFO in the 'F4's SPI. There is of course the one-frame holding buffer, but it's not the problem you have.

Your problem is interrupt latency. You are probably running other interrupts of higher or the same priority as this one, and that causes that the SPI Tx underruns. Unfortunately, in 'F4, the SPI does not set the UDR flag in SPIx_SR, except if in I2S mode which is not your case.

So the solution is either to push the priority of this interrupt higher than the others', or use DMA.

JW

dvd
Associate II

First of all thank you for pointing out that there is no FIFO in F4 MCUs, all the posts I found on similar behaviour for other MCUs spoke about FIFOs so I assumed it was the same for F4.

I will try both solutions you suggest.

Thanks again