Zbotic Logo Zbotic Logo
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

  • Shop
  • About Us
  • Contact Us
  • Reseller
  • Blogs
020 69134444
1800 209 0998
[email protected]
Help Desk
Facebook Twitter Instagram Linkedin YouTube
Zbotic Logo Zbotic Logo
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

All departments
  • 3D Print Service
  • 3D Printer
  • Batteries & Chargers
  • Development Boards
  • Drone Parts
  • EBike parts
  • Sensor Modules
  • Electronic Components
  • Electronic Modules
  • IoT and Wireless
  • Mechanical Parts and Workbench Tools
  • Motors & Drivers & Pumps & Actuators
  • DIY and Robot Kits
  • Show more
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
Return to previous page
Home Arduino & Microcontrollers

FreeRTOS on Arduino: Multitasking for Embedded Projects

FreeRTOS on Arduino: Multitasking for Embedded Projects

March 11, 2026 /Posted byJayesh Jain / 0

One of the most common frustrations in Arduino development is managing multiple tasks simultaneously — reading a sensor every second, updating a display, checking button presses, and communicating over serial, all at the same time without using delay() or complex state machines. FreeRTOS on Arduino solves this cleanly by bringing real-time operating system multitasking to your microcontroller projects. This tutorial explains what FreeRTOS is, why it matters, and gives you working code examples to add proper task scheduling to your Arduino projects today.

Table of Contents

  • What Is FreeRTOS?
  • Why Multitasking Matters in Embedded Systems
  • Installing FreeRTOS for Arduino
  • FreeRTOS Tasks: Creating and Managing Them
  • Semaphores and Queues: Safe Data Sharing
  • Practical Example: Sensor Reading + Display Update
  • Memory Considerations and Stack Overflow
  • Frequently Asked Questions

What Is FreeRTOS?

FreeRTOS is a real-time operating system kernel designed specifically for microcontrollers. “Real-time” here means the OS can guarantee that certain tasks will execute within defined time constraints — critical in embedded systems where missing a timing deadline can have real consequences (think motor control, safety systems, or communication protocols).

FreeRTOS is not a full operating system like Linux or Windows. It’s a very lightweight kernel (typically under 10KB of flash) that provides:

  • Task Scheduling: Multiple tasks appear to run simultaneously via preemptive multitasking
  • Task Prioritization: Higher-priority tasks preempt lower-priority ones
  • Inter-Task Communication: Queues, semaphores, mutexes, and event groups for safe data sharing between tasks
  • Timers: Software timers that execute callbacks at precise intervals
  • Memory Management: Multiple heap allocation schemes suited to resource-constrained environments

Amazon acquired FreeRTOS in 2017 and it’s now known as Amazon FreeRTOS (or FreeRTOS with AWS IoT integration). The core kernel remains open source under the MIT license. It’s used in hundreds of millions of devices worldwide, from consumer electronics to aerospace systems.

Recommended: Arduino Mega 2560 R3 Board — FreeRTOS on the Mega gives you more RAM (8KB vs 2KB on Uno) for task stacks, making it much easier to run 4-6 tasks simultaneously. Ideal for learning FreeRTOS with headroom for real projects.

Why Multitasking Matters in Embedded Systems

The standard Arduino programming model — a single loop() function that runs forever — is called a superloop architecture. It works for simple projects, but fails when your project has multiple concurrent requirements.

Consider a typical project: you need to read a temperature sensor every 500ms, check a button for presses, update a display every 100ms, and send data over serial when available. In a superloop, you achieve this with millis()-based timing:

void loop() {
  unsigned long now = millis();
  
  if (now - lastSensorRead > 500) {
    readSensor();
    lastSensorRead = now;
  }
  
  if (now - lastDisplay > 100) {
    updateDisplay();
    lastDisplay = now;
  }
  
  checkButton();
  checkSerial();
}

This works, but it has problems: if readSensor() takes 200ms to complete, your display update is late. If updateDisplay() blocks momentarily, you might miss a button press. Functions must be non-blocking, and timing becomes increasingly fragile as you add more tasks.

FreeRTOS solves this by giving each task its own execution context. The sensor task can block itself waiting for 500ms and the scheduler will run other tasks in the meantime. Each task is independent, has its own stack, and is scheduled based on its priority.

Installing FreeRTOS for Arduino

There are two main FreeRTOS libraries for Arduino:

1. Arduino_FreeRTOS (recommended for AVR)
For Arduino Uno, Mega, Leonardo, and other AVR-based boards, use the Arduino_FreeRTOS library by Richard Barry (maintained by feilipu).

  1. Open Arduino IDE → Sketch → Include Library → Manage Libraries
  2. Search for “FreeRTOS” — select the one by “feilipu” (not the Amazon one)
  3. Install it. It works immediately with Uno, Mega, and Leonardo

2. For ESP32
FreeRTOS is built into the ESP-IDF and the Arduino-ESP32 framework. No additional library is needed — FreeRTOS APIs are available directly in any ESP32 Arduino sketch.

3. For STM32 and ARM-based Arduinos
Use the CMSIS-RTOS wrappers or the STM32FreeRTOS library, depending on your board.

This tutorial focuses on the Arduino_FreeRTOS library for AVR (Uno/Mega).

Recommended: Arduino Nano 33 IoT with Header — The Nano 33 IoT uses the SAMD21 ARM Cortex-M0+ processor which has robust FreeRTOS support. It also has built-in Wi-Fi and Bluetooth, making it perfect for multi-task IoT projects where wireless communication runs as a background task.

FreeRTOS Tasks: Creating and Managing Them

A FreeRTOS task is essentially a function that runs in an infinite loop, managed by the RTOS scheduler. Here’s the minimal structure:

#include <Arduino_FreeRTOS.h>

// Task function prototype
void TaskBlink(void *pvParameters);
void TaskSerial(void *pvParameters);

void setup() {
  Serial.begin(9600);
  
  // Create tasks
  // Syntax: xTaskCreate(function, name, stack, params, priority, handle)
  xTaskCreate(
    TaskBlink,    // Task function
    "Blink",      // Task name (for debugging)
    128,          // Stack size in words (not bytes)
    NULL,         // Parameters passed to task
    1,            // Priority (1 = low, higher = more priority)
    NULL          // Task handle (for later control)
  );
  
  xTaskCreate(
    TaskSerial,
    "Serial",
    128,
    NULL,
    1,
    NULL
  );
  
  // Start the scheduler (never returns)
  vTaskStartScheduler();
}

void loop() {
  // With FreeRTOS, loop() is never used.
  // Tasks replace loop().
}

void TaskBlink(void *pvParameters) {
  (void) pvParameters; // Suppress warning
  
  pinMode(LED_BUILTIN, OUTPUT);
  
  for (;;) { // Tasks must loop forever
    digitalWrite(LED_BUILTIN, HIGH);
    vTaskDelay(500 / portTICK_PERIOD_MS); // Block for 500ms
    digitalWrite(LED_BUILTIN, LOW);
    vTaskDelay(500 / portTICK_PERIOD_MS);
  }
}

void TaskSerial(void *pvParameters) {
  (void) pvParameters;
  
  for (;;) {
    Serial.println("Running FreeRTOS!");
    Serial.print("Free heap: ");
    Serial.println(xPortGetFreeHeapSize());
    vTaskDelay(1000 / portTICK_PERIOD_MS); // Block for 1 second
  }
}

Key points about this code:

  • vTaskDelay() blocks the current task and lets the scheduler run other tasks. This is NOT like delay() — it doesn’t block the entire CPU, just this task
  • portTICK_PERIOD_MS converts milliseconds to FreeRTOS ticks (tick rate is configurable, default is 15ms on AVR)
  • Tasks must never return — they must loop forever using for(;;)
  • Stack size in words (each word = 2 bytes on AVR). 128 words = 256 bytes. Start small and increase if you get stack overflow errors
  • Priority: higher number = higher priority. Equal priority tasks are scheduled round-robin

Semaphores and Queues: Safe Data Sharing

When multiple tasks share data (like a sensor reading accessed by both a “read sensor” task and a “display” task), you need synchronization primitives to prevent race conditions — situations where two tasks try to read/write the same data simultaneously with unpredictable results.

Semaphores (Mutual Exclusion)

#include <Arduino_FreeRTOS.h>
#include <semphr.h>

SemaphoreHandle_t xSemaphore;
float sharedTemperature = 0.0;

void setup() {
  xSemaphore = xSemaphoreCreateMutex();
  // ... create tasks
}

void TaskReadSensor(void *pvParameters) {
  for (;;) {
    float newTemp = readTempSensor(); // Your sensor reading function
    
    if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
      sharedTemperature = newTemp; // Safe to write
      xSemaphoreGive(xSemaphore);
    }
    vTaskDelay(500 / portTICK_PERIOD_MS);
  }
}

void TaskDisplayTemp(void *pvParameters) {
  for (;;) {
    float temp;
    if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
      temp = sharedTemperature; // Safe to read
      xSemaphoreGive(xSemaphore);
    }
    displayValue(temp);
    vTaskDelay(100 / portTICK_PERIOD_MS);
  }
}

Queues (Task Communication)
Queues are the preferred way to pass data between tasks. Unlike shared variables, queues are inherently thread-safe and can buffer multiple values:

QueueHandle_t xSensorQueue;

void setup() {
  // Create queue that holds 5 float values
  xSensorQueue = xQueueCreate(5, sizeof(float));
}

void TaskSensor(void *pvParameters) {
  float reading;
  for (;;) {
    reading = readSensor();
    xQueueSend(xSensorQueue, &reading, portMAX_DELAY);
    vTaskDelay(500 / portTICK_PERIOD_MS);
  }
}

void TaskDisplay(void *pvParameters) {
  float receivedValue;
  for (;;) {
    if (xQueueReceive(xSensorQueue, &receivedValue, portMAX_DELAY)) {
      displayValue(receivedValue);
    }
  }
}

Practical Example: Sensor Reading + Display Update

Here’s a complete real-world example: reading a DHT11 temperature sensor every 2 seconds in one task, and updating an LCD display every 500ms in another task, with a third task handling button input:

#include <Arduino_FreeRTOS.h>
#include <semphr.h>
#include <DHT.h>

#define DHT_PIN 2
#define DHT_TYPE DHT11
#define BUTTON_PIN 7
#define LED_PIN 13

DHT dht(DHT_PIN, DHT_TYPE);
SemaphoreHandle_t xDataMutex;

struct SensorData {
  float temperature;
  float humidity;
};
SensorData gSensorData = {0.0, 0.0};

void TaskReadDHT(void *pvParameters);
void TaskButton(void *pvParameters);
void TaskStatusLED(void *pvParameters);

void setup() {
  Serial.begin(9600);
  dht.begin();
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  
  xDataMutex = xSemaphoreCreateMutex();
  
  xTaskCreate(TaskReadDHT,   "DHT",    256, NULL, 2, NULL);
  xTaskCreate(TaskButton,    "Button", 128, NULL, 3, NULL); // High priority
  xTaskCreate(TaskStatusLED, "LED",    128, NULL, 1, NULL);
  
  vTaskStartScheduler();
}

void loop() {} // Unused with FreeRTOS

void TaskReadDHT(void *pvParameters) {
  for (;;) {
    float t = dht.readTemperature();
    float h = dht.readHumidity();
    
    if (!isnan(t) && !isnan(h)) {
      if (xSemaphoreTake(xDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
        gSensorData.temperature = t;
        gSensorData.humidity = h;
        xSemaphoreGive(xDataMutex);
      }
      Serial.print("T: "); Serial.print(t);
      Serial.print(" H: "); Serial.println(h);
    }
    vTaskDelay(pdMS_TO_TICKS(2000));
  }
}

void TaskButton(void *pvParameters) {
  for (;;) {
    if (digitalRead(BUTTON_PIN) == LOW) {
      Serial.println("Button pressed!");
      vTaskDelay(pdMS_TO_TICKS(200)); // Debounce
    }
    vTaskDelay(pdMS_TO_TICKS(50));
  }
}

void TaskStatusLED(void *pvParameters) {
  for (;;) {
    digitalWrite(LED_PIN, HIGH);
    vTaskDelay(pdMS_TO_TICKS(100));
    digitalWrite(LED_PIN, LOW);
    vTaskDelay(pdMS_TO_TICKS(900));
  }
}
Recommended: DHT11 Temperature And Humidity Sensor Module with LED — This module is perfect for the FreeRTOS sensor example above. It includes the DHT11 sensor with a built-in LED indicator, ideal for multi-task projects where sensor reading and status indication happen in separate tasks.

Memory Considerations and Stack Overflow

The most common FreeRTOS issue on AVR Arduinos is running out of RAM. With only 2KB SRAM on the Uno (8KB on the Mega), memory management is critical.

Stack Size Guidelines:

  • Minimal task (just GPIO, no serial, no floats): 64-128 words
  • Task with Serial.print(): 128-256 words
  • Task with float math and string operations: 256-512 words
  • Task using DHT library or complex sensor libraries: 256-512 words

Detecting Stack Overflow:
Add this to your sketch to monitor free stack space:

// In any task:
Serial.print("Task stack high watermark: ");
Serial.println(uxTaskGetStackHighWaterMark(NULL));

If the watermark reaches 0 or very low values, increase your stack size. If you get a hard reset/crash with no obvious cause, stack overflow is the most likely culprit — increase all task stack sizes until stability returns.

Total Memory Budget:
FreeRTOS itself uses about 1KB of RAM overhead. Each task uses its stack allocation. For an Uno with 2KB total, you can typically run 3-4 simple tasks. On the Mega with 8KB, you can run 8-10 tasks comfortably. The Nano 33 IoT with 32KB SRAM has plenty of headroom for complex multi-task applications.

Recommended: Arduino Nano RP2040 Connect with Header — The RP2040 has dual ARM Cortex-M0+ cores with 264KB SRAM, making it exceptional for FreeRTOS. You can run many tasks with generous stack allocations, and the built-in Wi-Fi/BT adds networking tasks without extra hardware.

Frequently Asked Questions

Does FreeRTOS work on Arduino Uno?

Yes, the Arduino_FreeRTOS library (by feilipu) is specifically designed for AVR-based Arduinos including the Uno, Mega, Leonardo, and Nano. The Uno’s 2KB SRAM is tight — you can run about 3-4 simple tasks. The Mega’s 8KB SRAM is much more comfortable. For serious FreeRTOS projects, consider the Mega or an ARM-based board with more RAM.

What is the tick rate in FreeRTOS for Arduino?

The default tick rate in the Arduino_FreeRTOS library for AVR is 64Hz (about 15.6ms per tick). This means vTaskDelay(1) delays about 15ms. For finer timing, you can change the tick rate in FreeRTOSConfig.h, but higher tick rates increase overhead. Use pdMS_TO_TICKS(milliseconds) macro to convert milliseconds to ticks portably.

Is FreeRTOS different from threading?

FreeRTOS tasks behave similarly to threads but are optimized for microcontrollers. Unlike POSIX threads (Linux), FreeRTOS tasks have statically allocated stack space, no virtual memory, and run in a cooperative or preemptive scheduling mode depending on configuration. The biggest difference: FreeRTOS tasks are designed for deterministic, real-time behavior critical in embedded systems.

Can I use delay() inside a FreeRTOS task?

Technically yes, but you should not. delay() blocks the entire CPU and prevents the scheduler from running other tasks. Always use vTaskDelay() inside FreeRTOS tasks — it blocks only the calling task and allows the scheduler to run higher or equal priority tasks in the meantime.

Does FreeRTOS solve all timing problems in Arduino?

FreeRTOS greatly simplifies multi-task timing but doesn’t make Arduino a real-time system in the strictest sense. Interrupts can still cause timing jitter, and the AVR’s limited timer resources mean some precise timing requirements (sub-microsecond) still need hardware interrupt handling. For most practical projects, FreeRTOS provides more than enough timing predictability.

Build smarter, multi-task Arduino projects today.
Explore our full range of Arduino boards at Zbotic.in — from classic Uno for FreeRTOS learning to powerful ARM-based boards for complex real-time applications.

Tags: arduino multitasking, arduino tasks, embedded rtos, freertos arduino, freertos tutorial, rtos arduino
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
Digispark ATtiny85: Smallest A...
blog digispark attiny85 smallest arduino compatible board guide 594672
blog arduino bootloader via arduino isp programming explained 594675
Arduino Bootloader via Arduino...

Related posts

Svg%3E
Read more

Arduino Batch Programming: Flash Multiple Boards Quickly

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Based Radar System with Ultrasonic Sensor

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Automatic Plant Monitor: Sunlight, Moisture, Temperature

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Lie Detector: GSR Sensor Polygraph Project

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Metal Detector: Build a Treasure Finder

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading

Add comment Cancel reply

Your email address will not be published. Required fields are marked

Facebook Twitter Instagram Pinterest Linkedin Youtube

Get the latest deals and more.

Download on Google Play Download on the App Store

Call us: 020 69134444 / 1800 209 0998

Monday - Saturday 09:30 AM - 06:00 PM
For Technical Supports Email: [email protected]
For Sales / Enquiries Email: [email protected]

  • My Account

    • Cart

    • Wishlist

    • Checkout

    • My Orders

    • Track Order

    • My Account

  • Information

    • FAQs

    • Blogs

    • Career

    • About Us

    • Contact Us

    • Payment Options

  • Policies

    • Privacy Policy

    • Terms & Conditions

    • GST Input Tax Credit

    • Shipping Return Policy

    • E-Waste Collection Points

    • Our Sitemap

© Zbotic.in is registered trademark of Moxie Supply Pvt Ltd – All Rights Reserved
Login
Use Phone Number
Use Email Address
Not a member yet? Register Now
Reset Password
Use Phone Number
Use Email Address
Register
Already a member? Login Now