rtel wrote on Friday, September 05, 2014:
Ignoring the whys and wherefores of the advisability of using critical sections for a moment, some direct technical answers:
I was reading through http://www.freertos.org/RTOS-Cortex-M3-M4.html and
if I understand correctly, the port for Cortex M4 (specifically using the
Atmel sam4e8e) allows the use of taskENTER_CRITICAL/taskEXIT_CRITICAL in
interrupts. Is this correct?
I will have to revisit the page, as if it says that it was not intentional. As a general rule of thumb taskENTER_CRITICAL() and taskEXIT_CRITICAL() should not be used in interrupts (see an alternative below). As it happens, however, and specifically only to the Cortex-M3/4 ports (and a just a hand full of other ports), because of a combination of the way the port works and the intelligence built into the NVIC it is probably ok to do so (note the word ‘probably’ in that sentence, it is not something that is part of the testing).
Like other functions and macros though there is an alternative interrupt safe version that can be used. The macros that can be used are portSET_INTERRUPT_MASK_FROM_ISR() - which returns the existing interrupt mask before setting the mask up, and portCLEAR_INTERRUPT_MASK_FROM_ISR() which sets the mask back to its previous value. You can look at the implementation of xQueueGiveFromISR() to see how the macros are used.
These functions will also work from a task, so maybe your general code that gets called from both tasks and interrupts could use those macros instead of the ones that are intended to be used from tasks?
If they can be used in interrupts then what exactly do they do? The API
documentation just states “Preemptive context switches cannot occur when
in a critical region”, so if used within a regular task, then I expect that
no other task can preempt and execute but also that no interrupt can preempt
the executing code and execute
Again this answer is specific to the Cortex-M3/4 ports: Both the macros intended for use in tasks and those intended for use in interrupts set the interrupt priority to a level that will prevent any interrupt that is permitted to execute an interrupt safe FreeRTOS API function from firing. They do not disable interrupts completely. The version used in a task maintains a separate interrupt nesting count and clears the interrupt mask when the count reaches 0. The versions that are intended for use in interrupts set the interrupt mask then clears the mask back to its value prior to being set.
So if used in an interrupt then does this mean that no higher priority
interrupt can preempt the currently executing interrupt?
Not quite - priorities that are too high enough (above the defined maximum system call interrupt priority level) to be allowed to use the FreeRTOS API can still execute.