Introduction To Freertos: What Is An Rtos?
Introduction To Freertos: What Is An Rtos?
Introduction To Freertos: What Is An Rtos?
What is an RTOS?
Operating systems you’re used to deal with (e.g. Linux, Windows) allow multiple programs to execute at
the same time. This is called multi-tasking. In reality, each processor core can only be running a single
thread of execution at any given point in time. A part of the operating system called the scheduler is
responsible for deciding which program to run when, and provides the illusion of simultaneous
execution by rapidly switching between each program.
The type of an operating system is defined by how the scheduler decides which program to run when.
For example, the scheduler used in a multi user operating system (such as Unix) will ensure each user
gets a fair amount of the processing time. As another example, the scheduler in a desktop operating
system (such as Windows) will try and ensure the computer remains responsive to its user.
The scheduler in a Real Time Operating System (RTOS) is designed to provide a predictable (normally
described as deterministic) execution pattern. This is particularly of interest to embedded systems as
embedded systems often have real time requirements. A real time requirement is one that specifies that
the embedded system must respond to a certain event within a strictly defined time (the deadline). A
guarantee to meet real time requirements can only be made if the behavior of the operating system's
scheduler can be predicted (and is therefore deterministic).
In summary, RTOS typically does not have the more advanced features that are typically found in other
operating systems like Linux and Windows. The emphasis is on compactness and speed of execution.
Abstracting away timing information as the kernel is responsible for execution timing and
provides a time-related API to the application.
Maintainability/extensibility since tasks or modules have few interdependencies.
Modularity since tasks are independent.
Easier testing
Characteristics of a ‘Task’
A real time application that uses an RTOS can be structured as a set of independent tasks. Each task
executes within its own context with no coincidental dependency on other tasks within the system or
the RTOS scheduler itself. Only one task within the application can be executing at any point in time and
the real time RTOS scheduler is responsible for deciding which task this should be. The RTOS scheduler
may therefore repeatedly start and stop each task (swap each task in and out) as the application
executes. As a task has no knowledge of the RTOS scheduler activity it is the responsibility of the real
time RTOS scheduler to ensure that the processor context (register values, stack contents, etc) when a
task is swapped in is exactly that as when the same task was swapped out. To achieve this each task is
provided with its own stack. When the task is swapped out the execution context is saved to the stack of
that task so it can also be exactly restored when the same task is later swapped back in.
What is FreeRTOS?
FreeRTOS is a class of RTOS that is designed to be small enough to run on a microcontroller - although its
use is not limited to microcontroller applications. Traditional real time schedulers, such as the scheduler
used in FreeRTOS, achieve determinism by allowing the user to assign a priority to each thread of
execution. The scheduler then uses the priority to know which thread of execution to run next. In
FreeRTOS, a thread of execution is called a task.
A microcontroller is a small and resource constrained processor that incorporates, on a single chip, the
processor itself, read only memory (ROM or Flash) to hold the program to be executed, and the random
access memory (RAM) needed by the programs it executes. Typically, the program is executed directly
from the read only memory.
Microcontrollers are used in deeply embedded applications (those applications where you never
actually see the processors themselves, or the software they are running) that normally have a very
specific and dedicated job to do. The size constraints, and dedicated end application nature, rarely
warrant the use of a full RTOS implementation - or indeed make the use of a full RTOS implementation
possible. FreeRTOS therefore provides the core real time scheduling functionality, inter-task
communication, timing and synchronization primitives only. This means it is more accurately described
as a real time kernel, or real time executive. Additional functionality, such as a command console
interface, or networking stacks, can then be included with add-on components.
As of today, FreeRTOS supports more than 35 different architectures, including ARM, AVR, PIC (PIC18,
PIC24, dsPIC and PIC32), x86. The latest release is 10.4.3 (December 14, 2020).
In summary, FreeRTOS is a real-time kernel/scheduler on top of which MZU applications can be built to meet
their hard real-time requirements. As such, it allows MZU applications to be organized as a collection of
independent threads of execution (e.g. tasks).
1. Running
When a task is actually executing, it is said to be in the Running state since it is currently using
the processor. If there is only a single core then there can only be one task in the Running state
at any given time.
2. Ready
Ready tasks are those that are able to execute (they are not in the Blocked or Suspended state)
but are not currently executing because a different task of equal or higher priority is already in
the Running state.
3. Blocked
A task is said to be in the Blocked state if it is currently waiting for either a temporal or external
event. For example, if a task calls vTaskDelay() it will block (be placed into the Blocked state)
until the delay period has expired - a temporal event. Tasks can also block to wait for queue,
semaphore, event group, notification or semaphore event. Tasks in the Blocked state normally
have a 'timeout' period, after which the task will be timeout, and be unblocked, even if the
event the task was waiting for has not occurred.
Tasks in the Blocked state do not use any processing time and cannot be selected to enter the
Running state.
4. Suspended
Like tasks that are in the Blocked state, tasks in the Suspended state cannot be selected to enter
the Running state, but tasks in the Suspended state do not have a time out. Instead, tasks only
enter or exit the Suspended state when explicitly commanded to do so through the
vTaskSuspend() and xTaskResume() API calls respectively.
The difference between the tasks in the blocked state and tasks in the suspended state is that
tasks in the blocked state always have a timeout. Tasks in the suspended state are suspended
indefinitely and there is no timeout.
Entry point
Normally runs forever within an infinite loop
Has its own stack
Does not exit.
vTaskDelete(NULL);
Afterwards, when you click on Sketch -> include library, you will notice that FreeRTOS is showing up in
the menu. In addition, if you go to File -> Examples -> FreeRTOS, you will see a number of example that
tackle FreeRTOS.
In the below example, we will create 3 tasks with the following specifications:
1. LED blinks at digital pin 8 with 200ms frequency
2. LED blinks at digital pin 7 with 300ms frequency
3. Print numbers is serial monitor with 500ms frequency.
#include <Arduino_FreeRTOS.h>
Serial.begin(9600);
vTaskStartScheduler();
void loop()
{
}
while(1)
{
Serial.println("Task1");
digitalWrite(8, HIGH);
while(1)
{
Serial.println("Task2");
digitalWrite(7, HIGH);
while(1)
{
counter++;
Serial.println(counter);
vTaskDelay(500 / portTICK_PERIOD_MS);
}
}
Notes:
1. Note that the loop function remains empty as we don’t want manually and infinitely. The task
execution is now handled by the scheduler.
2. The function delay must not be used as it stops the CPU and the FreeRTOS will stop working as well.
Instead, we should use the vTaskDelay function:
vTaskDelay( const TickType_t xTicksDelay );
This API delays a task for a given number of ticks. The actual time for which the task remains blocked
depends on the tick rate. The constant portTICK_PERIOD_MS can be used to calculate real time
from the tick rate.
3. For more details on the above example, visit the following link:
https://circuitdigest.com/microcontroller-projects/arduino-freertos-tutorial1-creating-freertos-task-to-
blink-led-in-arduino-uno
Queues
Binary Semaphores
Counting Semaphores
Mutexes
Recursive mutexes
The objective of this post is to explain how to use FreeRTOS queues to achieve inter task
communication, using the Arduino core. Besides communication amongst tasks, queues also allow
communication between tasks and interrupt service routines.
Generically, queues can be used for a task to produce items and another to consume them, working as a
FIFO (first in first out). This is what we are going to do in this example, where a task will put some
integers in the queue and another will consume them. Although we are going to use integers, FreeRTOS
queues allow for using more complex data structures, such as structs.
Other important behavior to consider is performing blocking API calls. Both trying to write on a full
queue or read from an empty one will cause the task to block until the operation can be executed or a
pre-defined amount of time expires [1]. If more than one task blocks on a queue, the highest priority
task will be the one to unblock first when the operation can be completed.
#include <Arduino_FreeRTOS.h>
#include “queue.h”
QueueHandle_t queue;
int queueSize = 10;
void setup() {
Serial.begin(112500);
queue = xQueueCreate( queueSize, sizeof( int ) );
if (queue == NULL)
{
Serial.println("Error creating the queue");
}
void loop() {
delay(100000);
}
vTaskDelete( NULL );
}
vTaskDelete( NULL );
}
For more details on the above example, visit the following link:
https://techtutorialsx.com/2017/09/13/esp32-arduino-communication-between-
tasks-using-freertos-queues/
In the below example, we’ll use FreeRTOS semaphores to protect the serial
port so that 2 tasks can share the same hardware resource.
#include <Arduino_FreeRTOS.h>
#include <semphr.h> // add the FreeRTOS functions for Semaphores (or
Flags).
// the setup function runs once when you press reset or power the board
void setup()
{
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
if ( xSerialSemaphore == NULL )
{
// Create a mutex semaphore we will use to manage the Serial Port
xSerialSemaphore = xSemaphoreCreateMutex();
if ( ( xSerialSemaphore ) != NULL )
xTaskCreate(
TaskAnalogRead,
(const portCHAR *) "AnalogRead",
128, // Stack size
NULL,
1,
NULL );
void loop()
{
// Empty. Things are done in Tasks.
}
/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/
For more details on the above example, visit the following link:
https://create.arduino.cc/projecthub/feilipu/using-freertos-semaphores-in-arduino-ide-b3cd6c
The counting semaphores can be used to either count events or manage resources. In the below
example, we’ll create 2 tasks named Task 1 and Task 2 successively. Both tasks will use the same UART
module of Arduino to write data on the serial monitor. If we consider the Arduino serial monitor and
UART communication module as a resource that will be utilized by both tasks, then, we can use counting
semaphore for this resource management for Task1 and Task2. Because only one task can hold these
Arduino resources at a time.
#include <Arduino_FreeRTOS.h>
#include <semphr.h>
SemaphoreHandle_t xCountingSemaphore;
void setup()
{
Serial.begin(9600); // Enable serial communication library.
pinMode(LED_BUILTIN, OUTPUT);
xCountingSemaphore = xSemaphoreCreateCounting(1,1);
xSemaphoreGive(xCountingSemaphore);
}
void loop() {}
for (;;)
{
xSemaphoreTake(xCountingSemaphore, portMAX_DELAY);
Serial.println("Inside Task1 and Serial monitor Resource Taken");
digitalWrite(LED_BUILTIN, HIGH); xSemaphoreGive(xCountingSemaphore);
vTaskDelay(1);
}
}
for (;;)
{
xSemaphoreTake(xCountingSemaphore, portMAX_DELAY);
Serial.println("Inside Task2 and Serial monitor Resource Taken");
digitalWrite(LED_BUILTIN, LOW);
xSemaphoreGive(xCountingSemaphore); vTaskDelay(1);
}
}
For more details on the above example, visit the following link:
https://microcontrollerslab.com/freertos-counting-semaphore-examples-arduino/