Inetrrupt enable causes hard fault

auraner wrote on Tuesday, May 28, 2019:

Hi all,

I am using FreeRTOS on a CM4F port (STM32F429ZI) with CubeMX. In this scheme, there is a timer interrupt (Cortex timer periphery, not RTOS timer), that should periodically transmit some data over SPI using interrupt. The RTOS timer cannot be used due to requirements in precision/realtime.

Without FreeRTOS, it works fine, the SPI transmit function HAL_SPI_Transmit_IT() gets called from timer elapsed callback and the according TxCplt interrupt is called upon completion.

However, when FreeRTOS is running, the call HAL_SPI_Transmit_IT(), called from timer elapsed callback, results in a hard fault crash. It is namely the setting of the CR register in __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_RXNE | SPI_IT_ERR)) that causes the crash.

The mentioned interrupts do not call any FreeRTOS API functions. SPI interrupt is currently on priority 1 and the timer interrupt on priority 2 (seen from Cortex-M port, 0 = highest prio). However, having both on priority 5 (which is set as the threshold for RTOS API functions, configMAX_SYSCALL_INTERRUPT_PRIORITY) does not change anything in the behaviour. Without the timer and SPI interrupt, FreeRTOS works fine.

Any ideas? Thanks a lot in advance.

Cheers,
auraner

heinbali01 wrote on Wednesday, May 29, 2019:

I am using FreeRTOS on a CM4F port (STM32F429ZI) with CubeMX.
In this scheme, there is a timer interrupt (Cortex timer periphery,
not RTOS timer), that should periodically transmit some data over
SPI using interrupt. The RTOS timer cannot be used due to
requirements in precision/realtime.

When I read this, and without reading further, I think of an alternative solution of which I think it will also meet the requirements, and that will have less problems.

A timer goes off, triggers an interrupt, and why don’t you wake-up a task that will send the SPI data.

volatile uint32_t ulLastTimeCount;
void vTimerInterrupt( )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    /* Make sure the Timer interrupt won't be repeated. */
    uint32_t ulStatus = Instance->SR;
    if( ( ulStatus & TIM_FLAG_UPDATE ) != 0 )
    {
        /* May be different in your case. */
        Instance->SR = ~(TIM_FLAG_UPDATE);
        ulLastTimeCount = Instance->CNT;

        /* Wake-up the task and yield. */
        if( xMyTaskHandle != NULL )
        {
            vTaskNotifyGiveFromISR( xMyTaskHandle, &xHigherPriorityTaskWoken );
            portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
        }
    }
}

Alternatively, you can send a message to a task ( xQueueSendFromISR() ) which will wake it up.

I don’t think that HAL_SPI_Transmit_IT() was written to be called from an interrupt context. It may work in a bare-metal application, but I would not recommend to use it in a multi-tasking system.