cancel
Showing results for 
Search instead for 
Did you mean: 

SPI reception timeouts due to SPI_FLAG_RXP bit on STM32U575

cesarv
Associate II

Hi, i have a project here using an STM32U575RIT6Q with an external device i have connected throught the SPI interface.

The microcontroller is at 160MHz using HSE with PLL. The SPI interface is at 40MHz with SPI mode 0, nss software and 8 bits per word.

The problem surges when i call the function HAL_SPI_Receive. The reception of a long frame breaks up after some received bytes and then timeouts. Due to this timeout i cannot be able to receive the whole frame.

I have made some test on the NUCLEO-U575ZI-Q using the 3 SPI peripherals to check if my SPI interface has any limitation. The result is the same.

Here is the configuration for the SPI interfaces:

/**
  * @brief SPI1 Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  SPI_AutonomousModeConfTypeDef HAL_SPI_AutonomousMode_Cfg_Struct = {0};

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  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_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 0x7;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  hspi1.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
  hspi1.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_SPI_AutonomousMode_Cfg_Struct.TriggerState = SPI_AUTO_MODE_DISABLE;
  HAL_SPI_AutonomousMode_Cfg_Struct.TriggerSelection = SPI_GRP1_GPDMA_CH0_TCF_TRG;
  HAL_SPI_AutonomousMode_Cfg_Struct.TriggerPolarity = SPI_TRIG_POLARITY_RISING;
  if (HAL_SPIEx_SetConfigAutonomousMode(&hspi1, &HAL_SPI_AutonomousMode_Cfg_Struct) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

/**
  * @brief SPI2 Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_SPI2_Init(void)
{

  /* USER CODE BEGIN SPI2_Init 0 */

  /* USER CODE END SPI2_Init 0 */

  SPI_AutonomousModeConfTypeDef HAL_SPI_AutonomousMode_Cfg_Struct = {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_2;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 0x7;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  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;
  hspi2.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
  hspi2.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_SPI_AutonomousMode_Cfg_Struct.TriggerState = SPI_AUTO_MODE_DISABLE;
  HAL_SPI_AutonomousMode_Cfg_Struct.TriggerSelection = SPI_GRP1_GPDMA_CH0_TCF_TRG;
  HAL_SPI_AutonomousMode_Cfg_Struct.TriggerPolarity = SPI_TRIG_POLARITY_RISING;
  if (HAL_SPIEx_SetConfigAutonomousMode(&hspi2, &HAL_SPI_AutonomousMode_Cfg_Struct) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI2_Init 2 */

  /* USER CODE END SPI2_Init 2 */

}

/**
  * @brief SPI3 Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_SPI3_Init(void)
{

  /* USER CODE BEGIN SPI3_Init 0 */

  /* USER CODE END SPI3_Init 0 */

  SPI_AutonomousModeConfTypeDef HAL_SPI_AutonomousMode_Cfg_Struct = {0};

  /* USER CODE BEGIN SPI3_Init 1 */

  /* USER CODE END SPI3_Init 1 */
  /* SPI3 parameter configuration*/
  hspi3.Instance = SPI3;
  hspi3.Init.Mode = SPI_MODE_MASTER;
  hspi3.Init.Direction = SPI_DIRECTION_2LINES;
  hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi3.Init.NSS = SPI_NSS_SOFT;
  hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi3.Init.CRCPolynomial = 0x7;
  hspi3.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  hspi3.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi3.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi3.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi3.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi3.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi3.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi3.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  hspi3.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
  hspi3.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;
  if (HAL_SPI_Init(&hspi3) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_SPI_AutonomousMode_Cfg_Struct.TriggerState = SPI_AUTO_MODE_DISABLE;
  HAL_SPI_AutonomousMode_Cfg_Struct.TriggerSelection = SPI_GRP2_LPDMA_CH0_TCF_TRG;
  HAL_SPI_AutonomousMode_Cfg_Struct.TriggerPolarity = SPI_TRIG_POLARITY_RISING;
  if (HAL_SPIEx_SetConfigAutonomousMode(&hspi3, &HAL_SPI_AutonomousMode_Cfg_Struct) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI3_Init 2 */

  /* USER CODE END SPI3_Init 2 */

}

Here is the test i have developed:

while(1)
{
  HAL_StatusTypeDef state;
  uint16_t lenSpi = 35;
  uint8_t dataArray1[4000];

  memset(dataArray1, 0xFF, sizeof(dataArray1));

  state = HAL_SPI_Receive(&hspi1, &dataArray1[1000], lenSpi, 1000);
  printf("Receive1 %u %u %02X.\n", lenSpi, state, dataArray1[1000]);

  state = HAL_SPI_Receive(&hspi2, &dataArray1[2000], lenSpi, 1000);
  printf("Receive2 %u %u %02X.\n", lenSpi, state, dataArray1[2000]);

  state = HAL_SPI_Receive(&hspi3, &dataArray1[3000], lenSpi, 1000);
  printf("Receive3 %u %u %02X.\n", lenSpi, state, dataArray1[3000]);
}

I added this additional print inside the HAL_SPI_Receive function :

/* Receive data in 8 Bit mode */
  else
  {
    /* Transfer loop */
    while (hspi->RxXferCount > 0UL)
    {
      /* Check the RXP flag */
      if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXP))
      {
        *((uint8_t *)hspi->pRxBuffPtr) = *((__IO uint8_t *)&hspi->Instance->RXDR);
        hspi->pRxBuffPtr += sizeof(uint8_t);
        hspi->RxXferCount--;
      }
      else
      {
        /* Timeout management */
        if ((((HAL_GetTick() - tickstart) >=  Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
        {
          printf("Missing Data to Receive %u from %u.\n", hspi->RxXferCount, Size);
          /* Call standard close procedure with error check */
          SPI_CloseTransfer(hspi);

          SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_TIMEOUT);
          hspi->State = HAL_SPI_STATE_READY;

          /* Unlock the process */
          __HAL_UNLOCK(hspi);

          return HAL_TIMEOUT;
        }
      }
    }
  }

The results are the following ones at 40MHz:

Missing Data to Receive 6 from 35.
Receive1 35 3.
Missing Data to Receive 6 from 35.
Receive2 35 3.
Missing Data to Receive 22 from 35.
Receive3 35 3.
Missing Data to Receive 6 from 35.
Receive1 35 3.
Missing Data to Receive 6 from 35.
Receive2 35 3.
Missing Data to Receive 22 from 35.
Receive3 35 3.
Missing Data to Receive 6 from 35.
Receive1 35 3.
Missing Data to Receive 6 from 35.
Receive2 35 3.
Missing Data to Receive 22 from 35.
Receive3 35 3.

In this output is shown the lenght of the data that was not received,  the total requested data length, and the return value by the HAL_SPI_Receive function. This return value is always 3 that means HAL_TIMEOUT.

I have made this same test with decreasing the SPI frequency to 20MHz and this is the result:

Missing Data to Receive 20 from 1000.
Receive1 1000 3.
Missing Data to Receive 20 from 1000.
Receive2 1000 3.
Missing Data to Receive 843 from 1000.
Receive3 1000 3.
Missing Data to Receive 20 from 1000.
Receive1 1000 3.
Missing Data to Receive 20 from 1000.
Receive2 1000 3.
Missing Data to Receive 843 from 1000.
Receive3 1000 3.

It seems there is a dependancy on the SPI frequency and the triggering of this issue. While less the frequecy, more the data i can receive before the timeout due to the bit SPI_FLAG_RXP not being after some received bytes.
Maybe there is some configuration i am missing? i have made this same test on a STM32L452RET6 and it doesnt occur.

Thanks all.

 

4 REPLIES 4
ASchw.1
Associate II

Hi @cesarv 

Just had the same problem... have you managed to resolve yours? 
After some trial and error I managed to resolve this (still need to confirm by proper testing). What did the trick for me was adding a LL_SPI_Disable call (or any other that will disable your SPI) before calling the HAL_SPI_Receive.
The reason is that HAL_SPI_Receive does some registers inits in the beginning and when done, Enables the SPI (setting SPE bit to 1). Some of those inits should be done when SPI is disabled so making sure we start in disabled state seems to resolve this. Disabling the SPI also flushes internal FIFOs which I find to be not that well documented but perhaps it has something to do with that as well.
Would appreciate your thoughts on this.

Hi @ASchw.1 
Thanks for the replying. I have tried the method u said. But sadly it did not work for me.
The LL_SPI_Disable call resets the SPE bit to 0. i have added this.

CLEAR_BIT(hspi1.Instance->CR1, SPI_CR1_SPE);

Before each HAL_SPI_Receive. This bit clearing is what the LL_SPI_Disable functions does.

The good new is i am looking that the number of missing bytes is different when i use functions that reset the inferface. This may only means that the HAL has some kind of bugs with the treatment of the SPI interface. If i found some configuration or method to resolve this. I will let u know.

urbito
Senior

SPI bus is a syncro communication. 

 

I understand this code is for an SLAVE? but, how are you sincronizing the communication? In the Slave you should be waiting for a Byte to start receiving (IMO).

 

I usually do something like:

 

do{

spi_receive(&hspi, &dataarray, 1, 1);

}while(&datarray != 0xA);

 

Dont take it literally, is just an example. 

 

This is for a device that works in polimode, but you can also make it work in interrupt mode. 

 

What i see wrong is that, probably you are calling SPI_receive without any sincronization and probably the driver has lost data when u calling it. 

 

Maybe i am wrong and totally missunderstood the issue.

 

Hope it helps.

hi @urbito .

Thanks for ur response. This specific code is for SPI in master mode.
I am using the STM32U575RIT6Q micro in order to command some external slave devices.

There are some cases where i need a long transaction in either transmit or receive mode. In these long transactions (for example 1000 bytes), the reception fails cause the bit SPI_FLAG_RXP doesnt get to high anymore before reaching the specified lenght. So the function returns timeout.

The only two things i have discovered are:

  • There are some dependancies of the frequency. I can confirm this since the number of "missing bytes" is lower while the frequency is lower.
  • There are some dependancies on the other configurations. I have confirmed this today while testing the solution @ASchw.1 has said. If u move/reset some of the SPI registers. The number of "missing bytes" is different. Sometimes greater, sometimes lower.