FreeRTOS Support Archive
The FreeRTOS support forum is used to obtain active support directly from Real
Time Engineers Ltd. In return for using our top quality software and services for
free, we request you play fair and do your bit to help others too! Sign up
to receive notifications of new support topics then help where you can.
This is a read only archive of threads posted to the FreeRTOS support forum.
The archive is updated every week, so will not always contain the very latest posts.
Use these archive pages to search previous posts. Use the Live FreeRTOS Forum
link to reply to a post, or start a new support thread.
[FreeRTOS Home] [Live FreeRTOS Forum] [FAQ] [Archive Top] [April 2010 Threads] CortexM3 and gcc portPosted 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 portPosted 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 portPosted 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 portPosted 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 portPosted 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 portPosted 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 portPosted 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 portPosted 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 portPosted 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
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.
|