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


ISR stack

Posted by madis on October 24, 2007

I have an interesting problem here related to ISR-s. ISR-s are started as in case of FreeRTOS demos etc.:

void vUSB_ISR( void ) __attribute__ ((naked));
void vUSB_ISR( void )
/* This ISR can cause a context switch. Therefore a call to the
portENTER_SWITCHING_ISR() macro is made. This must come BEFORE any
stack variable declarations. */

/* Now variables can be declared. */

Which is followed by local variable declarations. But I noticed that when I declare too many local variables, funny things will happen. So I started to debug the entering to ISR-s. IRQ stack pointer is located at 0xfff0 as expected (part is SAM7X256 with 64K RAM and I debug in RAM). Stack sizes are declared like:
/* Stack Sizes */
.set UND_STACK_SIZE, 0x00000004
.set ABT_STACK_SIZE, 0x00000004
.set FIQ_STACK_SIZE, 0x00000004
.set IRQ_STACK_SIZE, 0X00002000
.set SVC_STACK_SIZE, 0x00000800
So IRQ stack is empty. But do to the naked attribute stack pointer is not modified while entering to the ISR. I think thats the expected action, as there is asm macro included, that enter_isr? But now the local variables are situated above the stack pointer...? So in case I declare enough local variables in ISR, it overwrites my vector table. I verified it with debugger. while declaring the local variables and initialising them, asm code generated is:

portCHAR cTaskWokenByPost = pdFALSE;
0x00001454 <vAudio_ISR+96>: mov r3, #0; 0x0
0x00001458 <vAudio_ISR+100>: strb r3, [sp, #11]

while stack pointer stays at the beginning of IRQ stack 0xfff0.

C flags are:
CPFLAGS = $(MCFLAGS) -mthumb-interwork $(OPT) -ggdb -fomit-frame-pointer -ffunction-sections -fdata-sections -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wno-strict-aliasing -fverbose-asm -Wa,-ahlms=$(<:.c=.lst) $(DEFS)
CPFLAGS += -MD -MP -MF .dep/$(@F).d

arm-elf-gcc version is 4.1.1 which was included with yagarto toolchain.

Can anybody point me whats wrong with my code, cflags or something else?

Thank you,

RE: ISR stack

Posted by Dave on October 24, 2007
Did you change the portENTER_SWITCHING_ISR() macro at all? Looking at the comments in the macro it seems to have this point covered by switching stacks:

#define portENTER_SWITCHING_ISR() \
/* Save the context of the interrupted task. */\
/* We don't know the stack requirements for the ISR, so the frame */\
/* pointer will be set to the top of the task stack, and the stack*/\
/* pointer left where it is. The IRQ stack will get used for any */\
/* functions calls made by this ISR. */\
asm volatile ( "SUBR11, LR, #4" );\

I think the last bracket is also very important.

RE: ISR stack

Posted by madis on October 24, 2007
No, I did not change the portENTER_SWITCHING_ISR() macro... Should I? Maybe I have missed an important point here.

Thank you,

RE: ISR stack

Posted by madis on October 25, 2007
But what about the demo projects provided with the FreeRTOS download? They use the same portENTER_SWITCHING_ISR() but just dont declare too many local variables in serial ISR. But I think these local variables are also situated above the IRQ stack? Any comments/guidance?


RE: ISR stack

Posted by Dave on October 25, 2007
I don't fully understand your problem, and find it odd that you would want to allocate so many variables within the ISR that you take up 0x2000 bytes of stack. However, it seems from the assembly code you provide that you could run into problems when making function calls from within the assembly routine as the function could use the same stack space.

I note you have the -fomit-frame-pointer compiler option set. This option was added to get around a bug in the GCC code generation. It might be though that this is what is causing your problem. I think this because of the comment in the macro that states the frame pointer is being moved to the task stack, but you are not using a frame pointer. I would have to look at the entire assembly code output to know if this actually was a problem or not.

RE: ISR stack

Posted by sotd on October 25, 2007
but the stack grows down, so its writing off the bottom.

RE: ISR stack

Posted by Richard on October 25, 2007
Looks like you might have a point here Dave ref the -fomit-stack-pointer option. I will check this out this evening and report back. In the mean time you can make your variables static (don't forget to manually initialise them then), or turn optimisation up to 1. This should get you going in the short term.


RE: ISR stack

Posted by Glen B. on October 25, 2007
Richard, et al

As you may recall, I have never accepted -fomit-frame-pointer as an acceptable solution to the FreeRTOS/GCC ARM context switch issue. The -fomit-frame-pointer impedes stack tracebacks too much for me.

I hope that -fomit-frame-pointer is not the problem in in this case, but if it is, I have previously posted a fix to the portSAVE_CONTEXT() macro. Well, as it turns out that fix didn't quite do it under certain optimization levels (note that I use -fno-omit-frame-pointer when I optimize, so I still have the problem under optimization). The 8 bytes of open space I left on the stack needs to be increased to 32 bytes. The number has been arrived at purely by experimentation. 16 is too small, 32 seems to work.

The good news is that a colleague of mine recently did some further experimentation and believes that GCC 4.2.1 finally fixes the underlying problem in the ARM/Thumb code generation. We'll see.

Note that the fix to portSAVE_CONTEXT() is reasonably inocuous even if the GCC thing is fixed.


RE: ISR stack

Posted by Richard on October 25, 2007
Hi Glen, et al :o)

I'm just looking at this again now and coming to the conclusion that probably the safest already solution is to declare all local variables in the interrupt service routine as static. This way it does not matter whether the frame pointer is used or not. This would also mean that the line "asm volatile ( "SUBR11, LR, #4" );" could be removed from the portENTER_SWITCHING_ISR() macro [it does not do anything when the frame pointer is not used anyway]. This should then work will all compiler options at all optimisation levels.

What do you think?

Also, probably the reason the amount of RAM you have to leave spare on entry to interrupts (with your previous work around) varies is simply because the stack requirement of the ISRs varies?


RE: ISR stack

Posted by Richard on October 25, 2007
I have added the following to the list of known issues:

ARM7 GCC demos
Some time back the compiler option -fomit-frame-pointer was introduced to all the ARM7 GCC demos as a work around for a GCC bug. It has recently been brought to my attention that since then interrupts that can cause a context switch have the potential to cause memory corruption as the macros used assume the existence of a frame pointer. As a workaround, all variables declared locally within an ISR should be declared static - when doing this don't forget to initialise the variables manually within the C code, not just where the variable is declared.


RE: ISR stack

Posted by Glen B. on October 26, 2007

I don't fully comprehend the specific ISR issue that triggered this discussion, so I can't really comment on that. Certainly I avoid using auto variables in functions with portENTER_SWITCHING_ISR() but I can't recall the details as to why it was necessary.
It made sense at the time - I don't recall if I read the advice or got it direct from you after explaining a problem.

On the issue of my workaround, no, it has nothing to do with ISR stack requirements. It's all about how GCC fiddles the stack pointer on returns from functions.

The point is this... under certain circumstances, details and rationale elude me, GCC generates code to return from functions in a bad way. Sometimes the stack pointer gets (briefly) pulled back behind valid stack data (such as the return address), then it is adjusted forward again, and the return address, etc. are popped off. This apparently only happens when no-omit-frame-pointers is in effect. The max. amount it gets pulled back beyond valid data varies, but my current guess is that it is less than 8 long words (32 bytes).

Now if an interrupt happens and FreeRTOS saves a task context just when the sp is badly positioned, boom, the valid data gets clobbered.

One solution, and that used by some other kernels, is to save the context in the TCB rather than on the system/user stack. My solution was stick with your design (and ARM port) but modify it to skip 32 bytes (originally 8) before pushing the context. That skips over the potentially valid data so that it doesn't get clobbered. Your context restore is robust against this change.

A colleague has pointed out to me that the GCC issue is a serious problem for those who want nested interrupts, even if there is no multitasking kernel. It's almost a requirement that things get pushed on the operational stack. This he argues, demonstates that it truly is a bug in GCC code generation (not merely an idiosyncracy). We are both relieved that it finally appears to be fixed in GCC 4.2.1.

RE: ISR stack

Posted by madis on October 26, 2007
Dave wrote:
>I don't fully understand your problem, and find it odd that you would want to allocate so many variables >within the ISR that you take up 0x2000 bytes of stack. However, it seems from the assembly code you provide >that you could run into problems when making function calls from within the assembly routine as the function >could use the same stack space.

I dont use 0x2000 bytes of stack in IRQ (I just reserved more stack as "funny things happened" within ISR). The assembly code I provided is generated by gcc. And shows how it initialises local variables, which are not static. These local variables get saved above the IRQ stack pointer, which is set to 0xfff0 (running from RAM and part is SAM7X256 so its at the end of RAM) by boot.S. I.e. no nested interrupts, just first interrupt arrives and stack is empty. And the situation is the same for all the interrupt functions, Im afraid. Local variables just happened to fit upon IRQ stack without overwriting vector table. Static variables dont cause any problem.

I changed ISR variables to static in my current project. But another solution would be to move IRQ stack down. Like declare it in two parts in boot.s. First make room for "unspecified features" and then save IRQ sp.


RE: ISR stack

Posted by Richard on October 28, 2007
See the following thread:



[ 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