Quality RTOS & Embedded Software

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




Loading

LPC2129-GCC port.

Posted by Richard on October 19, 2012
This topic was lost when the forum software was switched back to the old version. I am pasting the entire thread below as a single post so it does not get lost.

RE: LPC2129-GCC port.

Posted by Richard on October 19, 2012
is it OK to modify the function 'pxPortInitialiseStack()' in 'port.c' as below while porting FreeRTOS to LPC2129 with GCC tool.
because without this modification, the scheduler will not start the task due to improper information on stack when it is restored.
------------------------- ORIGINAL FUNCTION --------------------------------------------
portSTACK_TYPE pxPortInitialiseStack( portSTACK_TYPE pxTopOfStack, pdTASK_CODE pxCode, void pvParameters ) { portSTACK_TYPE pxOriginalTOS;
pxOriginalTOS = pxTopOfStack;

/* To ensure asserts in tasks.c don't fail, although in this case the assert
is not really required. */
pxTopOfStack--;

/* Setup the initial stack of the task. The stack is set exactly as
expected by the portRESTORE_CONTEXT() macro. */

/* First on the stack is the return address - which in this case is the
start of the task. The offset is added to make the return address appear
as it would within an IRQ ISR. */
*pxTopOfStack = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE;
pxTopOfStack--;

*pxTopOfStack = ( portSTACK_TYPE ) 0xaaaaaaaa; /* R14 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x12121212; /* R12 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x11111111; /* R11 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x10101010; /* R10 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x09090909; /* R9 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x08080808; /* R8 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x07070707; /* R7 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x06060606; /* R6 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x05050505; /* R5 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x04040404; /* R4 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x03030303; /* R3 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x02020202; /* R2 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x01010101; /* R1 */
pxTopOfStack--;

/* When the task starts is will expect to find the function parameter in
R0. */
*pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */
pxTopOfStack--;

/* The last thing onto the stack is the status register, which is set for
system mode, with interrupts enabled. */
*pxTopOfStack = ( portSTACK_TYPE ) portINITIAL_SPSR;

if( ( ( unsigned long ) pxCode & 0x01UL ) != 0x00 )
{
/* We want the task to start in thumb mode. */
*pxTopOfStack |= portTHUMB_MODE_BIT;
}

pxTopOfStack--;

/* Some optimisation levels use the stack differently to others. This
means the interrupt flags cannot always be stored on the stack and will
instead be stored in a variable, which is then saved as part of the
tasks context. */
*pxTopOfStack = portNO_CRITICAL_SECTION_NESTING;

return pxTopOfStack;
}
------------------ MODIFIED FUNCTION ------------------
portSTACK_TYPE pxPortInitialiseStack( portSTACK_TYPE pxTopOfStack, pdTASK_CODE pxCode, void pvParameters ) { portSTACK_TYPE pxOriginalTOS; portSTACK_TYPE *pxTempTOS;
pxOriginalTOS = pxTopOfStack;

/* To ensure asserts in tasks.c don't fail, although in this case the assert
is not really required. */
pxTopOfStack--;

/* Setup the initial stack of the task. The stack is set exactly as
expected by the portRESTORE_CONTEXT() macro. */

/* First on the stack is the return address - which in this case is the
start of the task. The offset is added to make the return address appear
as it would within an IRQ ISR. */
*pxTopOfStack = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE;
pxTopOfStack--;

pxTempTOS = pxTopOfStack;
*pxTopOfStack = ( portSTACK_TYPE ) 0xaaaaaaaa; /* R14 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x12121212; /* R12 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x11111111; /* R11 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x10101010; /* R10 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x09090909; /* R9 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x08080808; /* R8 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x07070707; /* R7 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x06060606; /* R6 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x05050505; /* R5 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x04040404; /* R4 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x03030303; /* R3 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x02020202; /* R2 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x01010101; /* R1 */
pxTopOfStack--;

/* When the task starts is will expect to find the function parameter in
R0. */
*pxTempTOS = (unsigned int *)pxTopOfStack;
*pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */
pxTopOfStack--;

/* The last thing onto the stack is the status register, which is set for
system mode, with interrupts enabled. */
*pxTopOfStack = ( portSTACK_TYPE ) portINITIAL_SPSR;

if( ( ( unsigned long ) pxCode & 0x01UL ) != 0x00 )
{
/* We want the task to start in thumb mode. */
*pxTopOfStack |= portTHUMB_MODE_BIT;
}

pxTopOfStack--;

/* Some optimisation levels use the stack differently to others. This
means the interrupt flags cannot always be stored on the stack and will
instead be stored in a variable, which is then saved as part of the
tasks context. */
*pxTopOfStack = portNO_CRITICAL_SECTION_NESTING;

return pxTopOfStack;
}
Thanks,
GCD

Reply
Link
Edit
Delete
Attach

Richard
23 hours ago
Can you please tell me what it is you changed so I don't have to go through the two functions line by line.
I'm not sure why any change would be necessary as the code that starts the first task is written in assembler and expects to find things on the stack exactly as placed on the stack with this code.
Regards.

Reply
Link
Edit
Delete
Attach

GCD
3 minutes ago
Hi Richard,
Thanks for the response. Modification is as below
Statement below Just before storing the data supposed to be in 'R14' on the
stack
pxTempTOS = pxTopOfStack;
below statement before storing the dummy contents of 'R0'
pxTempTOS = (unsigned int )pxTopOfStack;
I encountered this issue while debugging for not getting the first task started. unfortunately don't remember what value was getting corrupted. But got the tasks running after this modification even with FREERTOS version, 7.2.0. I'll recheck the whole procedure I did to use FREERTOS on LPC2129 with GCC. I apologise if this topic is misleading.
Thanks

Reply
Link
Edit
Delete
Attach

Richard

RE: LPC2129-GCC port.

Posted by Richard on October 19, 2012
So, if I understand correctly, the code you added:

1) Stores a pointer to the address that R14 will be popped from.

2) Writes 0xaaaaaaaa to the address R14 will be popped from.

3) Writes over 0xaaaaaaaa (the value never gets used) with the address that R0 will be popped from. R0 holds the parameters passed into the function.

So the net effect is, the stack frame is unchanged *other than*, when the task starts, R14 holds the address that R0 was popped from.

I don't understand why this would make a difference. If you compiler conforms to the ARM EABI standard, then the value in R14 should not be used unless you try to return from the task function (which is not allowed).

Which compiler are you using? (I know you said GCC, but which build?)

Regards.

RE: LPC2129-GCC port.

Posted by GCD on October 20, 2012
Hi Richard, got it..

Initially I'll explain the issue why I did the modification. Later i'll give the compiler details I am using.

a. Issue because of which I had to do the above modification
actually in function 'portRESTORE_CONTEXT()' in portmacro.h, after restoring the whole stack into system registers (R0 through R14), there are two more instructions to calculate PC values as below,

---------------------------------------------------------------------------------------------------------
/* Restore the return address. */ \
"LDR LR, [LR, #+60] \n\t" \
\
/* And return - correcting the offset in the LR to obtain the */ \
/* correct address. */ \
"SUBS PC, LR, #4
-------------------------------------------------------------------------------------------------------------------------------------

while trying to restore the return address using first instruction, adding 60 to the content of LR will be erroneous hence I added the address in the stack from where R0 will be popped. So with the modification, along with the address correction using next instruction gets PC value to the proper TOP OF STACK to get the return address.


b. GCC Compiler details. As u said, it looks as L14 is being used to get the right address, may be the compiler is not EABI compliant. but I have no idea how to check whether the compiler conforms to EABI. following are the details of the compiler I am using

----------------------------------------------------------------------------------------------------------------------------------------

FREE_RTOS_LPC_2129_v7# arm-softfloat-elf-gcc-4.4.3 -v
Using built-in specs.
Target: arm-softfloat-elf
Configured with: ../configure --target=arm-softfloat-elf --prefix=/usr/local/cross-arm --enable-interwork --enable-multilib --enable-languages=c,c++ --with-newlib --without-headers --disable-shared --with-gnu-as --with-gnu-ld --with-float=soft
Thread model: single
gcc version 4.4.3 (GCC)

----------------------------------------------------------------------------------------------------------------------------------------

however, with the above modification, I could see 3 tasks running but looking for the right way to get the rtos running

RE: LPC2129-GCC port.

Posted by GCD on October 20, 2012
---------- a correction to one of my statement above --------------

instead of
"adding 60 to the content of LR will be erroneous hence I added the address in the stack from where R0 will be popped"
it has to be
"adding 60 to the content of LR will be erroneous hence I copied the address of the stack location from where R0 will be popped to the location from where R14 is popped."

RE: LPC2129-GCC port.

Posted by Richard on October 21, 2012
The microcontroller should be in Supervisor mode when the first task is started. The code pops the registers from the initial stack frame into the System mode registers. So, while the CPU is using the Supervisor mode registers, it restores the System mode registers, then switches into System mode when the task starts.

If you are seeing R14 being altered during the start first task execution then my best guest (actually, almost certainly) you are starting the scheduler from the wrong CPU mode.

The easiest way to ensure the CPU is in the right mode is to have your start up code set the mode to Supervisor before main() is called. Then it will be in Supervisor when it starts the first task, and System mode when the task actually executes.

Regards.

RE: LPC2129-GCC port.

Posted by GCD on October 21, 2012
Hi Richard,
Thanks, got it working!!


[ 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