1
votes

I'm working on an embedded project with FreeRTOS, where I only use static memory allocation.

Looking at my linker script, I find that the following are taking up RAM space: .data .bss ._user_heap_stack

To my knowledge, ._user_heap_stack is used during the linking process to see if there is enough RAM space for the user-specified minimum MSP stack size. Here is a relevant snippet in my linker script:

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM

I believe that MSP will always be initialized to point to the end of RAM regardless of _Min_Stack_Size, and decrement from there and data is pushed onto the stack. I see that my startup .S file configures sp as follows:

_estack = 0x20004000;    /* end of RAM */

Reset_Handler:
  ldr   sp, =_estack    /* Atollic update: set stack pointer */

As for FreeRTOS tasks, they each have stack space that is statically allocated, so it has nothing to do with _user_heap_stack I think?

My question is, with the RAM allocated .data, .bss, and _user_heap_stack, I still have some unallocated RAM, so what happens to those RAM? Is it used by anything? Is it ever useful to reserve some free RAM (i.e. non-statically allocated RAM) or is it just wasted? Or perhaps it is just extra space for MSP to use if the main stack ever grows larger in size than what's specified in _Min_Stack_Size?

1
If you can verify that nothing in your code ever touches it, then nothing in your code ever touches it (though typically it will be zeroed behind the scenes by C startup routines). One technique sometimes employed is to prefill memory with a magic value (perhaps by modifying the startup code to do that instead of zero), run for a while, and then come back and then see what has changed; the catch is that this only shows the behavior of code paths you actually exercise.Chris Stratton
Sometimes guard values are placed between used values and checked in the hope of catching overflow, on the theory that it is better to force a restart than run in corrupted state; but again, this only catches things once they trespass, and only if the checker sees it in time.Chris Stratton
Does the magic value method typically assume an active debugger connection? I imagine that you run the code with a debugger, then come back and examine the memory content after a while using the debugger. How would this work if I am deploying the system in the field and don't have an active debugging connection?Ken Lin
Can you also elaborate on what a guard value is and how it is used? I am not 100% sure what it is, thanks!Ken Lin
You could build something into the program itself to check (or count) the magic values in un-utilized regions to determine the watermark of maximum utilization so far. Guard values are the same idea in a smaller range (possibly a single word); you would similarly need to build in a checker or sporadically connect a debugger and look.Chris Stratton

1 Answers

0
votes

TL;DR - The remaining RAM is used by the stack.


Or perhaps it is just extra space for MSP to use if the main stack ever grows larger in size than what's specified in _Min_Stack_Size?

Yes, this seem correct. See the last paragraph for more; it is not just the stack that is bigger.

See: this part,

_estack = 0x20004000;    /* end of RAM */

Reset_Handler:
  ldr   sp, =_estack    /* Atollic update: set stack pointer */

So at least the BOOT sp will be at the end of RAM.

The part with . = . + _Min_Stack_Size; just makes sure you have a MINIMUM stack or a linker error happens. Your stack is actually bigger and it is used at least at boot. I know nothing about FreeRTOS, but I suspectnote1 it is the system stack and you have user stacks. Each mode on the ARM has a separate stack. If FreeRTOS has any memory protection or privileged levels, then you will have multiple stacks. So one task crashing (due to stackoverflow, etc) won't crash the entire system. Just that tasksnote2 stack is corrupt, and not the one that manages the entire system.

It is a common idiom to have stack and heap together. With heap growing up and stack growing down. In this way, the MIN heap size and MIN stack size are imaginary. Eventually they will collide when the size of both are the total size. But things maybe okay if the stack goes into heap logical space or heap goes in to stack logical space AS long as it is not in use by the other. By space, I mean the constants in your linker file and not actual in use values.

Note1: It would kind of be insane to both waste memory and have your RTOS code using the same stack as all tasks. At least it would not be a robust OS.

Note2: By task I mean a schedulable entity. Maybe a process, task, thread, fiber, etc.