Quality RTOS & Embedded Software

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




Loading

ARM problem with ISR local automatic variable

Posted by Nobody/Anonymous on November 26, 2005
My ARM port is based on the ARM7_LPC2000 demo. I am using portENTER_SWITCHING_ISR() as is, in which R11 (FP) is set to LR as the last step. This leaves the FP as the SP of the interrupted task. This is nice, except that the compiler seems to be generating code for my __attribute__ ((naked)) ISR such that the offsets to autos from the FP are positive rather than negative (as is the case with normal functions). This then clobbers stuff on the task's stack.

Is this a known issue? Or have others seen it?

My fix has been to use statics. Functions called from the ISR are OK, of course.

RE: ARM problem with ISR local automatic variable

Posted by Nobody/Anonymous on November 26, 2005
Do you declare your local variables AFTER the call to portENTER_SWITCHING_ISR()? If you don't do this then you will get the problem you describe.

From the demo serial driver:

void vUART_ISR( void )
{
/* This ISR can cause a context switch, so the first statement must be a
call to the portENTER_SWITCHING_ISR() macro. This must be BEFORE any
variable declarations. */
portENTER_SWITCHING_ISR();

/* Now we can declare the local variables. */
signed portCHAR cChar;
portBASE_TYPE xTaskWokenByTx = pdFALSE, xTaskWokenByRx = pdFALSE;

/* What caused the interrupt? */
switch( UART0_IIR & serINTERRUPT_SOURCE_MASK )

etc...rest of function...

RE: ARM problem with ISR local automatic variable

Posted by Nobody/Anonymous on November 26, 2005
No. Ise now that this problem was an illusion. I had two short ints as local variables. The first appears at the R11 address. The second appear at R11 + #2 since it is in the 4 bytes word located by R11.

Unfortunately this doesn't resolve the underlying problem I am having which is that if I declare the ISR variables auto, my ulCriticalNesting variable ends up getting clobbered, but if I make them static everthing is fine. Maybe I am having a stack overflow issue.

RE: ARM problem with ISR local automatic variable

Posted by Nobody/Anonymous on November 26, 2005
Yes, I agree, could be a stack overflow.

RE: ARM problem with ISR local automatic variable

Posted by Glen B. on November 26, 2005
I am the originator of this thread. Just got a login id.

So my original hunch that the ISR auto variable were clobbering the interrupted task's saved ulCriticalNesting value was correct. But as noted, the reason was not positive offsets from R11 (the Frame Pointer).

What I did discover is that the the R11 is set up incorrectly in portENTER_SWITCHING_ISR(). The final line
asm volatile ( "MOV R11, LR" );
leaves R11 locating the saved ulCriticalNesting rather than a new (psuedo)frame on the interrupted task's stack. I corrected it with
asm volatile ( "SUB R11, LR, #4" );

I feel I may still be missing something because it seems odd that such a problem has not yet been found. Or maybe it has, the original subject line was somewhat misleading.


RE: ARM problem with ISR local automatic variable

Posted by Richard on November 26, 2005
Hi Glen,

I have a couple of questions about your setup:

1) Which GCC version are you using?
2) Are you using the GNUARM build (just for comparison with my own setup).
3) Have you modified the code within the Source/Portable/GCC/arm7_LPC2000 directory at all?

Would it be possible for you to forward me your project? If so can you:

1) Create the smallest project possible that demonstrates the problem.
2) Build the project with debug info included and preferably no optimisation.
3) Zip up your entire build directory including the object code, elf file, FreeRTOS code and your application code and send the zip to the mail address on the FreeRTOS contacts page (r +DOT+ barry _at_ freerto....org).

I will hopefully then be able to simulate your build

Thanks,
Richard.


RE: ARM problem with ISR local automatic variable

Posted by Richard on November 26, 2005
Sorry, a couple of other questions:

THUMB or ARM build? ... and ...
What is the optimisation level?

RE: ARM problem with ISR local automatic variable

Posted by Richard on November 27, 2005
I have been playing around with this a bit and cannot replicate the reported behavior so far. For example, with an ISR function of the form:

void ISR1( void )
{
____portENTER_SWITCHING_ISR();

____volatile short short1, short2;

____short1 = 0x1234;
____short2 = 0x5678;

____/* Just some dumy stuf to generate code. */
____if( short1 == short2 )
____{
________short1 = 0;
____}

____portEXIT_SWITCHING_ISR( 0 );
}

I find that the local variables are located on the IRQ stack and the frame pointer is not used. If I change this to:

short DummyFunction( short s1, short s2, long x, long y )
{
short a = 1;
short b = 2;
volatile long f = x + y;

____a += f;

____if( s1 > s2 )
________return s1 + a;
____else
________return s2 + b;
}

void vUART_ISR( void )
{
____portENTER_SWITCHING_ISR();

____volatile short short1, short2;
____long x = 0x12345678, y = 0x23456789;

____short1 = 0x1234;
____short2 = 0x5678;

____short1 = DummyFunction( short1, short2, x, y );

____portEXIT_SWITCHING_ISR( 0 );
}


Then the frame pointer is used for local variables, but it is used correctly and the address pointed to by R11 is not overwritten.


I will wait to here back from you with the info requested before looking at this any further.

Regards.



CONCLUSIONS - RE: ARM problem with ISR local

Posted by Richard on December 3, 2005
There does indeed appear to be a problem when using GCC V4.0.1 as follows:

Consider the following function fragment of a naked ISR function.

void vUART_ISR( void )
{
____portENTER_SWITCHING_ISR();
____short needSwitch, level;
____needSwitch = false;


portENTER_SWITCHING_ISR() saves the context, and sets the frame pointer to point to the last context item to be saved.

The line needSwitch = false is then translated into the following code:

mov r3, #0
strh r3, [r11, #-14]

from which it can be seen that the needSwitch variable has an offset of 14 from the frame pointer. However, the same code compiled with GCC V4.0.1 generates the following code

mov r3, #0
strh r3 [r11]

and in so doing writes the variable directly onto the memory pointed to by the frame pointer - clobbering the last stacked item.

It seems the FreeRTOS code is taking advantage of inefficiencies within the V3.4.3 version of GCC, that are no longer present in V4.0.1.

As the OP suggests, this can be fixed by a small modification to the portENTER_SWITCHING_ISR() macro. Within portENTER_SWITCH_ISR() the line:

asm volatile ( "MOV R11, LR" );

should be changed to

asm volatile ( "SUB R11, LR, #4" );


Many thanks to the OP for pointing this out. A fix will be released following further investigations.

Regards.






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




Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

FreeRTOS kernel V10 is available for immediate download. Now MIT licensed.


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

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

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

OpenRTOS and SafeRTOS