freeRTOS debug
Your sketch is written for ESP32 but you’re compiling it for ESP8266, and that’s why it’s failing.
Why
SemaphoreHandle_t, xSemaphoreCreateBinary(), xSemaphoreGive(), xSemaphoreTake(), and portMAX_DELAY are FreeRTOS API calls.
ESP32 Arduino comes with FreeRTOS by default.
ESP8266 Arduino does not use FreeRTOS — so those types and functions don’t exist unless you add a separate RTOS layer.
✅ When is it a Good Time to Use FreeRTOS?
FreeRTOS is a real-time operating system designed for microcontrollers. It lets you split your application into multiple tasks that run seemingly in parallel.
🧠 Use FreeRTOS When:
1. 🧵 You Need to Run Multiple Tasks Concurrently
- Example: Reading sensor data, updating a display, and handling WiFi at the same time.
- Each task can run independently using
xTaskCreate().
2. ⏱️ You Require Real-Time Responsiveness
- Critical tasks (e.g., handling motor feedback or interrupts) can be given higher priority.
- Guarantees predictable response time.
3. 🕓 You Need Precise Timing or Scheduling
- Use
vTaskDelay(),xTimerCreate(), etc., to run tasks at specific intervals. - Better than using
delay()or busy-wait loops.
4. 📶 You Have Asynchronous Events to Handle
- Great for UART, I2C, network communication, button presses, etc.
- Use queues, semaphores, and event groups for clean async handling.
5. 🔄 You Want to Structure a Large Project Cleanly
- Modular task-based design.
- Easier to manage and debug than a giant
loop()function.
6. 📦 You're Using ESP32 or STM32 with Multiple Cores or Peripherals
- ESP32 has dual-core (PRO & APP cores).
- FreeRTOS lets you pin tasks to cores, assign priority, and manage memory better.
🧊 Not Always Necessary If:
| Situation | Recommendation |
|---|---|
| Simple blink or sensor reading | No need for FreeRTOS |
| Single function, low resource | Use loop() and interrupts |
| Ultra-low-power apps | May be better without RTOS |
✅ Example: Good Use Case (ESP32 with Camera, Webserver, Sensors)
- 📷 Task 1: Camera image capture
- 🌐 Task 2: Web server and WiFi communication
- 🌡️ Task 3: Sensor data read and logging
- 🎯 Task 4: OTA update check
All these tasks can run smoothly in parallel using FreeRTOS, each with its own stack and priority.
🚀 Summary
| Feature | Why FreeRTOS Helps |
|---|---|
| Multitasking | Run multiple functions in parallel |
| Real-time priority | Critical tasks get CPU first |
| Precise scheduling | Timers, delays, and periodic execution |
| Clean architecture | Organized, modular task-based design |
| Event handling | Easy async using semaphores & queues |
Let me know if you'd like a simple FreeRTOS project example!
Use FreeRTOS primitives:
Queue: for passing sensor/audio/display data between tasks
Semaphore: to lock I2C bus or protect shared resources
Timer: for periodic updates (e.g., sensor every 1s)
🧩 Inter-Task Communication
✅ 1. SSD1306 (I2C)
Use Adafruit SSD1306 or u8g2 with I2C.
Share I2C bus with BMP280.
Protect with mutex semaphore.
xSemaphoreTake(i2c_mutex, portMAX_DELAY); // update display xSemaphoreGive(i2c_mutex);
✅ 2. BMP280 Sensor (I2C)
Read temperature & pressure every 1–2 seconds.
Send data to DisplayTask via queue.
Example Queues and Semaphores:
QueueHandle_t sensor_data_queue;
QueueHandle_t display_msg_queue;
SemaphoreHandle_t i2c_mutex;
Sensor to Display Queue Message:
typedef struct {
float temperature;
float pressure;
} sensor_data_t
Pseudocode Overview
void SensorTask(void *pvParams) {
sensor_data_t data;
while (1) {
xSemaphoreTake(i2c_mutex, portMAX_DELAY);
data = read_bmp280();
xSemaphoreGive(i2c_mutex);
xQueueSend(sensor_data_queue, &data, 0);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void DisplayTask(void *pvParams) {
sensor_data_t data;
while (1) {
if (xQueueReceive(sensor_data_queue, &data, portMAX_DELAY)) {
xSemaphoreTake(i2c_mutex, portMAX_DELAY);
update_display(data.temperature, data.pressure);
xSemaphoreGive(i2c_mutex);
}
}
}
cores
xTaskCreatePinnedToCore(task1, "Task1", 2048, NULL, 1, NULL, 0); // Run on Core 0
xTaskCreatePinnedToCore(task2, "Task2", 2048, NULL, 1, NULL, 1); // Run on Core 1
Core 0: PRO_CPU (usually handles Wi-Fi, BT stack)
Core 1: APP_CPU (often used for your application)
compare
| Feature / RTOS | FreeRTOS | Zephyr RTOS | ThreadX (Azure RTOS) | Bare-Metal (No RTOS) |
|---|---|---|---|---|
| License | MIT (Permissive, Free) | Apache 2.0 (Permissive, Free) | Microsoft EULA (Free, but limited) | None |
| Footprint | Very Small (<10 KB) | Medium (~50–100 KB) | Small (~10–20 KB) | Very Small |
| Real-Time | Yes (preemptive, deterministic) | Yes (configurable RT, preemptive) | Yes (deterministic RTOS) | Depends on implementation |
| Ease of Use | Simple API, easy learning curve | More complex, powerful config system | Easy API, good documentation | Full control but more effort |
| Hardware Support | Very wide (ARM, RISC-V, etc.) | Very wide + device trees | Good (mainly ARM, RISC-V, x86) | Manual per-device work |
| Task Management | Yes (tasks, priorities) | Yes (threads, priorities, SMP) | Yes (threads, priorities) | Manual state machine |
| Synchronization | Semaphores, mutexes, queues | Semaphores, FIFOs, message queues | Semaphores, mutexes, event flags | Manual implementation |
| File System Support | External (e.g., FatFs) | Native FS (e.g., LittleFS, FatFS) | With Azure FileX | Manual or third-party |
| Networking | External (e.g., lwIP) | Native (TCP/IP stack, 6LoWPAN) | Azure NetX Duo (IPv4/IPv6) | External, complex to integrate |
| Power Management | Basic, user-implemented | Advanced (built-in PM framework) | Good (some MCU-specific features) | Manual |
| Security/IoT | AWS IoT support (via Amazon RTOS) | Secure boot, crypto, OTA, TLS | Azure IoT support, TLS, OTA | Manual, very limited |
| Trace & Debug | Tools: SystemView, Tracealyzer | Zephyr logging & tracing | NetX, ThreadX tracing tools | Manual logging |
| Community Support | Huge, mature ecosystem | Growing fast, backed by Linux Foundation | Good, backed by Microsoft | None (solo dev) |
example 3
FreeRTOS Example Explanations
✅ In short:
-
Queue examples→ show how to pass data safely. -
Mutex/Notifications→ show synchronization methods. -
AnalogRead/Blink→ show multitasking with hardware. -
TaskStatus/Utilities→ show debugging and monitoring. -
Interrupts→ show ISR to task communication.
1. AnalogRead_DigitalRead
- Shows how to create tasks that perform analog input and digital output.
- One task periodically reads an analog pin (ADC).
- Another task toggles a digital pin (e.g., LED).
- Demonstrates how multiple tasks run independently without blocking.
2. ArrayQueue
- Demonstrates using a FreeRTOS queue to pass an array of data between tasks.
- For example: Task A fills an array → sends via queue → Task B receives and processes.
- Useful for handling data buffers (sensor readings, UART packets).
3. Assert
- Shows how configASSERT() works in FreeRTOS.
- Asserts help catch programming errors (e.g., stack overflow, bad API usage).
- Example demonstrates failing conditions to show how assert is triggered.
4. Blink_AnalogRead
- Combines two common Arduino tasks:
- One task blinks an LED.
- Another task reads analog input.
- Demonstrates that FreeRTOS allows both to run concurrently without delay() blocking.
5. GoldilocksAnalogueTestSuite
- Specific test suite for the Goldilocks Analogue board (Arduino-compatible with audio-grade ADC/DAC).
- Shows how to use FreeRTOS tasks with more advanced ADC/DAC hardware.
- Mostly relevant if you use that hardware.
6. IntegerQueue
- Demonstrates using a queue of integers between producer/consumer tasks.
- Example: one task generates numbers, another task prints them.
- Basic introduction to queues in FreeRTOS.
7. Interrupts
- Shows how FreeRTOS interacts with hardware interrupts.
- Example: An ISR (interrupt service routine) gives a semaphore or sends data to a queue.
- Demonstrates safe communication between interrupts and tasks.
8. Mutex
- Demonstrates a mutex (mutual exclusion lock).
- Ensures only one task at a time accesses a shared resource (like Serial or an I²C bus).
- Prevents data corruption when multiple tasks try to use the same peripheral.
9. Notifications
- Shows how to use task notifications instead of semaphores/queues.
- Lightweight way to signal a task from another task or from an ISR.
- Example: ISR notifies a task when a button is pressed.
10. StructArray
- Demonstrates passing an array of structs between tasks.
- Useful when you have structured data (like sensor packets).
- Similar to ArrayQueue, but with custom struct types.
11. StructQueue
- Demonstrates using a queue of structs.
- Example: Task A sends a struct
{temperature, humidity, timestamp}to Task B. - More real-world than IntegerQueue because data usually comes in structs.
12. TaskStatus
- Demonstrates retrieving task runtime statistics.
- Uses FreeRTOS APIs (
uxTaskGetSystemState,vTaskGetRunTimeStats) to show:- Task names
- CPU usage %
- Stack high-water marks
- Useful for debugging and optimization.
13. TaskUtilities
- Shows helper functions that make FreeRTOS task management easier.
- Examples: delaying tasks (
vTaskDelay), checking stack usage, suspending/resuming tasks. - A "toolbox" demo for common task patterns.
example 2
queues + shared state
struct ControlData {
uint16_t throttle;
uint16_t steering;
uint16_t battery_mv;
};
// Shared global (protected with mutex if multiple tasks write to it)
volatile ControlData control;
✅ Recommendation: Use FreeRTOS with 3–4 tasks (ELRS, motors, ADC, BLE) + one shared struct. It gives you the best modularity and avoids blocking.
ELRS Task (high priority)
- Reads UART (CRSF packets).
- Parses channel values.
- Updates control.throttle and control.steering.
Motor Control Task (medium/high priority)
- Runs periodically (e.g. every 10–20 ms).
- Reads latest control.throttle / steering.
- Writes PWM to motors (non-blocking).
Battery ADC Task (low priority / slow loop)
- Reads ADC every 500–1000 ms.
- Updates control.battery_mv.
BLE Task (lowest priority)
- Takes control.battery_mv and updates BLE advertising packet.
- Runs every 1–2 seconds.
simple example 1
#include "FreeRTOS.h"
#include "task.h"
#include <stdio.h>
void vTask1(void *pvParameters) {
while (1) {
printf("Task 1 running\n");
vTaskDelay(pdMS_TO_TICKS(1000)); // Delay 1000 ms
}
}
void vTask2(void *pvParameters) {
while (1) {
printf("Task 2 running\n");
vTaskDelay(pdMS_TO_TICKS(2000)); // Delay 2000 ms
}
}
int main(void) {
xTaskCreate(vTask1, "Task1", 128, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", 128, NULL, 1, NULL);
vTaskStartScheduler(); // Start FreeRTOS
while (1);
}