2026-06-14 · RTOS · FreeRTOS · Zephyr · NuttX · embedded · firmware

Do you need an RTOS?

Most firmware starts as a while(1) loop. Read the sensors, update the controller, push the outputs, repeat. It is the right answer far more often than engineers admit, and it keeps being the right answer until two requirements collide: something must happen on a strict deadline while something else takes an unpredictable amount of time. The moment a blocking operation — a TLS handshake, a flash erase, a USB enumeration — can stall the one task that must run every millisecond, the loop is no longer a schedule. It is a hope. An RTOS is what you reach for when hope is not an acceptable timing guarantee.

This is a field guide to that decision: what an RTOS actually provides, when a bare-metal design is the correct engineering choice, when you have outgrown both and need Linux, how the major kernels genuinely differ, which industries standardized on which, and what changed in the last few years — because the RTOS landscape of 2026 looks nothing like the one from a decade ago.

”Real-time” is a promise about when, not how fast

The most common misconception is that a real-time operating system is a fast one. It is not. Real-time means deterministic: the worst-case time between an event and the system’s response is bounded, known, and can be written into a specification. A 1 GHz application processor running stock Linux is far faster than a 64 MHz Cortex-M, yet it is not real-time, because under load its response latency has a long, ugly tail you cannot bound. The Cortex-M with a small RTOS can be, because its scheduler guarantees that the highest-priority ready task runs within a known number of microseconds — every time.

That guarantee comes in two grades. Hard real-time means a missed deadline is a system failure: an airbag squib, a motor commutation step, a brake-by-wire command. Soft real-time means a missed deadline degrades quality but is survivable: a dropped audio frame, a late UI repaint. The distinction decides how much of your design budget goes into proving the bound versus merely meeting it most of the time.

An RTOS delivers determinism with two ingredients and almost nothing else: a preemptive priority scheduler, and a set of synchronization and communication primitives. Everything marketed on top — networking, file systems, device drivers — is convenience, not the core. The core is the promise that the most important ready task is the running task, always.

Side-by-side comparison. On the left, a bare-metal super-loop: a single while(1) box cycling through Task A, a long Task B, and Task C in sequence, with a timeline below showing Task C's hard deadline missed because Task B overran. On the right, a preemptive RTOS: three prioritized tasks where a high-priority task and an interrupt preempt lower work immediately, and every deadline is met. Figure 1 — The same three jobs, two runtimes. In a cooperative super-loop one long job delays every other; a preemptive scheduler interrupts whatever is running the instant a more important task becomes ready.

What is actually inside

Strip an RTOS to its kernel and you find a small, well-defined set of objects. Learn these six and you understand 90% of every RTOS you will ever touch — the names change, the concepts do not.

  • Tasks (threads). Independent units of execution, each with its own stack and a priority. The scheduler runs the highest-priority task that is ready.
  • The scheduler. On every tick — or, in a tickless design, on every event — it decides who runs. Preemptive and priority-based is the norm; equal-priority tasks share the CPU round-robin.
  • Queues. The safe way for tasks to pass data. A producer posts, a consumer blocks until something arrives. Message passing, not shared globals, is the idiom that keeps concurrent firmware sane.
  • Mutexes. Mutual exclusion for a shared resource, ideally with priority inheritance so a low-priority holder is temporarily boosted to avoid blocking a high-priority waiter. This is not a detail — it is the bug that nearly lost the Mars Pathfinder mission.
  • Semaphores. Counting or binary signals, typically used to hand an event from an interrupt to a task (“data ready — wake the worker”).
  • Software timers. Deferred or periodic callbacks without burning a hardware timer per job.

A task is never just “running.” It moves through a small state machine, and understanding it is the difference between firmware that schedules and firmware that mysteriously hangs.

A two-part RTOS diagram. The top shows the canonical task state machine — Running, Ready, Blocked and Suspended — with labelled transitions for preemption, yielding, blocking on a queue or mutex, and resuming. The bottom shows a scheduling timeline with a high, medium and low priority task plus a tick interrupt and an ISR, illustrating context switches: the low task runs until the medium task becomes ready and preempts it, an interrupt fires and signals the high task which runs next, then control returns down the priority order. Figure 2 — Top: a task is always in exactly one state; the scheduler only ever runs a Ready task. Bottom: how preemption and a deferred interrupt actually interleave on one core, context switch by context switch.

When bare-metal is the right answer

The honest section first, because an RTOS is frequently the wrong tool. A super-loop with interrupt service routines is not a primitive design — it is the correct design for a large class of products, and it has properties an RTOS cannot match:

  • It is trivially analyzable. One execution path, no preemption, no shared state between concurrent tasks. The class of bug that an RTOS introduces — race conditions, deadlocks, priority inversion, stack overflow per task — simply cannot occur.
  • It is the smallest. No kernel, no per-task stacks, no scheduler tick. On a part with single-digit kilobytes of RAM, an RTOS may not even fit, and certainly will not leave room for your application.
  • It is the cheapest in CPU. No context-switch overhead, no scheduler latency. Every cycle goes to your code.

If your system has a handful of activities, their timing fits comfortably inside interrupt handlers, and a well-written state machine in the main loop ties it together — you do not need an RTOS, and adding one buys you concurrency bugs in exchange for nothing. A great deal of high-volume, cost-sensitive, single-function firmware ships exactly this way and should.

The cost of an RTOS is real and worth stating plainly: it adds a kernel you must trust, per-task RAM you must budget, a scheduler latency you must account for, and an entire category of timing-dependent bugs that are miserable to reproduce. You pay that cost to buy structured concurrency. Only buy it when you need it.

When you genuinely need one — and when you need Linux instead

Reach for an RTOS when one or more of these is true:

  • Multiple independent activities run at different rates and priorities — a control loop at 1 kHz, a comms stack on its own schedule, a UI that must stay responsive. Hand-multiplexing these in one loop becomes a fragile timing puzzle.
  • You must call blocking middleware. TCP/IP, TLS, USB, BLE, file systems — the mature stacks assume threads they can block. Bolting them onto a super-loop means rewriting them as state machines, which is more work than adopting a scheduler.
  • Hard and soft deadlines coexist. Priorities let the critical task always win, while best-effort work fills the gaps — a guarantee a flat loop cannot give.
  • The team and codebase need to scale. Tasks are a clean module boundary; several engineers can own separate tasks without stepping on a shared loop.

But there is a ceiling above the RTOS, too. When you need an MMU for memory protection between processes, a rich filesystem, a display stack and GUI framework, a package ecosystem, or simply more software than any one team can maintain, you have outgrown the RTOS and want embedded Linux. Linux is not a real-time operating system, but the PREEMPT_RT real-time patches — now mainlined — give it bounded-enough latency for many firm and soft tasks, and the genuinely hard real-time portion can be pushed to a microcontroller or a dedicated coprocessor alongside it. The modern heterogeneous SoC — Linux on the application cores, an RTOS on a Cortex-M companion — exists precisely because neither side wins the whole problem.

A positioning map of embedded runtimes on two axes. The horizontal axis runs from low to high software complexity and connectivity; the vertical axis runs from hard real-time determinism at the top to soft real-time at the bottom. Plotted from lower-left to upper-right: bare-metal super-loop, bare-metal with state machines, a classic RTOS such as FreeRTOS or ThreadX, a platform RTOS such as Zephyr or NuttX, Linux with the PREEMPT_RT patch, and full embedded Linux. A side checklist lists the questions that push a design up the ladder. Figure 3 — The runtime ladder. Each rung adds capability and subtracts determinism; the art is climbing exactly as far as the requirements force you and no further.

Where to start

The fastest way to learn an RTOS is to put one on real hardware and break it.

  1. Pick a Cortex-M board with good support: an ST Nucleo, a Nordic nRF52/53, a Raspberry Pi RP2350, or an ESP32. The silicon is cheap and the documentation is mature.
  2. Choose your first kernel by goal. Pick FreeRTOS to learn the concepts with the least ceremony — it is a small kernel and the mental model is uncluttered. Pick Zephyr to learn a modern platform OS with drivers, device tree and a connectivity stack — steeper, but the skills transfer directly to product work.
  3. Learn the core six from the list above, in order: create two tasks, pass data with a queue, protect a shared resource with a mutex, signal from an ISR with a semaphore, schedule periodic work with a software timer.
  4. Then learn the three things that bite people: priority inversion and why a mutex with inheritance — not a bare semaphore — guards a shared resource; how to size a task stack and detect overflow; and how to defer interrupt work to a task instead of doing it all in the ISR.
  5. Instrument it. A trace tool — Percepio Tracealyzer or SEGGER SystemView — turns the invisible interleaving of tasks into a timeline you can actually read. RTOS-aware debugging is the single biggest accelerator for understanding what your scheduler is really doing.

The major kernels, and how they actually differ

The market is wide, but the meaningful differences reduce to a few axes: is it a bare kernel or a full OS, how POSIX-compliant is it, what license does it carry, what is its footprint, and is there a safety-certified variant.

RTOSLicenseWhat it isPOSIXFootprintStewardWhere it lives
FreeRTOSMITBare kernel + primitivesWrapper only~5–10 KBAWSIoT, MCU, the default starting point
ZephyrApache 2.0Full platform OSPartial subsystem~8 KB → MBLinux FoundationConnected products, wearables, industrial
NuttXApache 2.0Tiny POSIX OS, Linux-likeStrict~tens of KBApacheDrones (PX4), consumer (OpenVela)
Eclipse ThreadXMITSmall kernel + middlewareWrapper~2–20 KBEclipse FoundationBillions of devices, safety-grade
RT-ThreadApache 2.0Kernel + large component setPartial~3 KB → MBRT-Thread (CN)Large adoption in China, IoT
VxWorksCommercialFull RTOSYesConfigurableWind River (Aptiv)Aerospace, defense, industrial
QNXCommercialPOSIX microkernelYesConfigurableBlackBerryAutomotive cockpits, medical
INTEGRITYCommercialSeparation-kernel RTOSYesConfigurableGreen HillsHighest-assurance avionics/defense

FreeRTOS vs NuttX — the clearest contrast in the field

These two are worth comparing directly, because they sit at opposite ends of the “kernel or OS” axis and the choice between them is really a choice of philosophy.

FreeRTOS is a scheduler you bolt onto your firmware. It is the kernel and the primitives — tasks, queues, mutexes, timers — and almost nothing else. Its API is its own (xTaskCreate, xQueueSend); it is not a POSIX system, though a thin POSIX wrapper exists. You bring the drivers, the file system, the network stack (typically as separate FreeRTOS+ or third-party components). That minimalism is the point: it fits in a few kilobytes, it is trivial to drop into an existing project, it runs on practically every architecture, and under AWS stewardship it has become a dependable long-term platform — SMP support landed in the mainline kernel (v11, late 2023) and the Long-Term-Support releases carry two years of security fixes. It is, by a wide margin, the most widely deployed RTOS on microcontrollers, and the right default when you want a scheduler and not an opinion about everything else.

NuttX is a tiny POSIX operating system that happens to fit on a microcontroller. Started by Gregory Nutt in 2007 specifically because no open-source RTOS was seriously POSIX-compliant, it deliberately looks like Linux: a virtual file system, device nodes under /dev, pthreads, BSD sockets, a working shell (NSH), even loadable applications — in tens of kilobytes. Its governing standards are POSIX and ANSI, and that is the entire value proposition: application code written against POSIX ports between NuttX and Linux with little change. Write your logic once, run it on a Linux box for development and on a Cortex-M in the product. That portability is why it underpins the PX4 flight stack on essentially every PX4 drone, and why Xiaomi’s OpenVela platform — reportedly over a thousand product SKUs across watches, speakers and displays — is built on it.

The trade is exactly what you would expect. FreeRTOS gives you maximal kernel simplicity, the smallest footprint, and the largest ecosystem, at the price of writing or sourcing everything above the scheduler in its own idiom. NuttX gives you maximal application portability — POSIX semantics, a familiar Linux-like environment — at the price of a larger footprint and a heavier system to learn. If you are shipping a single-purpose MCU and want a scheduler, FreeRTOS. If you are writing portable systems software that should move between Linux and deeply embedded targets, NuttX.

Zephyr is the third pole and increasingly the center of gravity. It is a full platform OS — a configurable kernel plus a device-tree-driven driver model, Kconfig, an enormous in-tree driver collection, and first-class connectivity (Bluetooth LE, Thread, Matter, full IP). It carries a partial POSIX subsystem but, unlike NuttX, POSIX is a compatibility layer rather than its founding standard. Its strength is breadth and vendor-neutral governance; its cost is a steeper learning curve (the West tool, device tree, a large build system) that the bare kernels do not impose.

A two-part landscape figure. The top is a stack comparison of three open RTOSes: FreeRTOS shown as a thin kernel layer with the application bringing its own drivers, file system and network stack; NuttX shown as a POSIX kernel with a built-in virtual file system, device drivers, network stack and shell, mirroring a small Linux; and Zephyr shown as a kernel plus a device-tree driver model, subsystems and a connectivity stack. The bottom is a positioning map with one axis from bare kernel to full POSIX OS and the other from permissive open source to certified commercial, placing FreeRTOS, SafeRTOS, ThreadX, NuttX, Zephyr, QNX, VxWorks and INTEGRITY. Figure 4 — Top: what each kernel actually ships in the box. Bottom: the same kernels placed by how much OS they are and how they are licensed and certified.

Which industries run which

RTOS selection in regulated industries is driven less by features than by certification evidence. A kernel that cannot supply a certification artifact package for the relevant standard is disqualified before its technical merits are even discussed.

IndustryCommon RTOSesGoverning standard
Automotive (ECU control)AUTOSAR Classic / OSEK, SafeRTOS, QNXISO 26262 (ASIL A–D)
Automotive (cockpit/ADAS)QNX, Linux, Android AutomotiveISO 26262, ISO 21434
Aerospace & defenseVxWorks, INTEGRITY, DeosDO-178C (DAL A–E), ARINC 653
Medical devicesSafeRTOS, INTEGRITY, QNX, ThreadXIEC 62304, FDA
Industrial / functional safetySafeRTOS, ThreadX, VxWorks, ZephyrIEC 61508 (SIL 1–4)
Consumer / wearables / IoTFreeRTOS, Zephyr, ThreadX, NuttX(typically uncertified)
RailVxWorks, INTEGRITY, QNXEN 50128

A few specifics worth knowing. In automotive control, the ECU world is the statically configured AUTOSAR Classic / OSEK runtime, while functional-safety MCUs frequently pair with SafeRTOS — the safety-certified sibling of FreeRTOS, with the same model and an independent certification pedigree. The digital cockpit is overwhelmingly QNX, a POSIX microkernel certified to ISO 26262 ASIL D and shipping in hundreds of millions of vehicles. In aerospace, VxWorks (Wind River, now part of Aptiv) has flown on Mars rovers and countless platforms, while Green Hills INTEGRITY owns the highest-assurance tier with its separation-kernel architecture and DO-178C DAL A evidence. In medical, the same certified names recur because the cost of certification, not the kernel, is the dominant expense.

A matrix figure mapping seven industries — automotive control, automotive cockpit, aerospace and defense, medical, industrial safety, consumer and IoT, and rail — against the RTOSes commonly deployed in each, with the governing safety standard called out per row: ISO 26262, DO-178C, IEC 62304, IEC 61508 and EN 50128. The certified commercial kernels cluster in the regulated rows and the permissive open kernels cluster in the consumer and IoT row. Figure 5 — The market splits cleanly: where a missed deadline can hurt someone, the certified commercial kernels dominate; where it cannot, the permissive open kernels do.

What changed in the last few years

The RTOS field has consolidated and re-aligned faster in the 2020s than in the two decades before. Five movements define the present:

  • Zephyr went from niche to default candidate. Backed by the Linux Foundation and a deep bench of silicon vendors — Nordic, NXP, STMicro, Intel, Renesas, Wind River and more — it now ships on a six-month cadence (the 4.x series through 2025–2026) with an enormous driver tree and Matter/Thread/BLE built in. A formal certification effort is bringing safety profiles to a project that began as a connectivity OS. For greenfield connected products, it is increasingly the first kernel evaluated rather than the alternative one.
  • A major commercial RTOS went permissive. Microsoft contributed Azure RTOS — the former Express Logic ThreadX — to the Eclipse Foundation as Eclipse ThreadX under the MIT license, completing the transition in 2024 and launching the ThreadX Alliance to sustain it. A small, fast, safety-pre-certified kernel with a mature middleware suite (NetX Duo, FileX, USBX, GUIX) becoming permissively licensed is a structural change in what teams can adopt for free.
  • FreeRTOS matured into a platform. Under AWS, it merged SMP into the mainline kernel, added MPU support, and put real weight behind Long-Term-Support releases with multi-year security maintenance — moving it from “the tiny kernel everyone starts with” to “the tiny kernel you can also ship and support for a decade.”
  • Arm exited. Mbed OS reaches end of life in July 2026; Arm has stopped active maintenance and pointed users to a community fork and to CMSIS-RTX. The shutdown of a vendor-backed RTOS accelerated the flow of mindshare toward the vendor-neutral projects, Zephyr chief among them.
  • POSIX became the portability lingua franca. NuttX under Apache — scaling to consumer volume through Xiaomi’s OpenVela — and Zephyr’s POSIX subsystem both reflect a broader pull: teams want application code that moves between Linux and deeply embedded targets without a rewrite. POSIX is how they get it.

Underneath all of it run the same currents: multicore reached the microcontroller, so SMP is now a kernel feature rather than a Linux luxury; security became table stakes, with secure boot, TF-M and an SBOM expected by default; and Rust started appearing in embedded codebases, with several kernels growing first- or second-class support. The throughline is that the RTOS is no longer just a scheduler — the market now expects a scheduler, a connectivity stack, a security story and a certification path, and the projects that bundle all four are the ones consolidating the field.

Field notes

  • Measure your worst case, do not estimate it. The whole value of an RTOS is a bounded latency. If you have not measured the worst-case response of your highest-priority task under full load, you have an RTOS but not a real-time system.
  • Priority inversion is a design error, not a rare event. Guard every shared resource with a mutex that has priority inheritance. A bare binary semaphore used as a lock is the Mars Pathfinder bug waiting to recur.
  • Size every stack, then watch the high-water mark. Per-task stacks are the RAM cost of an RTOS and the source of its most baffling crashes. Enable overflow checking in development and read the high-water mark before you ship.
  • An RTOS is not a substitute for a state machine. If your “tasks” are really one sequential process, you have added a scheduler to avoid writing a switch. Reach for concurrency because the problem is concurrent, not to avoid structure.
  • Choose the kernel for the obligation, not the demo. A weekend project picks the kernel that blinks an LED fastest. A product picks the one that can supply the certification artifact, the LTS guarantee, or the POSIX portability the next five years will demand. They are rarely the same kernel.