I went through and after some work, got FreeRTOS compiling on a STM32 CM0 with 4kb of RAM.
I couldn't get FreeRTOS to fit due to allocation too much heap space in the default config.This is the first time I've ever had working with software with dynamic memory allocation on a micrcontroller.
This is the first time I've ever had working with software with dynamic memory allocation on a micrcontroller.
So after pulling out my hair for a bit, I figured out in Keil where you set the IROM/IRAM and got into all of that and made sure those settings were correct. Eventually I saw that you also can allocate the stack and heap in the system startup file.
(In my case, the FreeRTOS port was allocating too much memory to its heap (the port looked like it was expecting 8kb of RAM, so there was enough memory for the rest of the system.)
The error at first was that there was not enough space for .bss objects, which I had never heard of. But it turns out there are a few other memory areas than the heap and stack where other stuff lives. Lesson learned.
But what is actually going on in the startup file to allocate memory?
I have a stock startup file from ST, with 4kb of RAM.
Am I correct that you just take the hex value, and convert it to decimal for the byte amount?
So in the stock startup file, I have 1024 byte of my RAM for the stack, and 512 bytes of my RAM for heap?
Are these start-up instructions used differently? Are they not an allocation, but a minimum amount for the compiler to allocate?
I understand the issue with the dynamic allocation and over-running the heap.
But say I think I will not dynamically allocate more than 512 bytes of RAM, is there a reason I would not change the stack value to 3500 bytes, and fully allocate the ram at startup?
And what about this those .bss objects?! Is that why you leave some unallocated ram from the stack and heap, for the miscellaneous.
PS: I am not thrilled at the thought of dynamic memory allocation on a microcontroller in a commercial product. Particularly because if the system overflows/locks, that's a warranty issue... I know FreeRTOS can now use static allocation at compile time. Ideally probably get that version running, but baby steps for now.
; Amount of memory (in bytes) allocated for Stack ; Tailor this value to your application needs ; <h> Stack Configuration ; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h> Stack_Size EQU 0x400 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp ; <h> Heap Configuration ; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h> Heap_Size EQU 0x200 AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size __heap_limit
These settings are causing the linker to allocate the space in RAM. These areas are cleared by the code in __main before jumping to your main() function.
The placement in RAM is nominally STATICS, HEAP, STACK
FreeRTOS might well have it's own allocator, or thread stacks.
Dynamic memory allocated during your initialization is safe from usual issues. ie configuration driven allocations
Yes, I think partially the fact that the dynamic memory can also be allocated during initialization is what was throwing me. I didn't really think that was possible during compile.
I assumed the heap was only allocated at run-time (classic malloc/free tutorial). I'll have to dig more on that. Important lesson learned...
I see that .bss object is one of several classes of statics that get stored in that 4kb of RAM. So actually the compiler/linker, was telling me there was no space for the statics in memory.
I talked with a guy with a compiler and assembly experience, and he very nicely stepped me through some 200 level compiler stuff I didn't know.
For the startup syntax, yes those are set ranges that both the stack and heap get explicit allocations for, which is noted by the linker. The compiler/link doesn't do any sort of smart calculations or optimize the object files when it compiles.
For sizing the stack space, the risk is pretty marginal, because you have the functions local variables and the function return address (not sure the exact term) coming in and off of the stack. So long as you go through all the functions in your embedded system, you can determine pretty quickly if your stack space is sufficient.
For sizing the heap space, well yes that's really dependent on what your doing. In this case, spinning off a bunch of tasks in an RTOS, could cause an overrun, but you wouldn't know until you in fact have crashed your system!
For sizing the statics, well they either fit or they don't because they are known at compile time.
So, no you wouldn't want to necessarily allocate my hypothetical 2.5kb of remaining RAM, because you would have no space for the statics left in memory.
The stack depth from the call tree can be predicted via static analysis in some cases, but this is complicated by multi threaded execution and interrupts, or recursive algorithms.
With the statics try to avoid global variables, use the stack for local/auto variables used for peripheral initialization where scope can be contained.
I assumed the heap was only allocated at run-time (classic malloc/free tutorial).
That assumption is expressed fuzzily enough that it can be either wrong or right.
At run-time, you allocate memory from the heap. But in a stand-alone embedded system, you still have to make a build-time decision about how much memory to allocate for the heap. The strictly classic textbook decision would be: zero. Industry coding standards for embedded programming like MISRA often forbid any and all usage of the heap.
Yes, I was looking at FreeRTOS more on this allocation issue.
At build time, you use the startup file you define the allocations. I get that.
FreeRTOS has a header where you define the actual heap allocation at build time.
Is there some connection to the linker to actually see if that allocation in the header for the heap is valid -- at build time? It seems like there was, because the linker was giving an error until I changed that heap allocation definition.
Obviously at run time, the wheels can fall off the wagon...
I have no opinion on MISRA or the good/bad nature of using dynamic allocation. I would say for the product/s we build, I would prefer not to use it.
Never mind, I just looked at the code real quick.
FreeRTOS, I would guess has been through a zillion iterations. I just started (trying!) to use it.
You can see actually that their define, actually creates a place in the static memory.
Which FreeRTOS than parcels back out and self manages.
Is this a "true" use of the heap... I don't know, because I would guess this actually maps to the memory area where the statics get placed by the linker. In any case, it is an example of dynamic memory usage.
#if( configAPPLICATION_ALLOCATED_HEAP == 1 ) /* The application writer has already defined the array used for the RTOS heap - probably so it can be placed in a special segment or address. */ extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; #else static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];