Skip to content

FreeRTOS »

RTOS Overview and FreeRTOS introduction

Using RTOS on MCU is method to deal with concurrent tasks which need to be handled in real-time within a acceptable delay. A task is a piece of code that can be scheduled by OS scheduler and dedicated for a specific functionality. Tasks can have different priorities to be run in an predictable order.

Last update: 2022-05-29

Real-time Operating System#

The main purpose of an OS is to have the functionality, of running multiple tasks at the same time, which obviously isn’t possible with bare metal.

Multitask Execution

A Real-time Operating System (RTOS) is designed to do manage different tasks to guarantee that all critical operations must be performed on time, and within a given time.

Critical operations include:

  • Exceptions and Interrupts
  • Prioritized functions
  • Scheduling

Having a RTOS system means:

  • Timeliness is more important than performance
  • It’s guaranteed on data processing within a timing constraint
  • Hard real-time functions must complete within a given time

The core of a RTOS is an advanced algorithm for scheduling, with the key factors are minimal interrupt latency and minimal thread switching latency.

Examples of RTOS system:

A Task#

A Task is a piece of code, or a function, that does a specific job when it is allowed to run.

A Task has its own Stack to create its local variables. Its stack can be used to store addition information which is needed to save or restore the task from running state.

Usually, a task is an infinite loop which can repeatedly do multiple steps.

void task_main(void *param) {
    // init task
    // main loop
    while(1) {
        // do things over and over

A Task should be put into some states:

  • INACTIVE: not to be run
  • READY: in queue to be run
  • RUNNING: is being executed
  • WAITING or BLOCKED: is paused, put in run queue, but not to be run in next time slot

The Scheduler#

This is the core of an RTOS, which decides which task will be run in next time slot.

Some types of a scheduler:

  • Cooperative: task by task, each task does its work until it finishes
  • Round-robin: each task has a time slice to run, there is no priority for task execution
  • Pre-emptive/ Priority-based: task has priority which has high number can interrupt the running task and takes place of execution

Round-robin scheduler

Priority-based scheduler

A simple Round-robin Scheduler

In this guide A simple implementation of a Task Scheduler, we have understood about how a Round-robin Scheduler works with its main reponsibilities:

  • Run a task
  • Select a next task to be run
  • Switch tasks

Priority Inversion

In Pre-emptive RTOS, when a High Priority task is waiting for a Low Priority task to run because the Low Priority is blocked by a shared resource that High Priority is also depent on.

The SysTick#

SysTick is a part of the ARM Core, that counts down from the reload value to zero, and fire an interrupt to make a periodical event. SysTick is mainly used for delay function in non-RTOS firmware, and is used as the timing interrupt for RTOS scheduler.

SysTick is also used as countable time span of a waiting task. For example, a task need to read an input, and it should wait for 50 ms, if nothing comes, task should move to other work. This task will use SysTick, which is fired every 1 ms, to count up a waiting counter, if the counter reaches 50 ticks, task quits the waiting loop and runs other code.

Non-blocking delay

Using SysTick as a counter, a task can be moved to the BLOCKED state and it can not run until the waiting period is over. See a simple implementation of non-blocking delay in the example A simple implementation of a Task Scheduler.

Memory Allocation#

Real time operating system supports static and dynamic memory allocation, with different strategies and algorithm.

Creating RTOS objects dynamically has the benefit of greater simplicity, and the potential to minimize the application’s maximum RAM usage:

  • The memory allocation occurs automatically.
  • The RAM used by an RTOS object can be re-used if the object is deleted.
  • The memory allocation scheme used can be chosen to the best suite the application.

Creating RTOS objects using statically allocated RAM has the benefit of providing the application more control:

  • RTOS objects can be placed at specific memory locations.
  • It allows the RTOS to be used in applications that simply don’t allow any dynamic memory allocation.
  • Avoid memory-related issues such as leak memory, dangling pointer, and undefined objects.

Memory layout in FreeRTOS

Shared Memory#

Tasks are usually a work to do in a loop, and it thinks it can control all resource. In a system, there are many tasks run together, and in many cases, they work with condition from others.

Inter-task communication is defined as some type:

  • Signal: tell other task to start doing something, to synchronize tasks
  • Message Queue/Mailbox: send data between tasks
  • Mutex/Semaphore: synchronize access to a shared resource, lock resource which is in-use

Queue between tasks

Signal between tasks

Shared resource between tasks


FreeRTOS is a market-leading real-time operating system (RTOS) for microcontrollers and small microprocessors. Distributed freely under the MIT open source license, FreeRTOS includes a kernel and a growing set of IoT libraries suitable for use across all industry sectors. FreeRTOS is built with an emphasis on reliability and ease of use.

  • FreeRTOS provides methods for multiple threads or tasks, mutexes, semaphores and software timers.
  • Thread priorities are supported.
  • FreeRTOS applications can be statically allocated, but objects can also be dynamically allocated with five schemes of memory management (allocation).
  • A tickless mode is provided for low power applications.


The Safety functionality is not guaranteed in FreeRTOS as it is not the main focus of the free version. FreeRTOS is designed to be small and simple.


FreeRTOS is designed to be run on many MCUs, therefore, it defines interfaces which will be implemented on a target MCU platform. For ARM cores, CMSIS also has a porting layer for FreeRTOS.

Download the source code of RTOS from FreeRTOS.

FreeRTOS and LTS support

  • A normal release of FreeRTOS includes Kernel, Libraries, and examples,
  • A LTS version only contains the Kernel and IoT libraries.
Library Git repo (including zip download)
FreeRTOS Kernel (RTOS kernel)
FreeRTOS+TCP (TCP/IP stack)
coreMQTT-Agent (multi-threaded MQTT client) (includes coreMQTT)
coreMQTT (base MQTT client)
coreHTTP (HTTP client)
corePKCS11 (software mock of PKCS#11)
AWS IoT Device Shadow
AWS IoT Jobs
AWS IoT Device Defender

Main features#

  • Preemptive or cooperative real-time kernel
  • Tiny memory footprint (less than 10 KB ROM) and easy scalable
  • Includes a tickless mode for low power applications
  • Synchronization and inter-task communication using
    • message queues
    • binary and counting semaphores
    • mutexes
    • group events (flags)
    • stream buffer
  • Hardware timer or Software timer for tasks scheduling
  • Execution trace functionality

Used resources#

Core resources:

  • Hardware System Timer (SysTick) — generate system time (time slice)
  • Two stack pointers: MSP for main RTOS and ISR, PSP for Tasks

Interrupt vectors:

  • SVC — Supervisor call to access privileged resources (like SWI in ARM7)
  • PendSV — Pendable System Call for context switching
  • SysTick — Hardware system timer for scheduling


  • Flash: 6-10 KB Flash +
  • RAM memory: 0.5 KB + task stacks

Main source files#

File Description
task.c ask functions and utilities definition
list.c List implementation used by the scheduler
queue.c Queue implementation used by tasks
timers.c Software timers functions definition
port.c Low level functions supporting SysTick timer, context switch, interrupt management on low HW level — strongly depends on the platform (core and SW tool set). Mostly written in assembly
FreeRTOS.h Configuration file which collect whole FreeRTOS sources
heap_x.c Different implementation of dynamic memory management
coroutine.c Co-routines functions definitions. Efficient in 8 and 16bit architecture. In 32bit architecture usage of tasks is suggested
event_groups.c Flags to notify tasks about am event

Memory Management#

FreeRTOS uses a region of memory called Heap (into the RAM) to allocate memory for tasks, queues, timers, semaphores, mutexes and when dynamically creating variables. FreeRTOS heap is different from the system heap defined at the compiler level.

When FreeRTOS requires RAM, instead of calling the standard malloc(), it calls PvPortMalloc(). When it needs to free memory it calls PvPortFree() instead of the standard free().

FreeRTOS offers several heap management schemes that range in complexity and features. The FreeRTOS download includes five sample memory allocation implementations, each of which are described in the following subsections. The subsections also include information on when each of the provided implementations might be the most appropriate to select.

Heap management schemes:

  • heap_1 — the very simplest, does not permit memory to be freed.
  • heap_2 — permits memory to be freed, but does not coalescence adjacent free blocks.
  • heap_3 — simply wraps the standard malloc() and free() for thread safety.
  • heap_4 — coalescence adjacent free blocks to avoid fragmentation. Includes absolute address placement option.
  • heap_5 — as per heap_4, with the ability to span the heap across multiple non-adjacent memory areas.


  • heap_1 is less useful since FreeRTOS added support for static allocation.
  • heap_2 is now considered as the legacy method because the newer heap_4 implementation is preferred.

For more detail, refer to RTOS Memory Management.

Overridden Interrupts#

PendSV interrupt

  • Used for task switching before tick rate
  • Lowest NVIC interrupt priority
  • Not triggered by any peripheral

SVC interrupt

  • Interrupt risen by SVC instruction
  • SVC 0 call used only once, to start the scheduler (within vPortStartFirstTask() which is used to start the kernel)

SysTick timer

  • Lowest NVIC interrupt priority
  • Used for task switching on configTICK_RATE_HZ regular time base
  • Set PendSV if context switch is necessary

API conventions#

  1. Prefixes at variable names:

    • c — char / s — short / l — long / u — unsigned
    • xportBASE_TYPE defined in portmacro.h for each platform (in STM32 it is long)
    • p — pointer
  2. Functions name structure: prefix+filename+function name.
    For example: vTaskPrioritySet().

  3. Prefixes at macros defines their definition location and names.
    For example: portMAX_DELAY