Using Arduino FreeRTOS


Install FreeRTOS for Arduino UNO, Adafruit Feather M4 Express or Adafruit QT-PY:

FreeRTOS library can also be installed directly through the Arduino Library Manager. To do so open the Arduino IDE and go to Sketch|Include Library|Manage libraries. Type “FreeRTOS" in the search window, choose the Phillip Stevens FreeRTOS library for Arduino UNO, FreeRTOS_SAMD51 for the Adafruit Feather M4 Express or FreeRTOS_SAMD21 for the Adafruit QT-PY, then click the Install button. Restart the Arduino IDE. You'll need to ensure the board drivers are already installed. Here is an example using the Adafruit Feather M4 Express.


Load the sketch FreeRTOS_NeoMatrix_8x1_04.ino (Sketch is saved as .zip to hopefully prevent Windows and your antivirus software from complaining.)


Where can I run this Arduino code?

How about on this add-on board that can be attached to this RGB LED device (this page contains both the LED and RGB LED boards - you'll want the lower one that is RGB LED). You'll need two of the 3x3 RGB LED array boards. You'll also need some sort of sound device or board like this one.


Sketch overview:

In this sketch example, a string of 8 RGB neopixel LEDs is illuminated from Left to Right then R to L while a tune is played in the background for each illumination direction.

At any time a push button can be toggled to turn on or off a separate blue LED. In the meantime the neopixel LEDs continue to illuminate and the tune continues to play.

(Note that tone() can malfunction and either not work or stop the other tasks from running. Making use of Suspend and Resume will make it behave more to your liking. If you wish to also run it as part of the blue LED routine, you'll need to setup a mutex and semaphore so the resource can be shared.)

If you have difficulties, write your code in stages on an Arduino UNO to get it right then port it over to an Adafruit Feather M4 Express later. (Don't forget that UNO uses 5v whereas everything uses 3v3.)


Within the program sketch we see the following detailed by line number:

1 to 60: Defines, constants and global variables are at the top of your sketch.

12 to 14:  Load the Arduino-tuned FreeRTOS library on UNO or Feather or QT-PY.

15:  Load semaphore support for shared tasks. We won't be using it in this program sketch.

17 to 30: Define your task(s) with task handle and no parameters. The handle will be used to suspend and resume the task(s).

32 to 41: Define the neopixel LED colours.

43 to 45: Include the Adafruit neopixel libraries for graphics, neopixel strands and neopixel matrices.

46 to 49: Pin assignments. Comments include pin assignments for Adafruit QT-PY if you wish to use it instead of Feather M4 Express.

50: Declare the total number of neopixel LEDs in the strands and matrices.

51 to 53: Logic states for the pushbutton switch function.

54 to 58: Neopixel matrix parameters of width by length, microcontroller pin, location of first pixel in matrix, matrix stack of rows or columns, progressive or zigzag layout, types of LEDS (GRB, RGB or RGBW), and protocol speed through the IN and OUT pins.

59: An array for the neopixel colours is created. aC[8] is black - the LED will be extinguished.

60: Initialize global counters.


The setup() portion of your code:

This is where your code starts to run. It used to be in loop() but it's now in setup().

64 to 70: All the usual pin and device assignments occur in setup(). loop() is present but is unused by FreeRTOS.

71 to 76: Perform your xTaskCreate() definitions in setup() but create your actual tasks below setup(). Parameters for various FreeRTOS directives including xTaskCreate() are listed in the table below. In the sketch code, the priority of each task is set to the lowest value of 1 and RAM is also set to a low value of 128 (128 x 4 = 512 bytes) to keep Arduino UNO (2KB limit) happy.

78: Start the scheduler. Without it, none of your tasks can run.


Define your task(s):

Unless you want to run your task indefinitely regardless of whatever else is running, you may wish to temporarily end each task with a vTaskSuspend () sent to the task's handle. You can then add a vTaskResume() for the same file handle when you expect that function to run at the same time as another. An example follows:

81 to 107: In the upper half (81 to 92) of the marchLR() function, LEDs are displayed in series from left to right. Each time the next one is illuminated, the preceding one is extinguished. The effect is that the LEDs are marching from left to right, hence the function name. In the lower half (94 to 105) of the function, LEDs are displayed in series again but from right to left. As you can see from the commented out line 95, this was originally the marchRL() function.

109 to 118: In the beepUP() function, a tone is increased by 100Hz until an audible limit for that particular buzzer/speaker is reached. When the task completes, the vTaskSuspend() operation in line 116 temporarily stops it from running. Within the marchLR() function the vTaskResume() operation restarts it to align with the start of the LEDs marching from left to right.

120 to 129: This is the beepDOWN() function that uses an audibly decreasing tone. It is paired with the lower half of marchLR(), that is, the marchRL() code.


Once you start, you should stop right away:

You may have noticed in line 72 that as soon as we create the task with the handle March LtoR, we suspend it with vTaskSuspend(beepUP_handle). The same is true in line 73 with the beepDOWN() task. If we didn't do this the sound routines would start right away and would not be initially sync'd:  beepUP() for marchLR() and beepDOWN() for marchRL(). By suspending the tasks immediately they will be started with the first vTaskResume(__handle) found at the beginning of marchLR() and at the beginning of marchRL().


And now for the push button switch:

In summary when the LEDs march from left to right the tone increases in pitch and when the LEDs march from right to left the tone decreases in pitch.

131 to 150:  When a push button switch is pressed and released, a blue LED illuminates. Pressing and releasing the switch a second time extinguishes the blue LED.

This task is running at the same time as the LED and sound tasks. If you ever experience a missed press, try increasing the task's priority so it is higher than the others. I didn't have that issue but just in case...



According to the xTaskCreate() section of our code, all tasks will run simultaneously with the marchLR() LEDs task starting first. Using suspend and resume for the sound component as we have in this example gives us a little control as to what will run and when.


The table below lists a number of FreeRTOS directives you'll find yourself using. More information can be found at FreeRTOS.org.




How FreeRTOS works

Video1: FreeRTOS and ESP32 video

Video2: FreeRTOS and ESP32 series of videos

Video3: FreeRTOS Deep Dive series of videos

These are good videos about multitasking as well as seeing FreeRTOS run. In the first two video series, this version of FreeRTOS is designed to run in the Arduino IDE (Integrated Development Environment) but not on Arduino gear; it runs on an Espressif ESP32 microcontroller (uC). (Arduino has been ported to Atmel/Microchip, Espressif, RP2040 and other microcontrollers.)

The ESP32 contains 2 CPU cores in the uC: Core0 is dedicated to the WiFi interface and Core1 is for the user's code. Running two cores at the same time could only be accomplished with a real time operating system which is why it is built into ESP32 by design.

If you insist on using an ESP32 board instead of Arduino or Adafruit Microchip boards, board selection info can be found here and here. Installation instructions can be found here.  Information on Arduino-ESP32 can be found here and Github library files can be found here.

Creating tasks xTaskCreate(task1,"Task 1", 256,NULL,1,NULL);

Inside setup() we create the xTasks. Six parameters required:

- function name: example task1

- task name: example "Task 1" is for human consumption

- stack size in 32-bit words (ESP32 uses bytes): example 128 x 4 = 512. Important with Arduino UNO's limited RAM

- task parameters from the task suffix(): example would be whatever you normally pass in the task suffix parentheses ()

- priority: example 1 (1 is low)

- task handle: example NULL or &task1_handle. NULL is used for the local task otherwise we would have to use the task_handle.

Task handle

TaskHandle_t  task1_handle = NULL;

Create this command in global parameters section, above Setup(). Initialized to NULL in the example.


Within the xTaskCreate function, replace the 6th parameter (task handle) with this one so the command will become:

xTaskCreate(task1,"Task 1", 256,NULL,1,&task1_handle);


The task handle allows the task to be controlled within the task or outside the task, even within another task.

Example: turn off a lit LED while turning on another LED.

Start the Scheduler vTaskStartScheduler(); After creating a task(s), start the Scheduler in a void Setup. It will coordinate the multitasking between all of the xTaskCreate objects.
Delays vTaskDelay(1000 / portTICK_PERIOD_MS);

This directive is non-blocking and replaces delay(): other tasks can run during this delay time.

Stopping a task



vTaskDelete(task_handle or NULL);

vTaskDelete(NULL) will stop the current task.


You need to use a task handle to stop the task outside of the current task.

Suspend or Resume Tasks





vTaskSuspend(NULL); suspends the current task within the task.


vTaskSuspend(task1_handle); You can suspend a task outside of the task, typically within loop().

Example: if(count1 > 3 && task1_handle != NULL) {   // This protects the original task.

                   vTaskSuspend(task1_handle);               }

                if(count2 == 5 && task1_handle != NULL) {

                   vTaskResume(task1_handle);                  }

Suspend All Tasks vTaskSuspendAll();


Usually used to ensure a mission critical task will run immediately.

xTaskResumeAll(); is usually run after the mission critical task has completed. Ensure both of these commands are within the function or comparison area.



Updated 2022-05-18 @ 8am