taskENTER_CRITICAL/taskEXIT_CRITICAL on Cortex M4

Firstly I apologize if this has been asked before and already explained in adequate detail. I didn’t find anything definite when I searched for an answer. 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 taskENTERCRITICAL/taskEXITCRITICAL in interrupts. Is this correct? I’m unsure because I have until recently used the arm7 port (at91sam7x) and I’m pretty sure that the use of taskENTERCRITICAL/taskEXITCRITICAL in interrupts meant certain disaster. I’m asking because I have some situations where some general purpose code has sections that are protected by critical sections and I want to know if this code can be called from an interrupt or if I need to take special precautions like I needed to on the arm7 platform. 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. So if used in an interrupt then does this mean that no higher priority interrupt can preempt the currently executing interrupt?

taskENTER_CRITICAL/taskEXIT_CRITICAL on Cortex M4

Hi, “taskENTERCRITICAL/taskEXITCRITICAL” do nothing more than temporarily disabling interrupts. vTaskSuspendAll/xTaskResumeAll is a ‘lighter’, it prevents that other competing tasks will become active, while still allowing interrupts. In general I would advise not to use any critical section within an interrupts handler. You have some “general purpose code” which must be called when an interrupt handler becomes active? In stead of calling this code directly, I would set a flag and call for instance xSemaphoreGiveFromISR(), so that a regular task wakes up and call the general purpose code. You don’t really gain performance by calling the code directly from the interrupt handler. Regards, Hein

taskENTER_CRITICAL/taskEXIT_CRITICAL on Cortex M4

You have some “general purpose code” which must be called when an interrupt handler becomes active? In stead of calling this code directly, I would set a flag and call for instance xSemaphoreGiveFromISR(), so that a regular task wakes up and call the general purpose code.
I realise this but as an example I have some logging functions (which I use for debugging or logging unusual events) which use critical sections and I need to be able to use these functions from interrupts or from tasks. There is little concern about the duration of the interrupt if debugging an issue or just logging an unusual event but the function needs to work reliably. I was really just wondering if anyone could answer the question of whether critical sections are safe to use on the Cortex m4 port or not. On a similar theme, since the cortex port allows nested interrupts, how do functions such as xSemaphoreGiveFromISR() protect the semaphore’s internal contents against corruption if another higher priority interrupt suddenly executes and gives/takes the same semaphore? Are critical sections in use here or do we actually need to use critical sections to protect the semaphore?

taskENTER_CRITICAL/taskEXIT_CRITICAL on Cortex M4

Calling xSemaphoreGiveFromISR() from an interrupt should always be safe, as the kernel (xQueueGenericSendFromISR()) will mask interrupts when necessary. For debugging purposes, sending logging during an interrupt is quite heavy. An alternative could be to use a circular buffer of events: ~~~~~

define LOGEVENTCOUNT ( 100 )

struct xInterruptEvent { char cText[15]; TickType_t xTimeStamp; }; struct xInterruptEvent xEvents[ LOGEVENTCOUNT ] volatile BaseTypet xEventHead = 0; BaseTypet xEventTail = 0; void vEventAdd( const char pcFormat, … ) { BaseType_t xIndex = xEventHead; xInterruptEvent *pxEvent = &xEvents[xIndex]; if( ++xEventHead >= LOG_EVENT_COUNT ) { xEventHead = 0; } va_list args; va_start( args, pcFormat ); / Make sure your version of vsnprintf() is reentrant, otherwise use strncpy() and fixed text messages / vsnprintf( pxEvent->cText, sizeof pxEvent->cText, pcFormat, args ); va_end( args ); / read a high-resolution time */ pxEvent->xTimeStamp = xGetHiresTime( ); } ~~~~~ The advantage is that the logging itself almost doesn’t influence the timing. You can log all events recorded from a normal task. Regards

taskENTER_CRITICAL/taskEXIT_CRITICAL on Cortex M4

If you’re prepared to have a modified local version of FreeRTOS (we’re not) then you can generalise the critical section handling for use in any context. Take a look at a feature request 84. As I said, will work in any context, in interrupts, and out, with FreeRTOS or without. Code there for MSP430 and ARM Cortex M3.

taskENTER_CRITICAL/taskEXIT_CRITICAL on Cortex M4

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 taskENTERCRITICAL/taskEXITCRITICAL 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 taskENTERCRITICAL() and taskEXITCRITICAL() 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 portSETINTERRUPTMASKFROMISR() – which returns the existing interrupt mask before setting the mask up, and portCLEARINTERRUPTMASKFROMISR() 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. Regards.

taskENTER_CRITICAL/taskEXIT_CRITICAL on Cortex M4

Many thanks for the detailed answers