Cortex M4 Port: Creating interrupt-safe critical section

bkneely wrote on Thursday, April 05, 2018:

Hello,

I’m using the IAR Cortex M4F port of FreeeRTOS. In a certain section of code, I need to do the following:

/* Enter critical section */
oldPrio = __get_BASEPRI();
__set_BASEPRI( /* Some priority higher than configMAX_SYSCALL_INTERRUPT_PRIORITY */ );
...
vTaskPrioritySet();
...
/* Exit critical section */
 __set_BASEPRI( oldPrio );

The issue I see is that vTaskPrioritySet()'s call to taskEXIT_CRITICAL() sets BASEPRI to 0, which exits my critical section before I would like to.

Is there a recommended way to do this (i.e. create an interrupt-safe critical section but still be able to call RTOS API functions within it)?

Thanks,

Brian

rtel wrote on Thursday, April 05, 2018:

A couple of general rules of thumb, which apply in most cases:

  1. Do not call FreeRTOS API functions that could cause a context switch
    (such as changing the priority of a task) from a critical section as it
    can create logic errors as the context switch will not be able to occur.

  2. The FreeRTOS kernel ‘owns’ BASEPRI because it keeps a nesting count
    of critical sections, which update BASEPRI.

Perhaps if you could describe what you are trying to achieve we could
suggest some alternatives for you?

bkneely wrote on Monday, April 09, 2018:

Hi Richard,

Thanks for the info. Really what we’re trying to accomplish is creating a critical section w.r.t. interrupts that use the FreeRTOS API. We have an ISR that basically does the following:

myISR()
{
    /* Read/modify/write hardware registers */
    xQueueSendFromISR( /* Data read from hw */ );
}

And a set of utilities, called from a task context, that can also read/modify/write this hardware. We don’t want to completely disable interrupts, hence the use of BASEPRI. From your reply above, it sounds like as long as we don’t make FreeRTOS API calls within this critical section, we should be ok. Is that correct?

In certain situations, we may want to change a task’s priority before we allow the scheduler to run again (based on hardware state, etc.) Is there a way to do this?

Thanks,

Brian

rtel wrote on Monday, April 09, 2018:

The interrupt must have a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY as it is using a FreeRTOS API
function in the interrupt’s handler. That means, if you have a task
that is accessing the same hardware as the interrupt, all you need to do
is wrap the access in the task in
taskENTER_CRITICAL()/taskEXIT_CRITICAL(). Those macros will set the
BASPI to a value that will prevent the interrupt executing, but not
prevent interrupts that have a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY from executing.