AnsweredAssumed Answered

STM32F0 SPI Timeout Error with illegal HAL state

Question asked by Janos on Aug 19, 2016
Latest reply on Aug 22, 2016 by Janos
Hello,
[I have just written my issue in detail and it has been deleted when I clicked Ok. Thanks, I will write it again though.]

We are using the STM32F072CB with the HAL driver in our application and facing serious trouble with the SPI. The peripheral code was generated by STM32CubeMx. The CPU runs at 48MHz and the SPI at 3MHz.
I have tracked down the problem to be a TIMEOUT condition in HAL_SPI_TransmitReceive(). I can reproduce the error by too frequent calls to that function.

The strange (and in my eyes, buggy!) reason for the timeout condition in the TransmitReceive function is an illegal state of the SPI instance, &hspi2. When it runs into timeout, these parts of the state don't make sense:
TxXferSize = 31 // ok
TxXferCount = 0 // ok
RxXferSize = 31 // ok
RxXferCount = 1 // wrong

So the HAL thinks that there is 1 more word to receive, which i a clear violation of how SPI works and how the HAL function is written.

So appart from not understanding this condition, I can solve the problem by implementing a little delay after every TransmitReceive call. Then everything works fine.

Here is how I reproduce the behaviour. The following loop is run in the main() right after the initialization of CubeMx:

uint8_t txBuffer[31];
uint8_t rxBuffer[31];
while(1) {
  // A short delay avoids trouble
  for (uint32_t i = 0; i < 500; i++);
  uint8_t status;
  status = HAL_SPI_TransmitReceive(&hspi2 ,txBuffer, rxBuffer, 31, 1000);
  printf("s");
  if (status != 0)
    printf("\nERROR\n");
}

In case you wonder, here are the initialization routines of the SPI:

void MX_SPI2_Init(void)
{
 
  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.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 = 7;
  hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
 
}

and

else if(spiHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */
 
  /* USER CODE END SPI2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();
   
    /**SPI2 GPIO Configuration   
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF0_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* Peripheral 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 */
  }

The clock polarity and phase are triple-checked with the SPI-target and do work in general.

Do you guys have an idea what is going on here and how to solve the issue? Am I missing some timing constraint on when I am allowed to call the HAL TransmitReceive function? Why do I have to wait so long?

Any hints on this problem are much appreciated!
Have a great weekend,
Cheers, Janos

Outcomes