cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_SPI_TransmitReceive_IT() never completes

andrew
Associate II
Posted on October 20, 2014 at 13:10

I am having an issue with the STM32Cube HAL function, HAL_SPI_TransmitReceive_IT(). I am using the STM32CubeF2 library with STM32CubeMX tool to generage most of the initialisation code.

I have an STM3220G evalutation board (STM32F207) modified to connect to a single SPI FRAM device via the SPI2 peripheral (full duplex master, 2 line, ~1.8MHz, software controlled chip select). There are no other SPI slaves present.

When using HAL_SPI_TransmitReceive_IT() to communicate with said device using a data length > 1, I never see the HAL_SPI_TxRxCpltCallback() function called.

Here is the SPI2 init (Cube auto-generated):

/* SPI2 init function */

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.FirstBit = SPI_FIRSTBIT_MSB;

 

hspi2.Init.TIMode = SPI_TIMODE_DISABLED;

 

hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;

 

HAL_SPI_Init(&hspi2);

}

And the msp function (also auto-generated):

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)

{

  GPIO_InitTypeDef GPIO_InitStruct;

  if(hspi->Instance==SPI2)

  {

    /* Peripheral clock enable */

    __SPI2_CLK_ENABLE();

  

    /**SPI2 GPIO Configuration    

    PC2     ------> SPI2_MISO

    PC3     ------> SPI2_MOSI

    PB10     ------> SPI2_SCK 

    */

    GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;

    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;

    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;

    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* Peripheral interrupt init*/

    /* Sets the priority grouping field */

    HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

    HAL_NVIC_SetPriority(SPI2_IRQn, 3, 0);

    HAL_NVIC_EnableIRQ(SPI2_IRQn);

  }

}

The board was modifed as specified in the STM3220G user manual to disconnect the various active components on SPI2. I have also used a 'scope to verify all signals. There doesn't appear to be anything wrong with the data being transmitted, or the correct number of clocks being generated so that the receive data can be shifted out of the FRAM device.

I instrumented the interrupt handling inside the HAL driver and this is what I see for a single byte full duplex transfer (TXE = SPI_TxISR() & RXNE = SPI_2LinesRxISR()):

TXE (SPI_TxCloseIRQHandler), RXNE (SPI_RxCloseIRQHandler()

Now I do the same for a four-byte full duplex transmission:

TXE, TXE, RXNE, TXE, RXNE, TXE (SPI_TxCloseIRQHandler)

I would have expected another two RXNE interrupts after the closing of Tx. However, they never happen, which means SPI_RxCloseIRQHandler() is never called, which means HAL_SPI_TxRxCpltCallback() isn't called either.

If I go and stick breakpoints in both the interrupt handling routines (I'm using IAR EW 7.2), slowing them down markedly, the transfer is successful!

TXE, RXNE, TXE, RXNE, TXE, RXNE, TXE (SPI_TxCloseIRQHandler), RXNE, (SPI_RxCloseIRQHandler)

There seems to be a weird race condition working, but I am having difficulty pinpointing the cause. Has anyone else seen anything like this? If further information is required I will do my best to supply it.

EDIT: I should add that the polled-mode function HAL_SPI_TransmitReceive() works fine.
5 REPLIES 5
Posted on October 21, 2014 at 11:12

Hi,

It seems an issue related to the SPI peripheral frequency, can you try to increase the baud rate prescaler to FCPU/32 or FCPU/64 ?

Let me know if this helps or if you have further questions.

Regards,

Heisenberg.

andrew
Associate II
Posted on October 21, 2014 at 13:02

Thanks for your response.

Increasing the baud rate prescaler to 32 from 16 seems to improve the situation (in the initial small amount of testing I've done so far).

My follow-up question is, ''Why?'' I haven't found anything in the user manual that states that SPI should be run at a certain prescaler setting in order for non-DMA mode interrupts to work properly. With the prescaler set to 32, the SPI is running at a very sedate ~937kHz, which isn't really acceptable.

I attach our CPU clock configuration, is there anything in it that could be contributing to this problem, or is it a known issue with some other aspect of the STM32CubeF2 libraries or even the STM32F207 processor itself?

________________

Attachments :

stm32f2_clocks.JPG : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006Hz2n&d=%2Fa%2F0X0000000bMv%2FXde3rGgnJmktdB_lMgKVzvCI9QSUGoEpfcssMQzOawQ&asPdf=false
Posted on October 21, 2014 at 15:25

In fact the SPI TX and RX interrupt processes are using the same IRQ line. Thus depending on the time required to interpret the SPI TX/RX IRQ handler, to make it work properly you can optimize manually the SPI IRQ handler HAL_SPI_IRQHandler() provided within the STM32CubeFW, by removing the SPI error management as an example, in order to serve each TX/RX interrupt at time, otherwise decreasing the SPI peripheral frequency may be also a workaround.

Regards,

Heisenberg.
andrew
Associate II
Posted on October 22, 2014 at 11:17

After a closer examination of the SPI IRQ handler, I have managed to observe an overrun condition. What I had not realised was that the overrun bit is cleared merely by reading the DR and SR consecutively, which means I had managed to miss it, d'oh!

We have backed off the baud rate for now until we have a DMA implementation.

Many thanks again for your help.

Amel NASRI
ST Employee
Posted on October 22, 2014 at 12:31

What I had not realised was that the overrun bit is cleared merely by reading the DR and SR consecutively, which means I had managed to miss it, d'oh!

Using the debugger to read some peripherals registers may cause such issue as it leads to clearing some flags like OVR in your case.

In RM0033, it is said ''Clearing the OVR bit is done by a read operation on the SPI_DR register followed by a read access to the SPI_SR register.''.

-Mayla-

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.