cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F0 SPI Timeout Error with illegal HAL state

janos2
Associate II
Posted on August 19, 2016 at 12:28

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 #stm32-stm32f0-spi-bug-problem
4 REPLIES 4
Posted on August 19, 2016 at 12:59

Szia Janos,

I don't and won't use Cube, but aren't you supposed to use HAL_SPI_TransmitReceive_IT() instead of HAL_SPI_TransmitReceive(), once you have enabled the SPI interrupt?

JW

janos2
Associate II
Posted on August 19, 2016 at 13:55

Hi Jan,

actually I am going to use the _IT function with interrupt, but I see similar behaviour there. I was using the non-interrupt implementation as a cleaner way to track down the source of the problem.

When I disable the interrupt configuration, the behaviour stays the same.

Cheers

Janos

Posted on August 19, 2016 at 22:21

It's ''hummmm'' then...

You may want to check the state of fifo level at the point of failure.

I downloaded the latest 'F0 Cube to check the function in question and I see that it is using the data packing feature. There is an unsettling erratum for the 'F031 basically rendering the data packing unusable; but this erratum is not present in the 'F072 errata.

I personally would write my own copy of that function avoiding the data packing; but I would not use Cube at all from start... 😉

JW

janos2
Associate II
Posted on August 22, 2016 at 13:41

Hi Jan,

thanks for your advise. I noticed three more interesting things by now. I am using a ring-buffer to output printf() debug messages over UART3 with interrupts. The things i noticed are:
  1. When I use

    HAL_SPI_TransmitReceive

    () (without interrupt) and don't use printf(), everything works fine.
  2. When I use

    HAL_SPI_TransmitReceive

    () (without interrupt), and disable the UART3-interrupts before (and re-enable it afterwards), SPI works fine.
  3. However when I use

    HAL_SPI_TransmitReceive_IT

    () and idle-wait for SPI to be ready, after 10-300 successful transmissions, the SPI-hangs (because XferCount>0), even if I don't initialize and use UART at all.
So I can fix my buggy behaviour for now by deactivating UART-interrupts during SPI transmissions. But it doesn't make any sense to me, what is going on. For the record: The SPI-interrupt-priority is 1 and the UART-interrupt-priority is 3. The SysTick-interrupt priority is 0. I have deactivated all other peripherals for my tests. Does this make any sense to you? Cheers, Janos