Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Real time embedded FreeRTOS mailing list 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT Training




Loading

taskENTER_CRITICAL/taskEXIT_CRITICAL on Cortex M4

Posted by incrediball on September 4, 2014

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

Posted by heinbali01 on September 5, 2014

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

Posted by incrediball on September 5, 2014

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

Posted by heinbali01 on September 5, 2014

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, ... ) { BaseTypet xIndex = xEventHead; xInterruptEvent *pxEvent = &xEvents[xIndex]; if( ++xEventHead >= LOGEVENTCOUNT ) { xEventHead = 0; } valist 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

Posted by ilgitano on September 5, 2014

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

Posted by rtel on September 5, 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 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

Posted by incrediball on September 8, 2014

Many thanks for the detailed answers


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) 2004-2010 Richard Barry. Copyright (C) 2010-2016 Real Time Engineers Ltd.
Any and all data, files, source code, html content and documentation included in the FreeRTOSTM distribution or available on this site are the exclusive property of Real Time Engineers Ltd.. See the files license.txt (included in the distribution) and this copyright notice for more information. FreeRTOSTM and FreeRTOS.orgTM are trade marks of Real Time Engineers Ltd.

Latest News:

FreeRTOS V9.0.0 is now available for download.


Free TCP/IP and file system demos for the RTOS


Sponsored Links

⇓ Now With No Code Size Limit! ⇓
⇑ Free Download Without Registering ⇑


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Renesas Electronics Gold Alliance RTOS Partner.jpg

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Atmel RTOS partner supporting ARM Cortex-M3 and AVR32 microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Xilinx Microblaze and Zynq partner

Silicon Labs low power RTOS partner

Altera RTOS partner for Nios II and Cortex-A9 SoC

Freescale Alliance RTOS Member supporting ARM and ColdFire microcontrollers

Infineon ARM Cortex-M microcontrollers

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

Cypress RTOS partner supporting ARM Cortex-M3

Fujitsu RTOS partner supporting ARM Cortex-M3 and FM3

Microsemi (previously Actel) RTOS partner supporting ARM Cortex-M3

Atollic Partner

IAR Partner

Keil ARM Partner

Embedded Artists