Quality RTOS & Embedded Software

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


ulCriticalnesting not on initial task stack?

Posted by Christopher Piggott on May 26, 2007
I am trying to sort out why my LPC2129 / GCC system is not working. My port began life as GCC/ARM7_LPC2000 modified to match my hardware and address map. In port.c I find a note that says:

Changes from V2.5.2
+ ulCriticalNesting is now saved as part of the task context, as is
therefore added to the initial task stack during pxPortInitialiseStack.

However, examining pxPortInitialiseStack() I do not see this happening. In fact, there is no other reference to ulCriticalNesting anywhere in that file.

Second, I see that ulCriticalNesting defaults to 9999. In a different port I found a note that says that this is to ensure that FreeRTOS knows that interrupts are off during initialization. It indicates that this will be set to 0 once the first task is started. I do not see where this happens...it is not in any of these:


I THINK that this should be in vPortISRStartFirstTask() prior to calling the portRESTORE_CONTEXT() macro.

Can anybody shed some light on what is going on here?


RE: ulCriticalnesting not on initial task stack?

Posted by Richard on May 27, 2007
The critical section nesting depth is zero when the task first starts. It is the last thing placed onto the initial task stack in pxPortInitialiseStack() with the following line:

/* 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. */

The value is then popped off the stack and placed into the ulCriticalNesting within the macro portRESTORE_CONTEXT() with the following lines:

/* The critical nesting depth is the first item on the stack. */\
/* Load it into the ulCriticalNesting variable. */\
"LDRR0, =ulCriticalNesting\n\t"\
"LDMFDLR!, {R1}\n\t"\
"STRR1, [R0]\n\t"\


RE: ulCriticalnesting not on initial task sta

Posted by Christopher Piggott on May 27, 2007
Thanks. I missed that. In light of this, there must be something else wrong with the initial stack, such that when it attempts to context switch to the first task it has an invalid LR and aborts. I will trace further.

I was reflecting on this problem last night, and it got me wondering something more generic. My understanding of the purpose of keeping a critical nesting depth does not mesh with the idea of having to preserve that nesting depth across context switches. In other words, if you were to enter a critical section, then there should not even be a context switch until you have exited that critical section. Within that context, you may want to call functions that also have critical sections; the nesting depth prevents interrupts from being turned back on until you have exited the last of those, i.e. the outer-most; nesting depth goes to 0 and you are no longer in any critical section.

Why, then, should the nesting depth be part of the task state, rather than a system-wide global?


RE: ulCriticalnesting not on initial task sta

Posted by Dave on May 27, 2007
99 times out of 100 this is because you are not in Supervisor mode when you attempt to start the scheduler. It is easiest to call main() in Supervisor mode. Use the startup files provided with the port you based yours on.

While a preemptive context switch will not occur from within a critical section, you still have the option to perform a switch if you want to. If you do this you can be assured that interrupts are disabled when the task starts running again (but will not necessarily be disabled while other tasks are running). This makes for a very flexible system, more so that (most?) other systems?


RE: ulCriticalnesting not on initial task sta

Posted by Christopher Piggott on May 27, 2007
Yep look at that, I was ending in SYSTEM mode, not SUPERVISOR mode. Ha!

I make it all the way to the idle task now. For some reason when the idle task yields it puts me into a bad place (instead of starting my first real task).

RE: ulCriticalnesting not on initial task sta

Posted by Dave on May 27, 2007
Are you -

Setting up stacks of Supervisor and IRQ modes? There is no need to setup stacks for User mode as this is done when the task is created.

Vectoring directly to your SWI and IRQ handlers without going through some intermediary code?


RE: ulCriticalnesting not on initial task sta

Posted by Christopher Piggott on May 27, 2007
Good point. Yes I am setting up USR -- I will fix that next. I also set up an abort stack that I probably also don't need, since abort does nothing but loop to itself. (Maybe later I will want abort to do something more useful).

I noticed some questions about initialization elsewhere on the forums. I will post my startup for the LPC2129/GCC in case it is useful for others. There are two snippets attached: my startup.s as well as lpc2129.x (linker script). I tried to make the linker configuration reasonably minimal. It allows for placement and location of initialized data at separate locations (ram and flash) and all of that seems to work well for me so far.

--- cut here ---
#define RAM_BASE 0x40000000
#define RAM_SIZE 16*1024

#define USR_STACK_SIZE 2048

#define Mode_USR 0x10
#define Mode_FIQ 0x11
#define Mode_IRQ 0x12
#define Mode_SVC 0x13
#define Mode_ABT 0x17
#define Mode_UNDEF 0x1B
#define Mode_SYS 0x1F

#define I_Bit 0x80
#define F_Bit 0x40

.global _start
.global undef_routine
.global data_abort
.global prefetch_abort
.global startup_routine

// set the SYS, I, and F bits in the CONTROL field of the CPU status register
// I is the interrupt mask
// F is the fast irq mask
// T indicates if we are in thumb mode ... it is bit 0x20
// The lower 5 bits are the MODE bits. Mode 0x1F is System mode.
msr cpsr_c, #Mode_SYS | I_Bit | F_Bit

// Load the static pointer to top of ram

// Call the low level initialization
bl lowlevelinit

// switch to irq mode and set his stack pointer too
msr cpsr_c, #Mode_IRQ | F_Bit | I_Bit

// switch to undefined mode and set his stack pointer
msr cpsr_c, #Mode_UNDEF | F_Bit | I_Bit

// switch to fast irq mode and set his stack pointer
msr cpsr_c, #Mode_FIQ | F_Bit | I_Bit

// switch to abort mode and set his stack pointer
msr cpsr_c, #Mode_ABT | F_Bit | I_Bit

// switch to supervisor mode and set his stack pointer
msr cpsr_c, #Mode_SVC | F_Bit | I_Bit

// Switch back to supervisor
msr cpsr_c, #Mode_SVC

bl clear_bss
bl initialize_sdata

mov a2, #0 /* Fill value */
mov fp, a2 /* Null frame pointer */
mov r7, a2 /* Null frame pointer for Thumb */

mov r0, #0 /* no arguments */
mov r1, #0 /* no argv either */

b main

// Clear BSS

ldr r1, =__bss_start__
ldr r3, =__bss_end__
subs r3, r3, r1
beq .end_clear_loop

mov r2, #0
strb r2, [r1], #1
subs r3, r3, #1
bgt .clear_loop

mov pc, lr

// Initialize data section


ldr r1, =_etext
ldr r2, =__data_start__
ldr r3, =__data_end__

cmp r2, r3
ldrlo r0, [r1], #4
strlo r0, [r2], #4
blo loopdat

// done
mov pc, lr
--- end ---

Now, in order to use this you have to have the corresponding linker configuration file, that defines the correct symbols for various pieces of memory. Here's what I came up with:

--- cut here ---
/* Default linker script, for normal executables */

* Code space is 256KB minus 8KB for the bootloader area
* that cannot be used
text (rx) : ORIGIN = 0x00000000, LENGTH = 0x3E000

* RealMonitor (if present) uses 0x40000040 - 0x4000011F
* In System Programming uses 0x40000120 - 0x400001FF
* Flash programming commands use the top 32 bytes of on-chip RAM.
* The resulting useful ram is 0x40000200 through 0x40003FE0
data (rwx) : ORIGIN = 0x40000200, LENGTH = 0x3DE0

/* OUTPUT_FORMAT("elf32-littlearm") */


.text :
_start_of_text_ = .;
*(.text .stub .text.*)
*(.glue_7t) *(.glue_7)
} > text

_etext = .;

/* RAM */

.data : AT ( ADDR(.text) + SIZEOF(.text) )
__data_start__ = . ;
. = ALIGN(2);
*(.data .data.* .gnu.linkonce.d.*)
. = ALIGN(2);
__data_end__ = . ;
} > data

.data1 : { *(.data1) }
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.eh_frame : { KEEP (*(.eh_frame)) }
.gcc_except_table : { *(.gcc_except_table) }
.dynamic : { *(.dynamic) }

_edata = .;
PROVIDE (edata = .);

/* Uninitialized data */
__bss_start = .;
__bss_start__ = .;
.bss :
*(.bss .bss.* .gnu.linkonce.b.*)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections. */
. = ALIGN(32 / 8);
. = ALIGN(32 / 8);
_end = .;
_bss_end__ = . ; __bss_end__ = . ; __end__ = . ;

PROVIDE (end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }

.comment 0 : { *(.comment) }

/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */

/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }

.stack 0x40003FDC :
_stack = .;

.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
/DISCARD/ : { *(.note.GNU-stack) }
PROVIDE (__stack__ = 0xa00) ;

--- end ---

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

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

Latest News

NXP tweet showing LPC5500 (ARMv8-M Cortex-M33) running FreeRTOS.

Meet Richard Barry and learn about running FreeRTOS on RISC-V at FOSDEM 2019

Version 10.1.1 of the FreeRTOS kernel is available for immediate download. MIT licensed.

View a recording of the "OTA Update Security and Reliability" webinar, presented by TI and AWS.


FreeRTOS and other embedded software careers at AWS.

FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Espressif ESP32

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

Xilinx Microblaze and Zynq partner