Author Topic: STM32F4 SPI interrupts stop firing with FreeRTOS  (Read 2613 times)

0 Members and 1 Guest are viewing this topic.

Offline MisterPatateTopic starter

  • Newbie
  • Posts: 4
  • Country: ch
STM32F4 SPI interrupts stop firing with FreeRTOS
« on: November 23, 2018, 11:49:58 am »
Hello everybody !  :)

I'm trying to make an SPI communication between a F410 MCU and a RPi using SPI. I post below the code that currently works (without FreeRTOS usage):

main.c
Code: [Select]
volatile int tx_done = 0;
volatile int rx_done = 0;

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
    tx_done = 1;
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
    rx_done = 1;
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_SPI5_Init();
    MX_USART2_UART_Init();

    const uint8_t BUF_SIZE = 16 * sizeof(uint8_t);
    uint8_t buf[16];

    // For UART debug
    uint8_t dbg_buffer[64];
    while (1) {
        memset(buf, 0, BUF_SIZE);
        HAL_StatusTypeDef ret = HAL_SPI_Receive_IT(&hspi5, (uint8_t*)&buf, BUF_SIZE);
        while (rx_done == 0) {};
        rx_done = 0;

        sprintf((char*) dbg_buffer, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d]\r\n",
                                    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
                                    buf[7], buf[8], buf[9], buf[10], buf[11], buf[12],
                                    buf[13], buf[14], buf[15]);
        HAL_UART_Transmit(&huart2, dbg_buffer, strlen((char const*) dbg_buffer), 50);

        HAL_SPI_Transmit_IT(&hspi5, (uint8_t*) &buf, BUF_SIZE);
        while (tx_done == 0) {};
        tx_done = 0;   
    }
}

stm32f4xx_it.c
Code: [Select]
/**
* @brief This function handles TIM1 trigger and commutation interrupts and TIM11 global interrupt.
*/
void TIM1_TRG_COM_TIM11_IRQHandler(void)
{
  HAL_TIM_IRQHandler(&htim11);
}

/**
* @brief This function handles SPI5 global interrupt.
*/
void SPI5_IRQHandler(void)
{
  HAL_SPI_IRQHandler(&hspi5);
}

spi.c
Code: [Select]
/* SPI5 init function */
void MX_SPI5_Init(void)
{

  hspi5.Instance = SPI5;
  hspi5.Init.Mode = SPI_MODE_SLAVE;
  hspi5.Init.Direction = SPI_DIRECTION_2LINES;
  hspi5.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi5.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi5.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi5.Init.NSS = SPI_NSS_HARD_INPUT;
  hspi5.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi5.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi5.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi5.Init.CRCPolynomial = 15;
  if (HAL_SPI_Init(&hspi5) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
    [...]
    HAL_NVIC_SetPriority(SPI5_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(SPI5_IRQn);
}

This is working fine with my test code on the other (raspberry pi) side, sending a SPI frame every second, waiting 100ms and reading the answer from the F410.

Now, when I activate FreeRTOS (I used CubeMX), I move the while(1) loop content to a task, and creates it with

Code: [Select]
BaseType_t  task1 = xTaskCreate(task1,  "task1", 512, NULL, tskIDLE_PRIORITY, &xHandle);

and osKernelStart(). I also use the TIM11 as Timebase Source (under SYS tab on CubeMX as advised by the software itself)

Then I have the following behavior: If I place breakpoints inside both Tx/Rx SPI interrupt, I found that a couple (3-4 ?) of them are fired, then never again. If I stop my code I see I'm stucked in the

Code: [Select]
while (rx_done == 0) {};

loop, confirming that I don't get SPI RX interrupts anymore whereas there is still frame coming on the SPI bus...

To dig a little into that theory, I made another test with this in my task:

Code: [Select]
	while(1) {
memset(buf, 0, 16);

HAL_StatusTypeDef ret = HAL_SPI_Receive_IT(&hspi5, (uint8_t*)&buf, 16);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
                // Wait for RX interrupt, task is suspended to give processing time to (incoming) others tasks
vTaskSuspend(NULL);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
        }

and in my Rx interrupt, I simply call
Code: [Select]
xTaskResumeFromISR(task1Handle);

With this code, the first packet sent is read correctly by the STM32F4, and task print it on USART2 and suspend itself again. From then, (checked with a breakpoint inside), the Rx interrupt is never called again, so the task resume inside neither, and my code is frozen...

It really looks like there is a messing between FreeRTOS and STM32 HAL SPI/interrupt handling ?

Any help will be gladly accepted !
« Last Edit: November 23, 2018, 11:59:52 am by MisterPatate »
 

Offline MadScientist

  • Frequent Contributor
  • **
  • Posts: 439
  • Country: 00
Re: STM32F4 SPI interrupts stop firing with FreeRTOS
« Reply #1 on: November 23, 2018, 12:02:12 pm »
Is the smt32 Hal ( cubemx ) compatible with freeRTOS ? , I didn’t think it was

Dave
EE's: We use silicon to make things  smaller!
 

Offline MisterPatateTopic starter

  • Newbie
  • Posts: 4
  • Country: ch
Re: STM32F4 SPI interrupts stop firing with FreeRTOS
« Reply #2 on: November 23, 2018, 12:05:56 pm »
It is, I configurated FreeRTOS within the CubeMX app.

https://www.freertos.org/FreeRTOS-Plus/BSP_Solutions/ST/STM32Cube.html
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4315
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: STM32F4 SPI interrupts stop firing with FreeRTOS
« Reply #3 on: November 23, 2018, 12:19:28 pm »
It's always worth looking at the hardware registers for the peripherals involved. See how they're really set up, what's enabled and what isn't, and whether there are any error flags set which will prevent normal operation until they're cleared.

For example, if a UART Rx interrupt is never called, this could be because this interrupt is disabled in the NVIC, or the UART receive IE bit isn't set, or interrupts are globally disabled, or reception is disabled due to (say) a framing error.

Reading the hardware registers directly and comparing them against the descriptions in the Reference Manual is the only definitive way to tell. From there, you'll have a way to work backward and see exactly where an undesirable register change was made, and why.

Offline MisterPatateTopic starter

  • Newbie
  • Posts: 4
  • Country: ch
Re: STM32F4 SPI interrupts stop firing with FreeRTOS
« Reply #4 on: November 23, 2018, 01:51:35 pm »
Does those registers available in hspi struct ? I must use the HAL here, so just asking
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4315
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: STM32F4 SPI interrupts stop firing with FreeRTOS
« Reply #5 on: November 23, 2018, 02:59:58 pm »
I honestly have no idea, but even if they were, anything you get from the HAL will tell you how the hardware should be configured, not necessarily how it is configured.

Eliminate as many sources of error as you can. By going straight to the hardware, you're able to find out definitively what's wrong, and then you can work backwards to figure out why. You'll find that the parameters you have to pass to the HAL are pretty similar to the register map anyway.

Offline MisterPatateTopic starter

  • Newbie
  • Posts: 4
  • Country: ch
Re: STM32F4 SPI interrupts stop firing with FreeRTOS
« Reply #6 on: November 23, 2018, 03:11:52 pm »
Do you have any links to the correspondant documentation ? I'm afraid I don't know where to start.
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4315
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: STM32F4 SPI interrupts stop firing with FreeRTOS
« Reply #7 on: November 23, 2018, 03:39:24 pm »
ST page for the STM32F410 processor:

https://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32-high-performance-mcus/stm32f4-series/stm32f410/stm32f410c8.html

The Reference Manual contains all the register settings in detail:
https://www.st.com/resource/en/reference_manual/dm00180366.pdf

Your IDE should be able to help you here. If, for example, you think there's a problem with peripheral SPI1, you should just be able to set a watch on "SPI1" and it'll show you a structure containing all the register names and their current values. For example, the status register is called SR, and it can be read just by accessing SPI1->SR.

All the register names and locations are defined in the HAL headers - which, IMHO, is the one thing they're good for.


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf