FreeRTOS is one of the most widely used real-time operating systems in embedded development. It gives a project tasks, queues, semaphores, timers, and a scheduler, so firmware can be organized as cooperating pieces instead of one large loop.
STM32 and ESP32 can both run FreeRTOS, but the development experience is not the same. STM32 usually feels like a traditional microcontroller project where the developer chooses how much RTOS structure to add. ESP32 usually feels like a connected system where FreeRTOS is already part of the platform, especially when Wi-Fi, Bluetooth, or the ESP-IDF framework are used.
Short Answer
Use STM32 with FreeRTOS when the project needs deterministic peripheral control, industrial I/O, motor control, measurement, or tight hardware timing. Use ESP32 with FreeRTOS when the project needs wireless connectivity, IoT features, web services, MQTT, Bluetooth, or fast prototyping with networking already available.
Both platforms are capable, but they solve different kinds of embedded problems.
FreeRTOS Role on Each Platform
| Topic | STM32 | ESP32 |
|---|---|---|
| Typical use | Industrial control, sensors, motor drives, low-level hardware control | IoT devices, Wi-Fi products, Bluetooth devices, gateways, smart sensors |
| RTOS integration | Often added through STM32CubeMX or manually integrated | Built into ESP-IDF and used by the system itself |
| Hardware focus | Precise peripherals, timers, ADC, PWM, DMA, communication interfaces | Wireless stack, networking, dual-core execution, flash-based applications |
| System complexity | Usually controlled directly by the firmware developer | Includes framework and system tasks in addition to user tasks |
| Best fit | Predictable embedded control | Connected embedded applications |
Development Environment
STM32
On STM32, FreeRTOS is commonly enabled from STM32CubeMX or STM32CubeIDE. CubeMX can generate the FreeRTOS configuration, create initial tasks, and connect the RTOS to the HAL time base. The developer still has strong control over startup code, clock configuration, peripheral setup, interrupt priorities, and memory layout.
This makes STM32 a good choice when the project depends on exact peripheral behavior. For example, a control board may use PWM timers, ADC conversion triggered by a timer, DMA transfers, CAN communication, and a FreeRTOS task that processes measurements at a fixed rate.
ESP32
On ESP32, the most complete FreeRTOS experience is through ESP-IDF. FreeRTOS is not only an optional layer; it is part of how the platform runs. Wi-Fi, Bluetooth, TCP/IP, event handling, logging, timers, and user code all live inside the same system environment.
This is powerful because networking and connectivity are already integrated. It also means the firmware developer must respect existing system tasks, stack usage, event loops, and core allocation.
Task Creation
A basic FreeRTOS task looks similar on both platforms:
static void sensor_task(void *argument)
{
for (;;) {
read_sensor();
process_sample();
vTaskDelay(pdMS_TO_TICKS(10));
}
}
xTaskCreate(sensor_task, "sensor", 512, NULL, 2, NULL);
The structure is the same: the task runs forever, performs work, and delays or blocks so other tasks can run. The important differences are in the port details. On many STM32 FreeRTOS projects, the stack depth is expressed in words. In ESP-IDF, task stack sizes are commonly documented in bytes. This is a small detail, but it can create confusing stack problems when code is moved between platforms.
Scheduling and Cores
STM32
Most STM32 FreeRTOS projects run on a single ARM Cortex-M core. Scheduling is therefore easier to reason about: one task is running at a time, interrupts can preempt tasks, and shared data is protected using queues, mutexes, critical sections, or interrupt-safe APIs.
This single-core behavior is often enough for real-time control. The design becomes clear when high-frequency work is handled by timers, DMA, and interrupts, while FreeRTOS tasks handle slower logic, communication, diagnostics, and state machines.
ESP32
Many ESP32 chips have two cores, and ESP-IDF FreeRTOS supports running tasks across them. A task can also be pinned to a specific core when needed. This is useful when one part of the application is handling communication while another part handles sampling, buffering, or local control.
The extra core is useful, but it adds design responsibility. Shared data may be accessed from tasks running truly in parallel, not just from tasks taking turns on one CPU. That makes mutexes, queues, and careful ownership rules more important.
Interrupts
Interrupt handling is one of the biggest practical differences between STM32 and ESP32 FreeRTOS projects.
STM32 Interrupts
STM32 uses ARM Cortex-M interrupt priorities through the NVIC. When FreeRTOS is
enabled, interrupt priority configuration becomes very important. Any interrupt
that calls FreeRTOS functions such as xQueueSendFromISR() must follow
the priority rules defined by the FreeRTOS configuration.
A common STM32 mistake is setting an interrupt priority too high and then calling a FreeRTOS API from that interrupt. The code may compile and sometimes run, but later fail in unpredictable ways.
ESP32 Interrupts
ESP32 interrupt handling is closely tied to ESP-IDF. Some interrupt routines must be placed in internal RAM if they need to run while flash cache is disabled. Wireless activity, flash operations, and system services can affect what is safe to do inside an interrupt.
The same general rule still applies: keep interrupt routines short, move data into a queue or buffer, and let a task do the heavier processing.
Memory and Stack
FreeRTOS makes memory use more visible because every task needs its own stack. More tasks can make firmware easier to read, but each task has a memory cost.
| Memory topic | STM32 | ESP32 |
|---|---|---|
| RAM pressure | Can be tight on smaller devices | Usually more RAM, but framework and wireless stacks also consume RAM |
| Task stack | Developer usually sizes every task carefully | User tasks share the system with ESP-IDF and network tasks |
| Heap use | Often minimized in industrial firmware | More common because networking and frameworks allocate memory |
| Debug focus | Stack overflow, heap size, static allocation, linker map | Stack high-water marks, heap regions, task monitoring, event queues |
Timing Behavior
FreeRTOS is real-time, but it is not magic. It does not make slow code fast, and it does not guarantee timing unless the system is designed correctly.
On STM32, very accurate timing is usually built with hardware timers, input capture, output compare, DMA, and interrupt-driven peripherals. FreeRTOS tasks then process events after the hardware has captured or transferred the data.
On ESP32, timing-sensitive work must be designed around system activity such as Wi-Fi, flash access, and other framework tasks. ESP32 can handle many real-time tasks well, but it is usually not the first choice for the most deterministic industrial control loops.
Communication
STM32
STM32 is strong when communication is close to the hardware: UART, SPI, I2C, CAN, USB, Ethernet, RS-485, and industrial protocols. FreeRTOS helps separate protocol handling from application logic. A common design is one task for communication, one task for control logic, and one task for diagnostics or logging.
ESP32
ESP32 is strong when communication means connectivity. Wi-Fi, Bluetooth, MQTT, HTTP, WebSocket, OTA updates, and cloud communication are much easier to build compared with starting from a basic microcontroller. FreeRTOS gives these features a natural structure because networking code usually blocks, waits for events, and exchanges messages with other tasks.
Debugging
Debugging FreeRTOS requires looking at the system as a group of tasks instead of a single program flow.
| Debug topic | STM32 | ESP32 |
|---|---|---|
| Common tools | STM32CubeIDE, ST-Link, SWD, trace tools, logic analyzer | ESP-IDF monitor, JTAG, logging, heap and task diagnostics |
| Common failures | Wrong interrupt priority, stack overflow, blocking inside callbacks | Insufficient task stack, blocking system event tasks, core-affinity issues |
| Best habit | Check priorities, stack sizes, and peripheral timing with real signals | Watch task stacks, heap usage, event queues, and logs under Wi-Fi load |
Architecture Patterns
A clean FreeRTOS design usually avoids creating a task for every small function. Tasks should represent independent timing or blocking behavior. If two pieces of code always run together, they often belong in the same task.
Good STM32 Pattern
Timer or DMA interrupt
|
v
Queue or notification
|
v
Processing task
|
v
Control output or communication task
This keeps the interrupt short and lets the RTOS schedule the longer work.
Good ESP32 Pattern
Wi-Fi or sensor event
|
v
Event handler or queue
|
v
Application task
|
v
MQTT, HTTP, storage, or local control task
This keeps framework callbacks light and prevents application code from blocking important system services.
Common Mistakes
- Creating too many tasks instead of using queues, timers, and state machines.
- Using
HAL_Delay()or busy loops inside RTOS tasks instead ofvTaskDelay()or blocking APIs. - Calling normal FreeRTOS APIs from interrupts instead of the
FromISRversions. - Giving every task a high priority and then wondering why lower-priority tasks never run.
- Making task stacks too small and ignoring stack high-water marks.
- Sharing global data between tasks without a queue, mutex, or clear ownership rule.
- On STM32, using interrupt priorities that conflict with FreeRTOS rules.
- On ESP32, blocking inside Wi-Fi, Bluetooth, or event callbacks.
Which One Should You Choose?
Choose STM32 with FreeRTOS when the product is mainly a control or measurement system. Examples include motor controllers, industrial I/O modules, power electronics, data acquisition boards, safety-related monitors, and devices that need predictable peripheral timing.
Choose ESP32 with FreeRTOS when the product is mainly a connected device. Examples include wireless sensors, smart home devices, BLE gateways, MQTT nodes, web dashboards, OTA-updated devices, and prototypes that need communication features quickly.
Conclusion
FreeRTOS gives both STM32 and ESP32 a structured way to build embedded software, but the platforms have different personalities. STM32 gives more direct control over hardware timing and peripheral behavior. ESP32 gives a richer connected environment where FreeRTOS is already part of the system architecture.
The best choice depends on the center of the project. If the hard part is precise control, STM32 is usually the cleaner starting point. If the hard part is wireless communication and application-level connectivity, ESP32 usually gets there faster.