FreeRTOS is a cross-platform, real-time operating system that has been ported to several architectures. It has a simple but powerful API to deal with tasks, scheduler, queues, semaphores and timers. Learning it is an enriching experience and a knowledge that can be reused widely due to its portability. Its source code is available under the MIT license and allows commercial use without having to pay royalties.
The code snippet below demonstrates how a task can be created. Task creation may fail if there is not enough heap space available to allocate task structures and stack.
// a task
static void run(void *pvParameters)
// do something useful, then block
// create task
p = xTaskCreate(run,
(const signed portCHAR *)"task",
if ( p != pdPASS )
// handle error
FreeRTOS divides processor time equally among tasks with the same priority. Tasks with higher priority always preempt lower priority tasks, no other lower priority task will run until the higher priority task blocks. Tasks can block on calls such as
To delete a task when done
// delete task
FreeRTOS has three different memory allocation implementations, available in separate code files called
heap_1.c, heap_2.c, and
heap_3.c. You have to choose one of the three. If you choose
heap_3.c, the C compiler’s implementation of
free are used, the heap space is determined based on the linker configuration. If interested in AVR32, see Using the GNU Linker Scripts on AVR UC3 Devices.
A task needs to perform activities. Most tasks are implemented as endless loops that wake up on some event, perform some activity and go back to waiting. An advantage of using queues is that they are multitask safe and thus an effective synchronization mechanism between tasks. You can use them to queue activities that a task must perform, serializing their execution. This is useful if multiple tasks must have access to a shared resource controlled by a single task.
The code snippet below demonstrates how to create a queue
xQueueHandle queue = 0;
queue = xQueueCreate(10, sizeof(unsigned int));
To queue a message (from any task)
unsigned int id = 0;
xQueueSend(xQueueIO, (void *)&id, (portTickType)0);
To retrieve a message from the queue and process it (usually in a dedicated task)
p = xQueueReceive(queue, &id, (portTickType)0);
if (p == pdPASS)
To delete the queue when done
Timers are a useful mechanism to stop long running activities and to start activities at periodic intervals.
The code snippet below demonstrates how to use the tick counter maintained by FreeRTOS to implement timers. The portTICK_RATE_MS macro is used to convert milliseconds to ticks. If the port of FreeRTOS for your board is not configured properly the value of portTICK_RATE_MS may not be correct.
The following code sets up some declarations and variables required later
static portTickType tickUntil;
static portTickType startTick;
// assign tick count when timer elapses i.e. after 1000 ms
startTick = xTaskGetTickCount();
tickUntil = startTick + (portTickType)(1000 / portTICK_RATE_MS);
In the task function, you’ll have code similar to
currentTick = xTaskGetTickCount();
if (tickUntil > startTick
&& (currentTick > tickUntil
|| (currentTick < startTick
&& currentTick < tickUntil))) // no overflow of tickUntil
// timer elapsed, do something
else if (currentTick < startTick && currentTick > tickUntil) // overflow of tickUntil
// timer elapsed, do something
In the ticklines below, when tick count enters the red region after
tickUntil, we consider the timer to have elapsed. The second tickline is for the case when