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

CortexM3 and gcc port

Posted by GregK on April 16, 2010
I am using Cortex-M3 port for STM32 and GCC.
I found that macros:

portCLEAR_INTERRUPT_MASK_FROM_ISR
and
portCLEAR_INTERRUPT_MASK()

are not fully implemented. It is shame because I need such macros to create function what call FreeRTOS API and could be used from interrupts and tasks. In my example:

===========================================================
uxSavedInterrup = portSET_INTERRUPT_MASK_FROM_ISR();
{
// <- proper BASE priority
queueSendStatus = xQueueSendFromISR(xQue_PRINT_SERVER,
&print_mes, &pxTaskWoken);
// UNSAFE LINE HERE and below
//<- due not fully implemented portCLEAR_INTERRUPT_MASK_FROM_ISR() base priority back to 0
if ( pdTRUE == queueSendStatus )
(print_mes->something)++;

queueSendStatus = xQueueSendFromISR(xQue_PRINT_SERVER,
&print_mes, &pxTaskWoken);
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterrup); // in fact not needed, xQueueSendFromISR()
// clear base priority to 0!
================================================================

See line with comment: UNSAFE LINE HERE. Interrupts back to zero, not to configMAX_SYSCALL_INTERRUPT_PRIORITY.
But there is no big issue to implement such macros. What I did: based on core_cm3.c and core_cm3.h (CMSIS 1.20) from http://www.onarm.com/download/download389.asp created functions to put in to portmacro.h


===============================================================================
static inline void __cortexM3__enable_irq() { __asm volatile ("cpsie i"); }
static inline void __cortexM3__disable_irq() { __asm volatile ("cpsid i"); }


static inline void __cortexM3__set_BASEPRI(unsigned portBASE_TYPE value)
{
__asm volatile ("MSR basepri, %0" : : "r" (value) );
}//

static inline unsigned portBASE_TYPE __cortexM3__get_BASEPRI(void)
{
unsigned portBASE_TYPE result = 0U;

__asm volatile ("MRS %0, basepri_max" : "=r" (result) );
return(result);
}//

static inline unsigned portBASE_TYPE portSET_INTERRUPT_MASK(void)
{
unsigned portBASE_TYPE uxSavedInterruptStatus;
__cortexM3__disable_irq(); /* need atomic execution !*/
{
uxSavedInterruptStatus = __cortexM3__get_BASEPRI();
__cortexM3__set_BASEPRI(configMAX_SYSCALL_INTERRUPT_PRIORITY);
}
__cortexM3__enable_irq();
return uxSavedInterruptStatus;
}//

static inline void portCLEAR_INTERRUPT_MASK(unsigned portBASE_TYPE uxSavedStatus)
{
__cortexM3__set_BASEPRI(uxSavedStatus);
}//


#define portSET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK(x)

#define portDISABLE_INTERRUPTS()portSET_INTERRUPT_MASK()
#define portENABLE_INTERRUPTS()portCLEAR_INTERRUPT_MASK(0U)
===============================================================================

GCC 4.4.1
With flag -O1 portSET_INTERRUPT_MASK() evaluate to only 5 instructions:

================================================================
0x080002bc : cpsid i
0x080002be : mrs r4, BASEPRI_MASK
0x080002c2 : mov.w r3, #191; 0xbf
0x080002c6 : msr BASEPRI, r3
0x080002ca : cpsie i
================================================================
With flag -O1 portCLEAR_INTERRUPT_MASK_FROM_ISR() only one instruction

0x080002f0 : msr BASEPRI, r4

Obviously optimization O1 or higher need to be used.
1. Is it correct?
2. Any chance to implement this or similar solution for this macros?

Regards

RE: CortexM3 and gcc port

Posted by Richard on April 16, 2010
I'm having difficulty reading this, maybe you could repost using the
 tags.

However - the portCLEAR_INTERRUPT_MASK_FROM_ISR and portCLEAR_INTERRUPT_MASK() *are*, as far as I am aware, fully implemented. The code has also be reviewed in tiny detail by an ARM Cortex M3 expert.

When you enter an interrupt the priority level is held in the NVIC itself, and putting the BASEPRI value down below the priority of the currently executing interrupt will not allow the CPU to accept interrupts that are below the priority of the currently executing interrupt. Therefore the fastest/most efficient thing to do is simply set it down to zero. The effect on the running system is the same as if you had set it back to its previous value.

Or am I missing your point?

Regards.

RE: CortexM3 and gcc port

Posted by Richard on April 16, 2010
Try again:

I'm having difficulty reading this, maybe you could repost using the code tags.

However - the portCLEAR_INTERRUPT_MASK_FROM_ISR and portCLEAR_INTERRUPT_MASK() *are*, as far as I am aware, fully implemented. The code has also be reviewed in tiny detail by an ARM Cortex M3 expert.

When you enter an interrupt the priority level is held in the NVIC itself, and putting the BASEPRI value down below the priority of the currently executing interrupt will not allow the CPU to accept interrupts that are below the priority of the currently executing interrupt. Therefore the fastest/most efficient thing to do is simply set it down to zero. The effect on the running system is the same as if you had set it back to its previous value.

Or am I missing your point?

Regards

p.s. also, there is no point where interrupts are globally disabled, as would be the case in your code.

RE: CortexM3 and gcc port

Posted by GregK on April 16, 2010
Hi

Yes, I think you are missing my point.
First I am not claiming that current FreeRTOS implementation is wrong from technically point of view. It is just not full (not full for me).
Sorry for not clear post, Once again, I hope now will be clear. just pseudocode

Lets image function what is used from ISR and task routine and use FreeRTOS API. In order to secure reentrancy I use
portSET_INTERRUPT_MASK_FROM_ISR() macros, (is any other way to do this?? ).

=========================================================

/* FUN used from ISR and task routine*/
void FUN()
{
unsigned uxSavedInterrup = portSET_INTERRUPT_MASK_FROM_ISR();
{
xQueueSendFromISR();
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterrup);

}

=========================================================

Is it correct model? If not than I missed something and my post not make sense, if yes please read below.

Now, last statement before return from xQueueSendFromISR() is:

portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); /* line 814 in queue.c */


This macro discard actually uxSavedInterruptStatus value and set BASEPRI to 0, what is not what I intend to get. My assumption is "push" and "pop" priority. What current implementation of macros are doing is set priority to configMAX_SYSCALL_INTERRUPT_PRIORITY and then set to 0 as you mention. I know it is easy and simply.

But if my function looks like this:
=========================================================

/* FUN2 used from ISR and task routine*/
void FUN2()
{
unsigned uxSavedInterrup = portSET_INTERRUPT_MASK_FROM_ISR();
{
/* assums no preemptuion in inner block*/
xQueueReceiveFromISR(&data);

data = global_data +1; /* could preempt here */

xQueueSendFromISR(&data);
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterrup);

}

=========================================================

Apart of sense of FUN2(), because xQueueReceiveFromISR() set BASEPRI to 0 just before return, now
line: data = global_data+1;
is not safe because could be pre-empted if used from task routine.
Assumption is no preemption inside inner block.

However my implementation do not introduce big overhead, it probably need to map to assembler macro due to not depend on compiler optimalization.

What you think?

Regards

RE: CortexM3 and gcc port

Posted by GregK on April 16, 2010
(once again, I do not have preview before I post)

Hi

Yes, I think you are missing my point.
First I am not claiming that current FreeRTOS implementation is wrong from technically point of view. It is just not full (not full for me).
Sorry for not clear post, Once again, I hope now will be clear. just pseudocode

Lets image function what is used from ISR and task routine and use FreeRTOS API. In order to secure reentrancy I use
portSET_INTERRUPT_MASK_FROM_ISR() macros, (is any other way to do this?? ).

=========================================================

/* FUN used from ISR and task routine*/
void FUN()
{
unsigned uxSavedInterrup = portSET_INTERRUPT_MASK_FROM_ISR();
{
xQueueSendFromISR();
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterrup);
}

=========================================================

Is it correct model? If not than I missed something and my post not make sense, if yes please read below.

Now, last statement before return from xQueueSendFromISR() is:
Code:
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); /* line 814 in queue.c */

This macro discard actually uxSavedInterruptStatus value and set BASEPRI to 0, what is not what I intend to get. My assumption is "push" and "pop" priority. What current implementation of macros are doing is set priority to configMAX_SYSCALL_INTERRUPT_PRIORITY and then set to 0 as you mention. I know it is easy and simply.

But if my function looks like this:
=========================================================
/* FUN2 used from ISR and task routine*/ void FUN2() { unsigned uxSavedInterrup = portSET_INTERRUPT_MASK_FROM_ISR(); { /* assums no preemptuion in inner block*/ xQueueReceiveFromISR(&data); data = global_data +1; /* could preempt here */ xQueueSendFromISR(&data); }

/* FUN2 used from ISR and task routine*/
void FUN2()
{
unsigned uxSavedInterrup = portSET_INTERRUPT_MASK_FROM_ISR();
{
/* assums no preemptuion in inner block*/
xQueueReceiveFromISR(&data);

data = global_data +1; /* could preempt here */

xQueueSendFromISR(&data);
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterrup);

}

=========================================================

Apart of sense of FUN2(), because xQueueReceiveFromISR() set BASEPRI to 0 just before return, now
line: data = global_data+1;
is not safe because could be pre-empted if used from task routine.
Assumption is no preemption inside inner block.

However my implementation do not introduce big overhead, it probably need to map to assembler macro due to not depend on compiler optimalization.

What you think?

Regards

RE: CortexM3 and gcc port

Posted by GregK on April 16, 2010
(Apologise!)

Hi

Yes, I think you are missing my point.
First I am not claiming that current FreeRTOS implementation is wrong from technically point of view. It is just not full (not full for me).
Sorry for not clear post, Once again, I hope now will be clear. just pseudocode

Lets image function what is used from ISR and task routine and use FreeRTOS API. In order to secure reentrancy I use
portSET_INTERRUPT_MASK_FROM_ISR() macros, (is any other way to do this?? ).

=========================================================

/* FUN used from ISR and task routine*/

void FUN() {
unsigned uxSavedInterrup = portSET_INTERRUPT_MASK_FROM_ISR();
{
xQueueSendFromISR();
} portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterrup);
}

=========================================================

Is it correct model? If not than I missed something and my post not make sense, if yes please read below.

Now, last statement before return from xQueueSendFromISR() is:

portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); /* line 814 in queue.c */


This macro discard actually uxSavedInterruptStatus value and set BASEPRI to 0, what is not what I intend to get. My assumption is "push" and "pop" priority. What current implementation of macros are doing is set priority to configMAX_SYSCALL_INTERRUPT_PRIORITY and then set to 0 as you mention. I know it is easy and simply.

But if my function looks like this:
=========================================================

/* FUN2 used from ISR and task routine*/
void FUN2()
{
unsigned uxSavedInterrup = portSET_INTERRUPT_MASK_FROM_ISR();
{
/* assums no preemptuion in inner block*/
xQueueReceiveFromISR(&data);

data = global_data +1; /* could preempt here */

xQueueSendFromISR(&data);
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterrup);

}

=========================================================

Apart of sense of FUN2(), because xQueueReceiveFromISR() set BASEPRI to 0 just before return, now
line: data = global_data+1;
is not safe because could be pre-empted if used from task routine.
Assumption is no preemption inside inner block.

However my implementation do not introduce big overhead, it probably need to map to assembler macro due to not depend on compiler optimalization.

What you think?

Regards

RE: CortexM3 and gcc port

Posted by GregK on April 16, 2010
Just addition if still not clear, see comments in code:


/* FUN2 used from ISR and task routine*/
void FUN2(void)
{
/* assuming current priority if called from task is 0
* and configMAX_SYSCALL_INTERRUPT_PRIORITY 11
*/

// PRI 0
unsigned uxSavedInterrup = portSET_INTERRUPT_MASK_FROM_ISR();
//PRI 11 correct
{ /* Assume no preemptuion in inner block*/
xQueueReceiveFromISR(&data);
//PRI 0 !!! not correct
data = global_data +1;
/* could preempt here */
xQueueSendFromISR(&data);
//PRI 0 not correct
} portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterrup);
//PRI 0
}

RE: CortexM3 and gcc port

Posted by Richard on April 16, 2010
The macros portSET_INTERRUPT_MASK_FROM_ISR() and portCLEAR_INTERRUPT_MASK_FROM_ISR() are only designed for use from and ISR - for the reason already stated. They are not intended for use at the task level, although this *might* work if the calls did not nest.

In the example you give you use the macros around a call to xQueueSendFromISR(). As xQueueSendFromISR() also uses the macros internally then

+ first the outer critical section is not necessary, and

+ second you are going to have problems for the reasons you are pointing out yourself.

You are simply using the macros out of scope. Stick to using them how they are supposed to be used and you will be ok.

Functions called from the task level should use taskENTER_CRITICAL() and taskEXIT_CRITICAL(). Functions called from an interrupt should used portSET_INTERRUPT_MASK_FROM_ISR() and portCLEAR_INTERRUPT_MASK_FROM_ISR(). If you want to call a function from both, and it is necessary that the function uses a critical section, then you are going to either have to modify the code or provide your own critical section implementation.

Regards.

RE: CortexM3 and gcc port

Posted by GregK on April 19, 2010
“+ first the outer critical section is not necessary, and”


I am not sure what you mean, probably you mean that is not necessary because it's not make sense in current implementation of macros. Because in my example it is crucial since switch context can not occurs between xQueueReceiveFromISR() and xQueueSendFromISR().
However I understand prom your last post this is not supported officially, due of implementation of macros.

“Functions called from the task level should use taskENTER_CRITICAL() and taskEXIT_CRITICAL(). Functions called from an interrupt should used portSET_INTERRUPT_MASK_FROM_ISR() and portCLEAR_INTERRUPT_MASK_FROM_ISR(). If you want to call a function from both, and it is necessary that the function uses a critical section, then you are going to either have to modify the code or provide your own critical section implementation.”


Thanks.
This is what I am doing, I provide my own implementation of portSET_INTERRUPT_MASK_FROM_ISR() and portCLEAR_INTERRUPT_MASK_FROM_ISR().

Regards


[ 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