Arduino library 路 Core

Arduino_FreeRTOS: tasks, queues and semaphores on an AVR

Arduino_FreeRTOS, by Phillip Stevens, is FreeRTOS ported to the AVR boards: the Uno, Nano, Mega and Leonardo. Instead of one loop() that does everything in turn, you write each job as its own task, a function with an endless loop inside and a stack of its own, and the scheduler switches between them. A task that blinks an LED with vTaskDelay() and one that reads a sensor can be written as if each had the board to itself.

Built in on Mokxi: #include <Arduino_FreeRTOS.h> and it builds, with nothing to install. Free, and no account needed.

What FreeRTOS (Arduino_FreeRTOS) does

Tasks hand data to each other through queues (xQueueSend and xQueueReceive) and share things like Serial safely through a mutex (xSemaphoreTake and xSemaphoreGive). loop() becomes the idle task, running only when no task is ready. On these boards the tick is about 15 ms, so vTaskDelay(1) is one tick, not one millisecond; pdMS_TO_TICKS() converts.

RAM is the real limit. Every task needs its own stack from the 2 KB an Uno has, so three or four small tasks is a realistic count, and a task that prints with Serial needs more stack than one that toggles a pin. On ESP32 boards FreeRTOS is already built into the core and these calls work without this library.

Library Manager nameFreeRTOS (Arduino_FreeRTOS)
AuthorPhillip Stevens
Include#include <Arduino_FreeRTOS.h>
#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
BoardsArduino Uno, Arduino Nano, Arduino Mega 2560, Arduino Leonardo, SparkFun Pro Micro, Arduino Micro, Arduino Pro Mini 3.3 V
In the simulatorRuns, with a gap the note below names.
Parts it drivesPotentiometer

Install it

It builds on Arduino Uno, Arduino Nano, Arduino Mega 2560, Arduino Leonardo, SparkFun Pro Micro, Arduino Micro, Arduino Pro Mini 3.3 V.

In Mokxi it is built in: #include <Arduino_FreeRTOS.h> and the sketch compiles, with no download, no zip and no Library Manager.

On a real board, install "FreeRTOS (Arduino_FreeRTOS)" by Phillip Stevens from the Arduino IDE鈥檚 Library Manager (Sketch, Include Library, Manage Libraries), or add FreeRTOS (Arduino_FreeRTOS) to lib_deps in PlatformIO. Mokxi follows the calls of release 11.1.0, so a sketch written here builds there too.

What to know in the simulator: The tasks take turns when one delays, waits or yields; there is no tick interrupt, so a task that never does any of those keeps the others from running. A tick is the library鈥檚 16 ms. Software timers and event groups are not here.

Arduino Uno 路 Arduino Nano 路 Arduino Mega 2560 路 Arduino Leonardo 路 SparkFun Pro Micro 路 Arduino Micro 路 Arduino Pro Mini 3.3 V

The calls you will use

In the order a sketch meets them.

xTaskCreate(TaskBlink, "Blink", 128, NULL, 2, NULL)

Creates a task: its function, a name, the stack depth, a parameter, the priority and an optional handle. Returns pdPASS when there was room for it.

void TaskBlink(void *pv) {
  pinMode(13, OUTPUT);
  for (;;) { digitalWrite(13, !digitalRead(13)); vTaskDelay(pdMS_TO_TICKS(500)); }
}

vTaskDelay(pdMS_TO_TICKS(500))

Puts the task to sleep for that long and lets the others run. Every task loop should block like this somewhere.

QueueHandle_t q = xQueueCreate(5, sizeof(int))

A queue holding up to five ints, for passing readings from one task to another.

xQueueSend(q, &value, portMAX_DELAY)

Puts a copy of value on the queue, waiting if it is full.

xQueueReceive(q, &value, portMAX_DELAY)

Waits for the next item and copies it into value. Returns pdTRUE when it got one.

SemaphoreHandle_t m = xSemaphoreCreateMutex()

A mutex for something only one task should use at a time, like Serial.

xSemaphoreTake(m, portMAX_DELAY)

Waits to own the mutex. Release it with xSemaphoreGive(m) when done.

uxTaskGetStackHighWaterMark(NULL)

How much of the calling task鈥檚 stack has never been used, the number to watch while tuning stack sizes.

Example: Two tasks, one passing readings to the other

On the Arduino Uno R3. It runs in the browser exactly as printed.

sketch.ino 路 Arduino Uno R3
#include <Arduino_FreeRTOS.h>
#include <queue.h>

QueueHandle_t readings;

void TaskRead(void *pvParameters);
void TaskPrint(void *pvParameters);

void setup() {
  Serial.begin(9600);
  readings = xQueueCreate(4, sizeof(int));
  xTaskCreate(TaskRead, "Read", 128, NULL, 1, NULL);
  xTaskCreate(TaskPrint, "Print", 128, NULL, 2, NULL);
}

void loop() {
  // loop() is the idle task, at priority 0.
}

void TaskRead(void *pvParameters) {
  (void) pvParameters;
  for (;;) {
    int value = analogRead(A0);
    xQueueSend(readings, &value, portMAX_DELAY);
    vTaskDelay(500 / portTICK_PERIOD_MS);
  }
}

void TaskPrint(void *pvParameters) {
  (void) pvParameters;
  for (;;) {
    int value;
    if (xQueueReceive(readings, &value, portMAX_DELAY) == pdPASS) {
      Serial.print("A0 = ");
      Serial.println(value);
    }
  }
}

Wiring

  • Arduino Uno R3 5V to Potentiometer 1
  • Arduino Uno R3 GND to Potentiometer 3
  • Arduino Uno R3 A0 to Potentiometer 2

Open it in the editor, wired and ready to run

Common errors and how to fix them

The board resets or behaves randomly after adding a task

A task overflowed its stack or the heap ran out. Give tasks that print or use floats a bigger stack, check xTaskCreate() returns pdPASS, and use fewer tasks on an Uno, whose 2 KB of RAM fills fast.

One task runs and the others never do

That task never blocks: it loops without vTaskDelay(), a queue wait or a semaphore wait. Every task loop needs a call that gives the processor up, or lower its priority below the others.

vTaskDelay(1000) waits about 15 seconds, not one

vTaskDelay() counts ticks, and on the AVR port a tick is about 15 ms. Write vTaskDelay(pdMS_TO_TICKS(1000)) or divide by portTICK_PERIOD_MS to wait in milliseconds.

Lines from two tasks come out mixed on the Serial Monitor

Both tasks print at once. Guard every Serial print with a mutex: xSemaphoreTake() before printing and xSemaphoreGive() after.

Try FreeRTOS (Arduino_FreeRTOS) without installing anything

Open the example, change the sketch, and keep your version in a free account.