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

RTOS for Arduino: FreeRTOS Task Scheduling Tutorial

RTOS for Arduino: FreeRTOS Task Scheduling Tutorial

March 11, 2026 /Posted byJayesh Jain / 0

If you have ever tried to make your Arduino do two things at the same time — say, read a sensor while also updating a display and responding to button presses — you have run into the fundamental limitation of the standard loop() approach. The solution used by professional embedded engineers worldwide is a Real-Time Operating System (RTOS), and the most popular free option for Arduino is FreeRTOS.

This tutorial walks you through everything you need to know to get FreeRTOS running on your Arduino, create multiple tasks, share data safely between them, and build genuinely responsive embedded systems — all without spending a rupee on additional hardware beyond your existing board.

Table of Contents

  1. What Is an RTOS and Why Do You Need One?
  2. Installing FreeRTOS on Arduino
  3. Creating Your First FreeRTOS Tasks
  4. Task Priorities and the FreeRTOS Scheduler
  5. Semaphores and Mutexes: Sharing Resources Safely
  6. Queues: Passing Data Between Tasks
  7. Practical Project: Multitasking Weather Station
  8. Tips, Stack Sizes, and Troubleshooting
  9. Frequently Asked Questions

What Is an RTOS and Why Do You Need One?

A Real-Time Operating System (RTOS) is a lightweight operating system designed to execute tasks within guaranteed time constraints. Unlike a full OS such as Linux, an RTOS has an extremely small footprint — FreeRTOS can run in as little as 6–12 KB of Flash and under 1 KB of RAM — making it perfect for microcontrollers like the ATmega328P (Arduino Uno) or ATmega2560 (Arduino Mega).

The standard Arduino loop() is fundamentally cooperative single-threaded execution. Every line of code blocks everything else. If you call delay(1000), your entire program freezes for a second. This is fine for simple projects, but breaks down the moment you need:

  • Concurrent sensor reading and display updates
  • Tight timing for motor control alongside serial communication
  • Responsive UI while running background data logging
  • Network communication (Ethernet/Wi-Fi) with local I/O

FreeRTOS solves this by providing preemptive multitasking: the scheduler switches between tasks so rapidly (every 1 ms by default on Arduino) that all tasks appear to run simultaneously. Each task gets its own stack, priority, and execution context.

Installing FreeRTOS on Arduino

Getting FreeRTOS onto your Arduino takes about two minutes:

  1. Open the Arduino IDE and go to Sketch → Include Library → Manage Libraries
  2. Search for “FreeRTOS” — look for the library by Richard Barry / Real Time Engineers Ltd
  3. Click Install

Alternatively, install via the Arduino CLI:

arduino-cli lib install "FreeRTOS"

The library supports the following Arduino boards out of the box:

  • Arduino Uno / Nano / Mini — ATmega328P, 32 KB Flash, 2 KB RAM (tight but workable)
  • Arduino Mega 2560 — ATmega2560, 256 KB Flash, 8 KB RAM (recommended for serious projects)
  • Arduino Leonardo — ATmega32U4, USB HID support
  • Arduino Nano Every — ATmega4809, more RAM than Uno
Recommended: Arduino Mega 2560 R3 Board — The 8 KB of RAM and 256 KB Flash make this the ideal board for FreeRTOS projects. You can create 8–12 tasks comfortably without hitting memory limits, and the extra peripherals (more UARTs, SPI, I2C) give you room to grow.

After installation, include the library at the top of your sketch:

#include <Arduino_FreeRTOS.h>
#include <semphr.h>   // for semaphores
#include <queue.h>    // for queues

Creating Your First FreeRTOS Tasks

The most important FreeRTOS concept is the task. A task is simply a C function that runs in an infinite loop. Here is the minimal structure:

void TaskBlink(void *pvParameters) {
  // one-time setup for this task
  pinMode(LED_BUILTIN, OUTPUT);

  for (;;) {  // infinite loop — never return!
    digitalWrite(LED_BUILTIN, HIGH);
    vTaskDelay(500 / portTICK_PERIOD_MS);  // non-blocking delay
    digitalWrite(LED_BUILTIN, LOW);
    vTaskDelay(500 / portTICK_PERIOD_MS);
  }
}

The critical difference from regular code: vTaskDelay() suspends only this task and lets other tasks run during the delay. It is non-blocking from the system’s perspective.

Create and start tasks in setup():

void setup() {
  Serial.begin(9600);

  xTaskCreate(
    TaskBlink,      // function name
    "Blink",        // task name (for debugging)
    128,            // stack size in words (not bytes)
    NULL,           // parameters to pass
    1,              // priority (1 = lowest)
    NULL            // task handle (optional)
  );

  xTaskCreate(
    TaskSerial,
    "Serial",
    128,
    NULL,
    1,
    NULL
  );

  // vTaskStartScheduler() is called automatically by the library
}

void loop() {
  // Leave empty — FreeRTOS takes over
}
Recommended: Arduino Nano Every with Headers — Powered by the ATmega4809 with 6 KB RAM (3x more than Uno), the Nano Every is a great compact board for FreeRTOS projects where you need more headroom than a standard Nano but want a small form factor.

Task Priorities and the FreeRTOS Scheduler

FreeRTOS uses a preemptive priority-based scheduler. Every tick (1 ms on Arduino by default), the scheduler checks whether a higher-priority task is ready to run and switches to it if so.

Priority rules:

  • Higher number = higher priority (opposite of what many expect)
  • Tasks of equal priority share time in a round-robin fashion
  • A high-priority task that is blocked (waiting) does not starve lower-priority tasks
  • Priority 0 is reserved for the idle task (runs only when nothing else can)

Practical priority assignment example:

// Priority 3: safety-critical motor control
xTaskCreate(TaskMotorControl, "Motor", 256, NULL, 3, NULL);

// Priority 2: sensor reading (needs to be timely)
xTaskCreate(TaskSensorRead, "Sensor", 256, NULL, 2, NULL);

// Priority 1: display update (visual, can lag slightly)
xTaskCreate(TaskDisplay, "Display", 128, NULL, 1, NULL);

// Priority 1: serial logging (lowest urgency)
xTaskCreate(TaskLogging, "Log", 128, NULL, 1, NULL);

Use taskYIELD() inside a task to voluntarily give up the CPU to another task of equal priority without blocking.

Semaphores and Mutexes: Sharing Resources Safely

When two tasks share a resource — a global variable, a peripheral like SPI or I2C, a serial port — you must protect access. Without synchronisation, you get race conditions: corrupted data, garbled output, and hard-to-debug crashes.

Mutex (Mutual Exclusion Semaphore) — ensures only one task accesses a shared resource at a time:

SemaphoreHandle_t xI2CMutex;

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

void TaskSensor1(void *pvParameters) {
  for (;;) {
    if (xSemaphoreTake(xI2CMutex, portMAX_DELAY) == pdTRUE) {
      // Safe to use I2C here
      float temp = bmp280.readTemperature();
      xSemaphoreGive(xI2CMutex);  // Release!
    }
    vTaskDelay(100 / portTICK_PERIOD_MS);
  }
}

Binary Semaphore — used for task synchronisation (signalling an event):

SemaphoreHandle_t xButtonSemaphore;

void setup() {
  xButtonSemaphore = xSemaphoreCreateBinary();
  attachInterrupt(digitalPinToInterrupt(2), buttonISR, FALLING);
}

void buttonISR() {
  // From ISR context — use FromISR variant!
  BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  xSemaphoreGiveFromISR(xButtonSemaphore, &xHigherPriorityTaskWoken);
  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

void TaskHandleButton(void *pvParameters) {
  for (;;) {
    if (xSemaphoreTake(xButtonSemaphore, portMAX_DELAY) == pdTRUE) {
      // Button was pressed — handle it
      Serial.println("Button pressed!");
    }
  }
}
Recommended: Arduino Nano 33 IoT with Header — For FreeRTOS projects that need wireless connectivity, the Nano 33 IoT runs on SAMD21 (ARM Cortex-M0+) with 32 KB RAM and built-in Wi-Fi/Bluetooth. The ARM architecture offers a richer FreeRTOS experience with more RAM for complex multi-task applications.

Queues: Passing Data Between Tasks

Queues are the standard FreeRTOS mechanism for passing data between tasks safely. Think of a queue as a thread-safe FIFO buffer.

QueueHandle_t xSensorQueue;

void setup() {
  // Create a queue holding 10 float values
  xSensorQueue = xQueueCreate(10, sizeof(float));

  xTaskCreate(TaskReadSensor, "SensorRead", 256, NULL, 2, NULL);
  xTaskCreate(TaskProcessData, "Process", 256, NULL, 1, NULL);
}

void TaskReadSensor(void *pvParameters) {
  for (;;) {
    float temperature = analogRead(A0) * 0.48828;  // example
    xQueueSend(xSensorQueue, &temperature, portMAX_DELAY);
    vTaskDelay(100 / portTICK_PERIOD_MS);
  }
}

void TaskProcessData(void *pvParameters) {
  float receivedTemp;
  for (;;) {
    if (xQueueReceive(xSensorQueue, &receivedTemp, portMAX_DELAY) == pdTRUE) {
      Serial.print("Temp: ");
      Serial.println(receivedTemp);
    }
  }
}

Queues can hold any data type, including structs. For complex sensor data, define a struct:

typedef struct {
  float temperature;
  float humidity;
  uint32_t timestamp;
} SensorData_t;

QueueHandle_t xDataQueue = xQueueCreate(5, sizeof(SensorData_t));

Practical Project: Multitasking Weather Station

Let us put it all together with a real project: a weather station that simultaneously reads temperature/humidity, logs data over serial, and displays results — all three happening independently.

Hardware needed:

  • Arduino Mega 2560 (recommended for RAM headroom)
  • DHT11 or DHT20 sensor
  • 16×2 LCD or TFT display
  • Push button for display mode toggle
#include <Arduino_FreeRTOS.h>
#include <queue.h>
#include <semphr.h>
#include <DHT.h>

#define DHTPIN 4
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

typedef struct {
  float temp;
  float humidity;
} WeatherData_t;

QueueHandle_t xWeatherQueue;
SemaphoreHandle_t xSerialMutex;

void TaskReadDHT(void *pvParameters) {
  WeatherData_t data;
  for (;;) {
    data.temp = dht.readTemperature();
    data.humidity = dht.readHumidity();
    if (!isnan(data.temp)) {
      xQueueSend(xWeatherQueue, &data, 0);  // don't block if full
    }
    vTaskDelay(2000 / portTICK_PERIOD_MS); // DHT needs 2s minimum
  }
}

void TaskLogSerial(void *pvParameters) {
  WeatherData_t data;
  for (;;) {
    if (xQueueReceive(xWeatherQueue, &data, portMAX_DELAY) == pdTRUE) {
      if (xSemaphoreTake(xSerialMutex, portMAX_DELAY) == pdTRUE) {
        Serial.print("Temp: "); Serial.print(data.temp);
        Serial.print("C  Humidity: "); Serial.print(data.humidity);
        Serial.println("%");
        xSemaphoreGive(xSerialMutex);
      }
    }
  }
}

void TaskHeartbeat(void *pvParameters) {
  for (;;) {
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
}

void setup() {
  Serial.begin(9600);
  dht.begin();
  pinMode(LED_BUILTIN, OUTPUT);

  xWeatherQueue = xQueueCreate(3, sizeof(WeatherData_t));
  xSerialMutex = xSemaphoreCreateMutex();

  xTaskCreate(TaskReadDHT, "DHT", 256, NULL, 2, NULL);
  xTaskCreate(TaskLogSerial, "Log", 200, NULL, 1, NULL);
  xTaskCreate(TaskHeartbeat, "HB", 64, NULL, 1, NULL);
}

void loop() {} // Empty
Recommended: DHT20 SIP Packaged Temperature and Humidity Sensor — The DHT20 improves on the DHT11 with I2C interface, better accuracy (±0.5°C, ±2% RH), and a proper SIP package that is more reliable than the bare module. Perfect for the multitasking weather station project above.
Recommended: 2.4″ Touch Screen TFT Display Shield for Arduino Uno/Mega — Add a visual output to your FreeRTOS weather station with this plug-and-play TFT shield. Assign display updates to a low-priority task so sensor reading is never delayed by screen refresh.

Tips, Stack Sizes, and Troubleshooting

Stack overflow is the most common FreeRTOS beginner problem. If your Arduino randomly resets, a task has overflowed its stack. Solutions:

  • Enable stack overflow detection: define configCHECK_FOR_STACK_OVERFLOW 2 and implement vApplicationStackOverflowHook()
  • Increase the stack size for the crashing task (try doubling it)
  • Use uxTaskGetStackHighWaterMark(NULL) to measure peak stack usage

Stack size guidance (words, not bytes — multiply by 2 for bytes on AVR):

  • Simple GPIO task: 64–100 words
  • Task with Serial or String usage: 200–300 words
  • Task with floating-point math: 256–400 words
  • Task using libraries (DHT, display): 300–512 words

Memory management tips for small AVR boards:

  • Avoid String objects (heap fragmentation) — use char[] arrays
  • Avoid Serial.print(F("text")) — always use F() macro to keep strings in Flash
  • Monitor free heap with xPortGetFreeHeapSize()
  • If total RAM usage (stack + queue + mutex) exceeds 1.5 KB on an Uno, move to a Mega

Timing: The default tick rate is 1 ms. vTaskDelay(1) delays exactly one tick (1 ms). Use pdMS_TO_TICKS(ms) macro for clarity. For periodic tasks with accurate timing, use vTaskDelayUntil() instead of vTaskDelay().

Frequently Asked Questions

Can I use FreeRTOS with Arduino Uno even with only 2 KB RAM?

Yes, but you are severely constrained. Each task needs at minimum 64–128 words (128–256 bytes) of stack plus the task control block (~100 bytes). Realistically you can run 2–3 simple tasks on an Uno. For anything more complex, use an Arduino Mega 2560 (8 KB RAM) or Nano Every (6 KB RAM). The Mega is the most popular FreeRTOS platform for beginners.

What is the difference between vTaskDelay() and delay()?

delay() is a busy-wait that blocks the entire CPU — no other task can run. vTaskDelay() suspends only the calling task and places it in a blocked state, freeing the scheduler to run other tasks during that time. Always use vTaskDelay() inside FreeRTOS tasks. Never use delay() in a FreeRTOS sketch.

Can I use interrupts with FreeRTOS?

Yes, but ISRs (Interrupt Service Routines) cannot call normal FreeRTOS API functions. Use the FromISR variants: xSemaphoreGiveFromISR(), xQueueSendFromISR(), xTaskNotifyFromISR(). Always pass a BaseType_t xHigherPriorityTaskWoken parameter and call portYIELD_FROM_ISR() at the end of the ISR if it returns pdTRUE.

Is FreeRTOS suitable for commercial or production projects?

Absolutely. FreeRTOS is MIT-licensed and is used in millions of commercial products worldwide, including medical devices, industrial controllers, and consumer electronics. It is maintained by Amazon (AWS FreeRTOS) and has a rigorous safety certification track record. Many Indian product companies use FreeRTOS in their embedded products.

How do I debug FreeRTOS task issues?

Use vTaskList() to print a table of all tasks, their states, stack high watermarks, and priorities to Serial. Call it periodically in a low-priority task. Also use vTaskGetRunTimeStats() to see CPU time distribution between tasks — this quickly reveals which task is hogging the CPU or starving others.

FreeRTOS transforms Arduino from a simple sequential executor into a capable embedded platform that can handle real-world complexity. Whether you are building an industrial sensor logger, a drone controller, or a smart home hub, task-based thinking and the FreeRTOS scheduler will make your code cleaner, more reliable, and genuinely concurrent.

Ready to start your RTOS journey? Browse our full range of Arduino boards and accessories at Zbotic.in — from the Mega 2560 for RAM-heavy FreeRTOS projects to compact Nano boards for space-constrained applications. All shipped fast across India.

Tags: Arduino, embedded systems, FreeRTOS, multitasking, real-time OS, RTOS, task scheduling
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
Raspberry Pi Ubuntu Server: Fu...
blog raspberry pi ubuntu server full setup and configuration guide 594949
blog dual core programming arduino vs esp32 concurrency guide 594955
Dual Core Programming: 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