Using FreeRTOS primitives before starting scheduler

Your confusion will probably clear by looking at the code. The following is what enter/exit critical do:

static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;

void EnterCritical( void )
{
    portDISABLE_INTERRUPTS();
    uxCriticalNesting++;
}

void ExitCritical( void )
{
    uxCriticalNesting--;

    if( uxCriticalNesting == 0 )
    {
        portENABLE_INTERRUPTS();
    }
}

uxCriticalNesting keeps track of how many times we call enter critical, so that we enable interrupt when exiting the last critical section. Example:

taskENTER_CRITICAL()
taskENTER_CRITICAL()
taskEXIT_CRITICAL() // This call will NOT enable interrupts.
taskEXIT_CRITICAL() // This call will enable interrupts.

As you can see, uxCriticalNesting is initialized to a large value (0xaaaaaaaa). This means that the check if( uxCriticalNesting == 0 ) in exit critical will not be true and interrupts will not be enabled. In other words, a call to enter and exit critical will leave interrupts disabled.

At the time of scheduler start, we set uxCriticalNesting to 0 and enable interrupts so that enter/exit critical can work normally afterwards.

This is done to ensure that interrupts remain disabled from the time first FreeRTOS API is called (which internally calls enter/exit critical) till the time scheduler is started.

3 Likes

Thanks Gaurav for the effort - it does make sense how interrupts remain disabled as uxCriticalNesting is already large enough, which is set to 0 only once the scheduler starts.

I have Kernel V10.0.0 and I see the following though I can’t find where uxCriticalNesting is set to 0xaaaaaaaa.

void vPortEnterCritical( void )
{
    portDISABLE_INTERRUPTS();
    uxCriticalNesting++;

    /* This is not the interrupt safe version of the enter critical function so
    assert() if it is being called from an interrupt context.  Only API
    functions that end in "FromISR" can be used in an interrupt.  Only assert if
    the critical nesting count is 1 to protect against recursive calls if the
    assert function also uses a critical section. */
    if ( uxCriticalNesting == 1 )
    {
        configASSERT( ( SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk ) == 0 );
    }
}
/*-----------------------------------------------------------*/

void vPortExitCritical( void )
{
    configASSERT( uxCriticalNesting );
    uxCriticalNesting--;
    if ( uxCriticalNesting == 0 )
    {
        portENABLE_INTERRUPTS();
    }
}

Here is it - https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/V10.6.1/portable/GCC/ARM_CM4F/port.c#L152

seemingly it’s port_cmsis.c for me but it initializes to 0 instead

/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0;

That has to be a different variable with the same name. Note, it is declared “static” so the name isn’t exported out of the file.

Note “port_cmsis.c” isn’t a FreeRTOS file, but a wrapper provided by your implementation.

This file is not distributed by us. Where did you get it from?

it’s in the nordic SDK (nRF52)

I think that means you are using a modified version of FreeRTOS not associated with any of our release tags.

so with uxCriticalNesting being 0, shouldn’t interrupts not be disabled?

That isn’t the version of uxCriticalNesting that the code would be using, since it is marked “static”, such variables can only be used in the translation unit they are defined in.

port_cmsis sounds like a file that is part of the CMSIS wrapper layer provided by your vendor.

There will be another variable by that name declared in the FreeRTOS code, in the port.c for the processor that is part of the FreeRTOS code.

You can verify that by doing the following:

  1. Find an interrupt that you can trigger - something like an interrupt that triggers on a button press.
  2. Set the interrupt priority to less than configMAX_SYSCALL_INTERRUPT_PRIORITY.
  3. Call a FreeRTOS API to create a FreeRTOS object (lets say task).
  4. Enter infinite loop.
  5. Trigger the interrupt and see if the handler fires. If the handler fires, then the interrupts are not disabled otherwise they are disabled.

If you want to share your code, we can take a look and clarify.