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.
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.