ulCriticalnesting not on initial task stack?

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:     vTaskStartScheduler()     xPortStartScheduler()     prvSetupTimerInterrupt()     vPortISRStartFirstTask() 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? --Chris

ulCriticalnesting not on initial task stack?

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. */ *pxTopOfStack = portNO_CRITICAL_SECTION_NESTING; 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. */        "LDR        R0, =ulCriticalNesting                nt"    "LDMFD    LR!, {R1}                        nt"    "STR        R1, [R0]                    nt"    Regards.

ulCriticalnesting not on initial task stack?

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? --C

ulCriticalnesting not on initial task stack?

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? Dave.

ulCriticalnesting not on initial task stack?

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).

ulCriticalnesting not on initial task stack?

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? Dave.

ulCriticalnesting not on initial task stack?

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 USR_STACK_POINTER (RAM_BASE + RAM_SIZE) #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         .text         .global _start         .global undef_routine         .global data_abort         .global prefetch_abort         .global startup_routine _start: 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         ldr SP,=USR_STACK_POINTER         // 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         ldr SP,=(USR_STACK_POINTER-USR_STACK_SIZE-4)         // switch to undefined mode and set his stack pointer         msr cpsr_c, #Mode_UNDEF | F_Bit | I_Bit         ldr SP,=(USR_STACK_POINTER-USR_STACK_SIZE-USR_STACK_SIZE-4)         // switch to fast irq mode and set his stack pointer         msr cpsr_c, #Mode_FIQ | F_Bit | I_Bit         ldr SP,=(USR_STACK_POINTER-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-4)         // switch to abort mode and set his stack pointer         msr cpsr_c, #Mode_ABT | F_Bit | I_Bit         ldr SP,=(USR_STACK_POINTER-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-4)         // switch to supervisor  mode and set his stack pointer         msr cpsr_c, #Mode_SVC | F_Bit | I_Bit         ldr SP,=(USR_STACK_POINTER-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-4)         // Switch back to supervisor         msr cpsr_c, #Mode_SVC         ldr SP,=USR_STACK_POINTER         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 // ///////////////////////////////////////////////////////////////////////////// clear_bss:         ldr     r1, =__bss_start__         ldr     r3, =__bss_end__         subs    r3, r3, r1         beq     .end_clear_loop         mov     r2, #0 .clear_loop:         strb    r2, [r1], #1         subs    r3, r3, #1         bgt     .clear_loop .end_clear_loop:         mov     pc, lr ///////////////////////////////////////////////////////////////////////////// // // Initialize data section // ///////////////////////////////////////////////////////////////////////////// initialize_sdata:         ldr             r1, =_etext         ldr             r2, =__data_start__         ldr             r3, =__data_end__ loopdat:         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 */ MEMORY {   /*    * 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") */ OUTPUT_ARCH(arm7tdmi) ENTRY(_start) SECTIONS {   .text           :   {     _start_of_text_ = .;     *(.vectors)     *(.text .stub .text.*)     *(.glue_7t) *(.glue_7)     *(.rodata)   } > text   _etext = .;   /* RAM */   .data : AT ( ADDR(.text) + SIZEOF(.text) )   {     __data_start__ = . ;     . = ALIGN(2);     *(.data .data.* .gnu.linkonce.d.*)     SORT(CONSTRUCTORS)     . = 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            :   {    *(.dynbss)    *(.bss .bss.* .gnu.linkonce.b.*)    *(COMMON)    /* 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 = .;     *(.stack)   }   .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }   /DISCARD/ : { *(.note.GNU-stack) }   PROVIDE (__stack__ = 0xa00) ; } -– end —