Cortex-M4 vPortEnterCritical() altering BASEPRI register before vTaskStartScheduler()

jcwren wrote on Friday, March 15, 2019:

In our design, before vTaskStartScheduler() is called, the system needs to use the systick interrupt for delays and timeouts. During the process of initialization, xQueueCreateStatic() is called, which ultimately calls xQueueGenericReset().

xQueueGenericReset() wraps it’s code block in a taskENTER_CRITICAL()/taskEXIT_CRITICAL() pair, the former of which ultimately calls vPortEnterCritical().

vPortEnterCritical() calls portDISABLE_INTERRUPTS(), who in turn calls vPortRaiseBASEPRI(), which sets PRIMASK to 0x50 (derived from configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY).

The STM32 HAL library runs the systick interrupt at priority 15, so the systick interrupt is no longer generating interrupts. This will occur for any FreeRTOS call that uses taskENTER_CRITICAL().

Unless I am mistaken in that it’s “legal” to call functions like xQueueCreateStatic() and such before calling vTaskStartScheduler(), it seems that portDISABLE_INTERRUPTS() should include a check to see if the scheduler has been started yet, and if not, then not modify the BASEPRI register (or use __interrupt_disable()). The same would be true for portENABLE_INTERRUPTS()

rtel wrote on Friday, March 15, 2019:

Interrupts remain masked between any (or at least most) calls to
FreeRTOS API functions and the scheduler being started. That behavior
was introduced many years ago in response to a very common cause of
support requests that resulted from interrupts trying to use kernel
features before the kernel was changed. I don’t think we would be
willing to check if the scheduler has been started or not on every call
as that would have a negative impact on run time performance as the
check would be made very frequently. However you can change this
behavior by changing the line:

static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;

in port.c to

static UBaseType_t uxCriticalNesting = 0x00;

jcwren wrote on Friday, March 15, 2019:

I’m unclear how that should help. It looks like it will just skip throwing an configASSERT() until after xPortStartScheduler() has been called. It’s still going to change the BASEPRI value.

rtel wrote on Friday, March 15, 2019:

Did you try it?

richarddamon wrote on Saturday, March 16, 2019:

One alternative is to configure the HAL to use a Timer Peripheral for its clock, and you can even give it a priority above configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY so that FreeRTOS will not disable it.