MisterPatate
MisterPatate

Reputation: 287

STM32F4 SPI interrupts stop firing with FreeRTOS

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

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

/**
* @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

/* 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 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 move the while(1) loop content to a task, and creates it with

BaseType_t  task1 = xTaskCreate(task_1,  "task_1", 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

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:

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

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 !

Upvotes: 1

Views: 1712

Answers (1)

Richard
Richard

Reputation: 3246

Do you call NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); as described in the red text on this page: https://www.freertos.org/RTOS-Cortex-M3-M4.html ?

If you are using an STM32 with the STM32 driver library then ensure all the priority bits are assigned to be preempt priority bits by calling NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); before the RTOS is started.

Upvotes: 0

Related Questions