Hi, I have used FreeRTOS successfully on several projects. My next project is one where global variables are highly discouraged but stack and heap are fine. Even after stripping FreeRTOS down to bare bones (this is ARM Cortex-M single core) I still see nearly 256 bytes parked in .bss and .data. Is there any viable way to avoid the use of globals in FreeRTOS or is that major surgery?
You first need to fix your definition or method of measuring “global” variables. My guess is that much of what you are measuring are the file-static variables in task.c, which hold the basic kernel state, which is inherently “static” in nature (not local/inside a function) so shows up in the .bss section. You could take all this state, wrap it into a structure and dynamically allocate it with portMALLOC and store just a pointer to it in file-static memory, and reduce the size of the .bss section, and the cost of slower code and creating more of the coupling that the avoidance of “global variables” tries to achieve.
You will also find that the primitives used for communication between FreeRTOS tasks tend to work best a “global” variables.
One other BIG warning, don’t try to avoid “global” variables by placing the variables in the main function stack and pass pointers to that to the tasks, as many ports “reset” the main state to use for interrupts, and thus corrupt such variables.
I personally try to make as much of these variables as possible file-static objects and create the primitives with the static creation function calls, even to the extent of my task stacks are allocated in static memory (vs dynamically created through malloc-like functions), as this lets me KNOW my memory requirements and can control which things go in which memory (internal ram is limited, but faster than external ram) and I can possible recognize the addresses of things (or look them up in the linker map). This says I have an ENORMOUS set of .bss segments.
I don’t have a clear answer to your question. Just sharing my observations here. I also observe similar result when
configSUPPORT_STATIC_ALLOCATION is set to 0. Global variables are used in timer.c and tasks.c.
Tasks and timer implement a singleton design. If we want to remove the static global data, we will need to update the APIs to pass the context or come out other APIs to allocate and get the singleton context. pxCurrentTCB is a gloable variable in tasks.c. It is referenced in the port for context switch and need to be considered. There are many lines of code using these global variables so a big change could be imagined.
I think a large part of the question is based on a confusion of the guideline to limit the use of “global variables”. A variable that is (or potentially is) manipulated by wildly disparate parts of the program can make understanding the program hard to do.
This has NOTHING to do with the amount data being statically allocated. You could allocate a large structure of such data dynamically and reference it with a single global pointer many places in the code, and you still get the same problem. The issue is how widely is the data accessed.
In FreeRTOS, the static structures in task.c and timer.c are not such data. Most are even normally declared static so they can ONLY be accessed within that file. A few need to be accessed by the porting layer, so are made true globals (like pxCurentTCB) but these are not supposed to be manipulated by anything but FreeRTOS itself (and are not declared in any public headers).
Also, some embedded guidelines say that a program should avoid the use of dynamically allocated memory (as that means you need to figure out how to handle the possible failure of such allocations) and as such ALL memory in the program will end up being “statically allocated”, either directly for the objects, or for the memory space that will become a task stack. Such a system will have configSUPPORT_DYNAMIC_ALLOCATION set to 0, and configSUPPORT_STATIC_ALLOCATION set to 1. In such a system you KNOW that you have enough memory for your usage (at least once you have stack sizes set correctly, and you really shouldn’t be having large objects on the stack).
Thanks for the feedback. Agreed that static allocation is often preferred to dynamic allocation since the compiler then knows exactly how much memory will be allocated.
To clarify my question, I am not so much worried about the scope of variables as I am about where the variables in the .data and .bss sections are located in memory. Right now the compiler/linker will park global and static variables where it wants in .data/.bss and the location is fixed for all time. In the case that I want to land global and static variables in a particular region of memory determined at runtime (i.e. unknown to compiler/linker) then it seems like major surgery is required.
The COMPILER doesn’t know where they will land, that is determined by the linker.
Why do you want the linker to not know where it placed them?
Again, it seems that you just want to obfuscate your code by hiding the actual data behind pointers to dynamically allocated memory (if it was statically allocated, the linker WILL know, as it placed it there).
If you want to be be able to control where it ends up, just add the attributes to the variables to assign them to specific memory segments and tell the linker where to put them.
Note, trying to put variables in memory besides the normal .data/.bss segments does mean YOU will have to handle the changes to the startup code to make sure these new memories get properly initialized. That is one thing about dynamic allocation, you need to add the explicit initialization of the memory after you allocate it.
Again, why are you interested in making the program less efficient in accessing these important data items?
Would you please describe the problem that you are trying to solve? What are you trying to achieve by doing this? If you just want to place certain variables in a section of memory, then you can use attributes and linker script as Richard described.
Sorry to be vague. In my application there are a handful of SRAM faults at random locations. Before FreeRTOS starts I know where they are and I want to steer the FreeRTOS variables to a region of SRAM that is known not to have any faults.
If the errors are at fixed locations on all devices, then you can just build linker segments to avoid those locations and assign variables to the good segments (and may need to update the startup to initialize multiple segments).
If the errors vary by device, then you are going to need to do the major surgery. But, I would advise if that is actually the case, You seem to have defective parts, and how sure are you that other faults won’t occur.