Forums

FREERTOS problem on gcc and LPC2138

Started by rseku October 21, 2005
I found, that asm instructions in freertos are not compiled as exactly
as should be. As a result of execution of below code I get data_abort
exception
First I noticed LDMIA and LDMF difference.

this is RTOS code:
#define portRESTORE_CONTEXT() \
{
extern volatile void * volatile pxCurrentTCB;\
extern volatile unsigned portLONG ulCriticalNesting;\
/* Set the LR to the task stack. */ \
asm volatile ( "LDR R0, %0" : : "m" (pxCurrentTCB) );\
asm volatile ( "LDR LR, [R0]" );\
/* The critical nesting depth is the first item on the stack. */\
/* Load it into the ulCriticalNesting variable. */ \
asm volatile ( "LDR R0, =ulCriticalNesting" );\
asm volatile ( "LDMFD LR!, {R1}" );\
asm volatile ( "STR R1, [R0]" );\
/* Get the SPSR from the stack. */\
asm volatile ( "LDMFD LR!, {R0}" );\
asm volatile ( "MSR SPSR, R0" );\
/* Restore all system mode registers for the task. */\
asm volatile ( "LDMFD LR, {R0-R14}^" );\
asm volatile ( "NOP" );\
/* Restore the return address. */\
asm volatile ( "LDR LR, [LR, #+60]" );\
/* And return - correcting the offset in the LR to obtain the */\ /*
correct address. */\
asm volatile ( "SUBS PC, LR, #4" );\
( void ) ulCriticalNesting;\
}

and this is gcc interpretation:
E1A0C00D mov r12, sp
E92DD800 stmfd sp!, {r11-r12, lr-pc}
E24CB004 sub r11, r12, #0x00000004
/* Simply start the scheduler. This is included here as it can only be
called from ARM mode. */
portRESTORE_CONTEXT();
E59F3038 ldr r3, [pc, #56]
E5930000 ldr r0, [r3]
E590E000 ldr lr, [r0]
E59F024C ldr r0, [pc, #588]
E8BE0002 ldmia lr!, {r1}
E5801000 str r1, [r0]
E8BE0001 ldmia lr!, {r0}
E169F000 msr spsr_cf, r0
E8DE7FFF ldmia lr, {r0-lr}^
E1A00000 nop
E59EE03C ldr lr, [lr, #60]
E25EF004 subs pc, lr, #0x00000004
E59F300C ldr r3, [pc, #12]
E5933000 ldr r3, [r3]


An Engineer's Guide to the LPC2100 Series

> I found, that asm instructions in freertos are not compiled as exactly
> as should be. As a result of execution of below code I get data_abort
> exception
> First I noticed LDMIA and LDMF difference.

<snip>

In this case the translation is correct, and equivalent.

Which version of GCC are you using?

If this part of the code is not working then the most common cause is the
processor being in the wrong mode. The processor must be in Supervisor mode
when vTaskStartScheduler() is called. The startup code included in the
FreeRTOS.org demo applications ensures this is the case - have you modified
this at all?

Regards,
Richard. http://www.FreeRTOS.org


I wonder... what does this instruction aim for?:

asm volatile ( "LDR LR, [LR, #+60]" );

What is LR+60 pointing to? Why 60? Why not 56 or 64?

Guille

PS: Oh my God! I think I've been bumping my head against the desk all
day for the same exact problem! --- In lpc2000@lpc2..., rseku <rseku@p...> wrote:
>
> I found, that asm instructions in freertos are not compiled as
exactly
> as should be. As a result of execution of below code I get
data_abort
> exception
> First I noticed LDMIA and LDMF difference.
>
> this is RTOS code:
> #define portRESTORE_CONTEXT() \
> {

> extern volatile void * volatile pxCurrentTCB;\

> extern volatile unsigned portLONG ulCriticalNesting;\
> /* Set the LR to the task stack. */ \
> asm volatile ( "LDR R0, %0" : : "m" (pxCurrentTCB) );\
> asm volatile ( "LDR LR, [R0]" );\

> /* The critical nesting depth is the first item on the stack. */\
> /* Load it into the ulCriticalNesting variable. */ \
> asm volatile ( "LDR R0, =ulCriticalNesting" );\
> asm volatile ( "LDMFD LR!, {R1}" );\
> asm volatile ( "STR R1, [R0]" );\
> /* Get the SPSR from the stack. */\
> asm volatile ( "LDMFD LR!, {R0}" );\
> asm volatile ( "MSR SPSR, R0" );\
> /* Restore all system mode registers for the task. */\
> asm volatile ( "LDMFD LR, {R0-R14}^" );\

> asm volatile ( "NOP" );\
> /* Restore the return address. */\
> asm volatile ( "LDR LR, [LR, #+60]" );\
> /* And return - correcting the offset in the LR to obtain the */\
/*
> correct address. */\
> asm volatile ( "SUBS PC, LR, #4" );\
> ( void ) ulCriticalNesting;\
> }
>
> and this is gcc interpretation:
> E1A0C00D mov r12, sp
> E92DD800 stmfd sp!, {r11-r12, lr-pc}
> E24CB004 sub r11, r12, #0x00000004
> /* Simply start the scheduler. This is included here as it
can only be
> called from ARM mode. */
> portRESTORE_CONTEXT();
> E59F3038 ldr r3, [pc, #56]
> E5930000 ldr r0, [r3]
> E590E000 ldr lr, [r0]
> E59F024C ldr r0, [pc, #588]
> E8BE0002 ldmia lr!, {r1}
> E5801000 str r1, [r0]
> E8BE0001 ldmia lr!, {r0}
> E169F000 msr spsr_cf, r0
> E8DE7FFF ldmia lr, {r0-lr}^
> E1A00000 nop
> E59EE03C ldr lr, [lr, #60]
> E25EF004 subs pc, lr, #0x00000004
> E59F300C ldr r3, [pc, #12]
> E5933000 ldr r3, [r3]
>




--- In lpc2000@lpc2..., "Guillermo Prandi"
<yahoo.messenger@m...> wrote:
>
> I wonder... what does this instruction aim for?:
>
> asm volatile ( "LDR LR, [LR, #+60]" );
>
> What is LR+60 pointing to? Why 60? Why not 56 or 64?
>
> Guille
>
> PS: Oh my God! I think I've been bumping my head against the desk
all
> day for the same exact problem!
>

When I see that kind of code it makes me think of an execution stack
frame. Find the way back to the previous frame by using an offset
to the current frame.

Not that I am sure that is what is happening but that is what I have
seen done before where there are frames, notably in Pascal where
everything is linked.


rtstofer wrote:

>--- In lpc2000@lpc2..., "Guillermo Prandi"
><yahoo.messenger@m...> wrote: >>I wonder... what does this instruction aim for?:
>>
>>asm volatile ( "LDR LR, [LR, #+60]" );
>>
>>What is LR+60 pointing to? Why 60? Why not 56 or 64?
>>
>>Guille
>>
>>PS: Oh my God! I think I've been bumping my head against the desk
>>
>>
>all >>day for the same exact problem!
>>
>>
>>
>
>When I see that kind of code it makes me think of an execution stack
>frame. Find the way back to the previous frame by using an offset
>to the current frame.
>
>Not that I am sure that is what is happening but that is what I have
>seen done before where there are frames, notably in Pascal where
>everything is linked. >
>
You're correct, it is the Link Register (stack).

TomW
>Yahoo! Groups Links

--
Tom Walsh - WN3L - Embedded Systems Consultant
http://openhardware.net, http://cyberiansoftware.com
"Windows? No thanks, I have work to do..."
----------------


> I wonder... what does this instruction aim for?:
>
> asm volatile ( "LDR LR, [LR, #+60]" );
>
> What is LR+60 pointing to? Why 60? Why not 56 or 64?

The stack frame is always the same, and this is the offset to the return
address once the context has been restored.

Regards,
Richard. http://www.FreeRTOS.org



> PS: Oh my God! I think I've been bumping my head against the desk all
> day for the same exact problem!

The scheduler code always runs in Supervisor mode (the tasks in System
mode). The processor must therefore be in Supervisor mode when
vTaskStartScheduler() is called, otherwise the code fragment previously
posted will pop the registers into the wrong place.

The startup code for the demo applications ensures the processor is in
Supervisor mode when main() is called. This is why I try and emphasis in
the docs that the best way of creating a new application is to start with
and then modify the provided code/project. This way all the compiler
options and the startup code are automatically correct and you will not get
any problems.

I am thinking about updating the code to ensure a switch into Supervisor
mode actually in the scheduler code immediately prior to the first task
being started. While it would prevent this problem from occurring it is
still really encouraged to use the provided startup code anyway, as it also
configures all the stacks as necessary.

Regards,
Richard. http://www.FreeRTOS.org



--- In lpc2000@lpc2..., "FreeRTOS Info" <nospam@F...> wrote:
>
> > I wonder... what does this instruction aim for?:
> >
> > asm volatile ( "LDR LR, [LR, #+60]" );
> >
> > What is LR+60 pointing to? Why 60? Why not 56 or 64?
>
> The stack frame is always the same, and this is the offset to the
return
> address once the context has been restored.
>
> Regards,
> Richard. > http://www.FreeRTOS.org
>

Oh, I see... 60 = 15 (registers) x 4 (bytes per register).

Thanks, Richard.



I am using Crossworks for ARM 1.5. I think now, there are some project
settings, which change code. Strange is that project compiles only for
Thumb mode. Although it compiles also for ARM mode, but code doesn't
want to download to the chip with Wiggler from Olimex. robert

Guillermo Prandi wrote:

> --- In lpc2000@lpc2..., "FreeRTOS Info" <nospam@F...> wrote:
>
>>>I wonder... what does this instruction aim for?:
>>>
>>>asm volatile ( "LDR LR, [LR, #+60]" );
>>>
>>>What is LR+60 pointing to? Why 60? Why not 56 or 64?
>>
>>The stack frame is always the same, and this is the offset to the
>
> return
>
>>address once the context has been restored.
>>
>>Regards,
>>Richard.
>>
>>
>>http://www.FreeRTOS.org
> > Oh, I see... 60 = 15 (registers) x 4 (bytes per register).
>
> Thanks, Richard. >
>
> Yahoo! Groups Links >
>



> I am using Crossworks for ARM 1.5. I think now, there are some project
> settings, which change code. Strange is that project compiles only for
> Thumb mode. Although it compiles also for ARM mode, but code doesn't
> want to download to the chip with Wiggler from Olimex.

If you are using the uIP Rowley demo, then I have only provided a THUMB
debug sample project (the docs say only to use this configuration).

The FreeRTOS GCC port itself supports both THUMB and ARM builds. If you
look in the FreeRTOS/Demo/ARM7_LPC2106_GCC directory you will see some batch
files as:

ram_arm.bat
ram_thumb.bat
rom_arm.bat
rom_thumb.bat

These build the LPC2106 demo as per the name of the batch file. If you take
a look in the batch file you will see that there are some environment
variables that are configured to setup the required build type, prior to
make being called.

e.g. from rom_arm.bat:

--------
set USE_THUMB_MODE=NO
set DEBUG=
set OPTIM=-O3
set RUN_MODE=RUN_FROM_ROM
set LDSCRIPT=lpc2106-rom.ld
make
-------

Using the Rowley IDE you can do something similar by:
+ Creating a new project configuration ARM_Flash_Debug, setup as per the
THUMB_Flash_Debug config, then...
+ Remove the preprocessor definition THUMB_INTERWORK from the
project->properties->preprocessor settings.
+ Set the instruction set to ARM mode for ALL files using the
project->properties->compiler->instruction set setting. This can be done
globally for the configuration.

I think that should be it - although I have not actually tried an ARM build
from Rowley myself. The kernel port code is the same for the command line
GCC and the Rowley IDE. The only differences being the native linker script
format used by Rowley CrossWorks.

Regards,
Richard.

http://www.FreeRTOS.org