Design Solutions Research & Design Hub

FreeRTOS – Part 2

Written by Bob Japenga

FreeRTOS Tasks

Bob continues his article series about the open-source FreeRTOS. At the heart of FreeRTOS is the task. In part 2, looks at what a task is, what options are available to configure a task’s Task Control Block (TCB) and what features might be missing in the FreeRTOS TCB.

  • What is a task in RTOSes?

  • How does execution context work?

  • What are the optional TCB parameters in FreeRTOS?

  • What’s missing in a FreeRTOS TCB?

  • FreeRTOS

Growing up, I gradually discovered that I was good at multi-tasking. I first noticed it while working summers in the blueberry fields in Michigan. I could pick blueberries and muse about a myriad of topics (walking and chewing gum at the same time came later). Then, while in high school, I worked in a machine shop and operated a punch press. My mind would take endless excursions from girls to relativity—all while I stamped out the metal components of a greeting card rack for American Greetings. As I grew older, I would find myself multi-tasking in many more situations. While developing software, the compile, link and load times allowed me to do other things while waiting to test and debug my code. I answered email, made phone calls or touched base with a colleague. With the advent of the cell phone, my multi-tasking increased.

Somewhere along the line, I began to hear that perhaps this was not such a good habit. Various studies [1][2] came along with mixed results. But summary statements like this got my attention: “People who frequently use many types of media at once, or heavy media multitaskers, performed significantly worse on simple memory tasks” [3]. As I have gotten older, and complex cognitive tasks have become harder, I have attempted to break myself of this life-long habit. Figure 1 is me except for the tie!

FIGURE 1 – Frantic multi-tasking

Although there is much to learn about the effects of multi-tasking on our brains, multi-tasking operating systems are well-documented. This month we will continue our series on FreeRTOS—concentrating on the task. What is a task? What is the difference between a thread and a task? What are the key elements of a FreeRTOS task? And finally, what is missing in a FreeRTOS task that is included in more complex RTOSes?


From the FreeRTOS Tutorial [4], a task is a structured set of software that execute independently of other tasks. Of course, “independently” is a relative term. On a single core processor, only one task can execute at a time. One goal of every OS is to allow the tasks to be as independent as possible. But other tasks can affect timing, resources and stability. In Figure 2 Data Acquisition, User Interface, Network Communications and Logging are “independent” tasks. For a more detailed introduction to tasks and multi-tasking, checkout Part 1 of this article series “FreeRTOS (Part 1)” (Circuit Cellar 365, December 2020 [5]).

FIGURE 2 – Multi-tasking OS

So, what is the difference between a thread and a task? Tasks can go by different names: process, apps or threads. In “A Note About Terminology,” the FreeRTOS tutorial [4] says:

In FreeRTOS, each thread of execution is called a “task.” There is no consensus on terminology within the embedded community, but I prefer “task” to “thread,” as thread can have a more specific meaning in some fields of application.

What this means is that documentation for FreeRTOS uses thread and task interchangeably. Therefore, a function that is “thread safe” can be safely used in multiple tasks—it is task safe. Some operating systems (Linux) use the words “process” and “thread” for tasks or threads of execution. And Linux uses the term task to encompass the totality of a process and thread. The creator of Linux, Linus Torvalds, says:

The way Linux thinks about this … is that there is no such thing as a “process” or a “thread”. There is only the totality of the [Context of Execution] (called a “task” by Linux) [6].

Linux allows separate execution threads to inherit some of the Execution Context from a parent. This includes things like the CPU state (registers), the Memory Management Unit state if applicable (page mappings), permissions and various states of resources. For example, a process (or task) in Linux can start another process with a completely independent Execution Context. Or, it can start a thread which inherits some of the parents Execution Context. For our purposes, FreeRTOS uses thread and task (or process) interchangeably and there is truly no difference.


Each time the scheduler or kernel needs to stop one task and start another task, the Execution Context of the first needs to be stored and the Execution Context of the second restored. Obviously, different processors will have different elements of the Execution Context. For example, if the processor does not have memory management, then there is no need to store that information. For most operating systems and FreeRTOS, this Execution Context is stored in the Task Control Block (TCB) and a stack.

Listing 1 

struct tskTaskControlBlock                 /* The old naming convention is
                                           used to prevent breaking kernel 
                                           aware debuggers. */
    volatile StackType_t    *pxTopOfStack;    /*< Points to the location of
                                              the last item placed on the 
                                              asks stack.  THIS MUST BE 
                                              THE FIRST MEMBER OF THE 
                                              TCB STRUCT. */
    ListItem_t              xStateListItem;   /*< The list that the state
                                              list item of a task is
                                              reference from denotes
                                              the state of that task
                                              (Ready, Blocked, 
    ListItem_t              xEventListItem;   /*< Used to reference a
                                              task from an event list */
    UBaseType_              uxPriority;       /*< The priority of the 
                                              task.  0 is the lowest 
                                              priority. */
    StackType_t             *pxStack;         /*< Points to the start
                                              of the stack. */
    char                    pcTaskName[ configMAX_TASK_NAME_LEN ];  
                                              /*^ Descriptive name given
                                              to the task when created.
                                              Facilitates debugging only.*/
} tskTCB;                                     /*lint !e971 Unqualified char
                                              types are allowed for strings
                                              and single characters only.*/

LISTING 1. FreeRTOS minimal task control block (TCB).

Since FreeRTOS is highly configurable, let’s look at the minimal TCB and then look at what options are provided for your tasks. Listing 1 above shows the C code of the minimal TCB for FreeRTOS. This provides a great summary of the basics that are needed for the context of a task including:

Start of the stack: Where the stack pointer is set when the task is initialized.
Top of the stack: This points to the last item put on the stack.
State of the task: Is the task Ready, Blocked or Suspended?
Event list: For the location of call-back functions for events
Priority: The numeric value of the priority of the task (higher number is a higher priority)

My initial take on this list was that it was just lacking one thing. Every RTOS that I ever created from scratch or used had a maximum stack size so that the RTOS could determine stack-overruns. But I realized that it is not absolutely necessary. Just design the code perfectly and then thoroughly test and you will never need the OS to check for stack-overruns.


That leads nicely to the optional parameters in the TCB for FreeRTOS. Of course, the pointer to the end of the stack is included for checking stack-overruns. Here are the optional parameters in the TCB:

End of stack: This pointer is used during context switches to check for stack-overruns. It is used in method 1 of FreeRTOS’s Run Time Stack Checking. Because checking for stack-overruns at the time of a context switch may be too late, FreeRTOS also incorporates a second method that fills the stack with a known pattern, which can be checked at any time for stack-overruns. If the pattern is not present beyond the end of the stack, a task’s stack-overrun is flagged. This enables a watchdog-type task to continuously monitor each task for stack-overruns.

Memory management parameters: Not all processors have memory management and many handle it in a different manner. This pointer allows complete flexibility based on the individual port of FreeRTOS.

Critical section nesting count: This is used if you have functions that enter a critical section of code that cannot be interrupted or that cannot allow a task switch. FreeRTOS keeps track of these for you so that, if you are in a critical section of code and you call a function that enters and exits the critical section, the RTOS will not exit the critical section until the counter reaches zero. When we used the smx RTOS many years ago, we needed to maintain this ourselves.

Enable trace: This enables debuggers to provide tracing.

Enable mutexes: Mutex stands for mutual exclusivity. Mutexes can ensure atomic access to any shared resource. See my article “Concurrency in Embedded Systems (Part 5)” (Circuit Cellar 271, February 2013 [7]) for more details about mutexes.

Enable task tagging: This feature allows the task to be identified by a tag.

Amount of local thread pointers: FreeRTOS allows for pointers to global variables to be stored in the TCB. Some C libraries have global variables associated with them. errno is the most infamous. In a multi-tasking system with a single library, this can create a problem as demonstrated in Figure 3. A low priority task fails an fopen and tries to read library global: errno. A higher priority task interrupts the low priority task after the fopen but before errno is read. This causes the low priority task to have the wrong value for errno. This optional feature allows common libraries to use pointers to these global variables to be stored in the TCB to maintain deterministic results.

FIGURE 3 – As shown here, a low priority task fails an fopen and tries to read library global: errno. A higher priority task interrupts the low priority task after the fopen but before errno is read. This causes the low priority task to have the wrong value for errno.
(Click to enlarge)

Enable run time stats: Enabling this allows FreeRTOS to accumulate how much time the task has been in a running state.

Enable newlib library: The GNU Arm embedded tool chain includes a smaller run-time library called newlib (there is also a nano version of this). This library, if used incorrectly, has re-entrancy issues with certain calls. FreeRTOS provides support for it but disavows its reliability.

Enable task notifications: The FreeRTOS Tutorial has an entire chapter on Task Notifications. The author explains it better than I can:

“Task Notifications” allows tasks to interact with other tasks, and to synchronize with ISRs, without the need for a separate communication object [Like a queues-, a semaphores- or event-group].

Allow static or dynamic stack and/or TCB: FreeRTOS allows the designer the flexibility of having both the stack and the TCB to be dynamic or static. But if so, the kernel needs to know that and keep track of it.

Abort delay functionality: If a task has a delay that has not timed out at the time it was aborted, this feature allows the timer to end when the task was aborted. Perhaps you know that your design will never abort tasks or won’t care if they get delayed because of a pending wait? Not enabling this will slightly reduce your footprint.

Enable POSIX error numbering: As you may suspect, FreeRTOS is not POSIX (Portable Operating System Interface) compliant. However, a POSIX wrapper for FreeRTOS is coming. FreeRTOS+POSIX provides a subset of the POSIX threading API. This addition to the TCB allows compatibility with POSIX error numbering.


Now let’s take a look at what’s missing in a FreeRTOS TCB. It is an apples and oranges comparison between FreeRTOS and Linux. The TCB in FreeRTOS is 75 lines of code whereas in Linux it is more than 700 lines. We don’t want FreeRTOS to become Linux! But there are some things that are missing that may be of value going forward.

Security: Security is always on our mind and Linux supports a number of features in its equivalent TCB. Randomization of the TCB structure to increase security from prying eyes is one example.

Multi-core support: There are a few ports (Espressif for the ESP32) of a symmetric multiprocessing (SMP) version of FreeRTOS. The Linux TCB includes several variables that support SMP. As our microprocessors get more complex, non-uniform memory access (NUMA) may be required in the TCB. This allows for true multi-processors as opposed to multi-core devices which have uniform memory.

Trace capability: Linux provides a lot of tracing capability in the TCB that could enhance FreeRTOS without a significant cost.

Parent ancestry: Linux provides a lot of data for keeping track of which tasks started which. This could be useful going forward as FreeRTOS matures.

Out of memory (OOM) support: Although dynamic memory is a no-no for many embedded systems, (see MISRA C Guidelines [8]), FreeRTOS allows dynamic memory. Therefore, I think a mechanism to support OOM is essential for those systems.


One advantage of FreeRTOS is that it is still small enough to actually get a handle on what it does. Next time, just as I looked at configuring Linux in a previous article, I will look at what configuration options (other than those covered this month) are available to you. But of course, only in thin slices. 

Read Part 1 Here

Read Part 3 Here


[1] “Minds and brains of media multitaskers: Current findings and future directions” Statements like this in their conclusion “in general, heavier media multitaskers often exhibit poorer performance in a number of cognitive domains” make one sit up and take notice.
[2] Reference 1 adds: “many studies report[ing] no performance differences between groups”
[3] October 28th, 2018 article in the Stanford News
[4] This is a very good and helpful tutorial.
[5] Embedded in Thin Slices: Part 1 of the FreeRTOS series in Circuit Cellar December 2020 Issue 365
[6] Check out this email from the creator of Linux Linus Torvalds
[7] Embedded in Thin Slices: Concurrency in Embedded Systems (Part 5)” (Circuit Cellar 271, February 2013)
[8] See  for a great set of documentation for developing safety critical embedded systems

FreeRTOS |


Keep up-to-date with our FREE Weekly Newsletter!

Don't miss out on upcoming issues of Circuit Cellar.

Note: We’ve made the Dec 2022 issue of Circuit Cellar available as a free sample issue. In it, you’ll find a rich variety of the kinds of articles and information that exemplify a typical issue of the current magazine.


Advertise Here

Would you like to write for Circuit Cellar? We are always accepting articles/posts from the technical community. Get in touch with us and let's discuss your ideas.

Sponsor this Article
+ posts

Bob Japenga has been designing embedded systems since 1973. From 1988 - 2020, Bob led a small engineering firm specializing in creating a variety of real-time embedded systems. Bob has been awarded 11 patents in many areas of embedded systems and motion control. Now retired, he enjoys building electronic projects with his grandchildren. You can reach him at

Supporting Companies

Upcoming Events

Copyright © KCK Media Corp.
All Rights Reserved

Copyright © 2024 KCK Media Corp.

FreeRTOS – Part 2

by Bob Japenga time to read: 10 min