Code and data size for an RTOS-based design
This article is written by Jean J. Labrosse, RTOS Expert.
An RTOS consists of a set of services (i.e., functions) that a developer adds to an application. These services will consume both flash (code space) and RAM (data space).
The actual amount of code space consumed by an RTOS is typically quite small, ranging from about 8 kilobytes to 24 kilobytes. Code space is generally not a concern with today’s 32-bit CPUs and MCUs. On the other hand, an RTOS-based application requires more RAM than a single threaded application (i.e., super loop).
An RTOS uses internal variables to perform its duties. Typically, this ranges from a few hundred bytes up to a kilobyte or so. Each task in an application also requires a data structure called a task control block (TCB) which the RTOS uses to keep track of the status of each task. A TCB can consume between 50-250 bytes of RAM depending on the features provided by the RTOS as well as whether the RTOS collects statistics about each task.
Probably the biggest consumer of RAM in an RTOS-based application is the stack that each task requires, the size of which depends on the task’s requirements (e.g., function call nesting, arguments passed to functions, local variables, etc.). To avoid stack overflows, a developer needs to over-allocate stack space, yet not too much, to avoid wasting RAM. The linker in IAR Embedded Workbench has a neat feature which helps determine how much stack space each task will require. You simply check boxes in the linker’s configuration (see screen shots below), build your code and examine the link map (.MAP file) to reveal the call stack depth (in bytes) for each function in your application. You then simply note the task’s call stack size for each of your tasks since we still have to add one or two values to that number.
The stack for each task needs to hold enough storage to hold the context of the task. This consist of a copy of the CPU registers as well as the FPU registers (if an FPU is used). The simple equation below is used to determine the total task stack size (in bytes) needed for a given task and, adds an extra 33% to provide some wiggle room. In fact, in most embedded applications, it’s desirable to keep run-time stack usage below the 70% mark. You can certainly be more conservative as needed by your requirements.
As an example, let’s assume one of the task’s call stack in your application is 256 bytes deep and you are using a Cortex-M4. In this case, the CPU context is 64 bytes while the FPU is another 132 bytes. The above equation would thus yield the follow task stack size:
You can confirm the actual stack usage at run-time by examining the kernel awareness feature provided in the C-SPY Debugger in IAR Embedded Workbench as shown below for a uC/OS-III based application.
Finally, tasks can either share resources or communicate with each other, and do so through other data structures that are called RTOS objects. RTOS objects are small, and typically consume between 16 to 64 bytes each.
For example, let’s assume an application has 10 tasks, and on average a task stack is 1 kilobyte (typical task need less). If the application also has 5 RTOS objects (each 64 bytes), then this is the calculation for the required RAM:
However, this RAM is solely for the RTOS’ needs; it does not include the amount of RAM needed for the application code itself.