A practical decision framework for embedded engineers and product teams โ grounded in real hardware decisions made at DigitalMonk across IoT, wearable, and industrial projects.
The RTOS selection you make in week one shapes memory architecture, debug tooling, power budgets, and certification pathways for the entire product lifecycle. Three DigitalMonk projects โ each with a different OS choice โ taught us why this decision deserves a proper framework.
Every embedded project eventually confronts the same early question: do we need an RTOS, and if so, which one? The honest answer is that this depends entirely on hardware constraints, team capability, concurrency demands, and how far the product needs to scale. There is no universal right answer โ but there are clearly wrong answers for specific contexts, and making the wrong call is expensive.
At DigitalMonk, we build across a range of silicon: nRF52840, ESP32, STM32L, RP2040, and occasionally more constrained targets like ATtiny. Across these platforms, we have shipped products running bare-metal C, FreeRTOS, and Zephyr RTOS. The framework below reflects what we actually learned โ including a case where we migrated from FreeRTOS to bare-metal midway through a wearable project because task overhead was consuming too much RAM on a 256kB device.
This article is not an academic comparison. It is the decision tree our engineers use internally, now made public. Our embedded software development services are built on this framework โ and the same thinking applies whether you are prototyping a single device or designing for 50,000-unit production.
The attributes that matter most in real selection decisions โ not synthetic benchmarks, but properties you feel on day 30 of a project.
| Attribute | Bare-Metal C | FreeRTOS | Zephyr RTOS |
|---|---|---|---|
| Minimum RAM footprint | ~0 kB overhead | ~8โ12 kB | ~20โ50 kB |
| Flash overhead | <1 kB | ~5โ10 kB | 50โ200 kB |
| Learning curve | Low | Medium | High |
| Deterministic timing | Excellent (ISR-controlled) | Good (tick-based) | Good (configurable) |
| Concurrency model | Manual state machines / cooperative | Preemptive tasks + queues | Preemptive + threads + fibers |
| BLE stack integration | Manual, fragile | Vendor-specific (Nordic SDK / nimble) | First-class (Zephyr BLE) |
| Power management | Full manual control | Tickless idle available | PM subsystem built-in |
| OTA update support | DIY bootloader required | Third-party (MCUboot) | MCUboot integrated |
| Safety certification path | Possible, high effort | SAFERTOS variant available | IEC 61508 in progress |
| Community & ecosystem | Vast (generic C) | Very large, mature | Growing fast (Linux Foundation) |
| Best target silicon | AVR, ATtiny, constrained M0+ | STM32, ESP32, Cortex-M3/M4 | nRF52/53/91, STM32 with BLE/LTE |
| Build system | Make / simple toolchain | CMake or IDE-integrated | CMake + West (opinionated) |
Scored 1โ10 across six critical dimensions. Higher is better. Scores reflect real project experience, not vendor documentation.
Work top-to-bottom. Stop at the first node that matches your project constraints. This is the actual decision tree our engineers use before writing a single line of application code.
Figure 1 โ DigitalMonk embedded RTOS decision flowchart. Original diagram. Green = Bare-Metal C, Red = FreeRTOS, Blue-teal = Zephyr RTOS.
Bare-metal is not the primitive fallback. For constrained, time-critical, or certifiable firmware, direct hardware control remains the cleanest architecture available.
With no scheduler overhead, interrupt service routines fire with sub-microsecond predictability. For hard real-time control loops โ motor PWM, sensor sampling at precise intervals, safety shutdown sequences โ nothing beats direct hardware register access.
When your target is an ATtiny84 with 512 bytes of SRAM, every byte is yours. No RTOS heap, no task stacks eating memory you cannot spare. Bare-metal lets you pack data structures right against hardware limits.
Entering and exiting sleep modes on exact clock cycles โ without waiting for a tick boundary โ is only achievable in bare-metal. Battery-operated sensors targeting multi-year battery life consistently win here.
On one industrial sensor node using STM32L011 (8 kB RAM, 64 kB Flash), an RTOS was simply impossible. We implemented a cooperative state machine with five states and a hardware timer. The result: 14-month battery life on two AA cells, zero task heap overhead.โ DigitalMonk Engineering Notes
The weakness of bare-metal becomes visible the moment you add a second concurrent concern. Managing BLE advertising while polling a sensor and feeding a UART protocol stack with manual state machines is maintainable at two tasks, chaotic at four, and unmaintainable at six. This is precisely the boundary where FreeRTOS earns its place.
FreeRTOS is the dominant RTOS in production embedded firmware for a reason. It is compact, portable, well-documented, and understood by nearly every embedded engineer hired in the last decade. Its memory model is explicit โ you allocate task stacks manually and choose from five heap implementations โ which means you always know exactly what memory is in use.
The concurrency primitives โ tasks, queues, semaphores, event groups, software timers โ cover the vast majority of real-world firmware requirements without demanding the full complexity of a modern OS. On an ESP32 development engagement, FreeRTOS is already the default scheduler baked into ESP-IDF, which means zero additional integration cost.
Where FreeRTOS shows its age is in the wireless stack layer. Native BLE support does not exist โ you depend entirely on vendor SDKs (Nordic's SoftDevice, Espressif's NimBLE-based stack) that sit beside the RTOS rather than inside it. For complex multi-protocol devices needing BLE + Thread + OTA simultaneously, this coupling becomes a source of subtle race conditions and priority inversion risks that are time-consuming to debug.
| FreeRTOS Feature | Notes | DigitalMonk Experience |
|---|---|---|
| Preemptive scheduler | Tick-based, configurable priority levels | Used on all multi-task ESP32 builds |
| Queues & mailboxes | Thread-safe inter-task communication | Primary IPC for sensor โ comms tasks |
| Software timers | Runs in timer task, not ISR context | Watch timer task stack size |
| Static allocation | No heap at all โ tasks in static buffers | Used for safety-sensitive sub-systems |
| Stream buffers | Lock-free single-producer/consumer | Excellent for UART DMA โ parse pipeline |
| POSIX layer (shim) | pthread compatibility available | Rarely needed; adds overhead |
Zephyr is not a stripped-down RTOS with a few drivers bolted on. It is a full embedded operating system with a Kconfig build system, a devicetree hardware abstraction layer, and first-class protocol stacks for BLE 5, Thread, Zigbee, LTE-M, and Wi-Fi. The Linux Foundation backs it. Nordic Semiconductor โ one of the most important silicon vendors in connected IoT โ ships Zephyr as their primary SDK for nRF devices.
For projects involving nRF52, nRF5340, or nRF9160 development, Zephyr is now the de facto standard. Nordic's nRF Connect SDK is a Zephyr distribution. OTA via MCUboot, BLE Mesh, Thread/Matter โ all available as modules with no integration work beyond Kconfig flags. This dramatically reduces firmware complexity for connected wearables, mesh sensor networks, and cellular IoT products. For Nordic teams specifically, our guide to choosing between nRF5 SDK and nRF Connect SDK covers the migration question, the real learning curve on Zephyr, and when each SDK is the right call.
The learning curve is real and significant. West (Zephyr's meta-tool), devicetree overlays, Kconfig dependency trees โ these take two to four weeks for an experienced embedded engineer to reach productivity with, and longer for juniors. But the return on that investment is substantial for any product that needs to evolve beyond a first feature set. Adding I2C sensor drivers, USB CDC, or a second BLE service becomes a configuration problem, not a coding problem.
On our Smart Golf Ball project โ nRF52840, BLE Mesh, 6-axis IMU, sub-5 ms shot detection latency โ we chose Zephyr because the BLE Mesh stack and IMU driver were both in-tree. What would have been 3 weeks of vendor SDK wiring became 4 days of Kconfig and devicetree configuration.โ DigitalMonk Engineering Notes
Each project had different constraints. The OS decision in each case was driven by the framework above โ not defaults, not familiarity bias.
nRF52840 SoC. BLE Mesh network between multiple balls. LSM6DSO IMU sampled at 833 Hz. Shot detection model running as a Zephyr workqueue item. OTA firmware updates via MCUboot. BLE Mesh and the IMU driver were both in-tree Zephyr modules โ zero custom wireless integration work. Target latency from impact to shot classification: under 5 ms. Achieved.
ESP32 managing three concurrent sub-systems: a coin acceptor state machine, a Raspberry Pi serial interface, and an MQTT telemetry stream over Wi-Fi. FreeRTOS tasks with prioritised queues kept coin event processing (hard deadline: 50 ms) isolated from the MQTT keepalive loop. Deployed at Jersey Airport. ESP-IDF's built-in FreeRTOS meant zero additional scheduler integration โ stack operational day one.
STM32L011 on 2ร AA batteries. 8 kB SRAM. Single-function: ultrasonic ranging every 60 seconds, LoRa packet transmission, sleep. A cooperative state machine with five states and a hardware timer drove everything. Firmware binary: 18 kB. Battery life target exceeded โ 14 months on a single cell pair at 4 ยตA average draw.
Beyond the flowchart, here is the engineering reasoning behind each decision node.
If available SRAM is under 32 kB and you cannot change the silicon, the answer is bare-metal. FreeRTOS typically needs 8โ12 kB for task stacks and scheduler structures before application code runs a single instruction. Zephyr needs substantially more. Know your numbers before any other decision.
BLE 5, Thread, Matter, LTE-M, or NB-IoT on Nordic silicon? Zephyr is the right answer. On ESP32 with Wi-Fi + BLE, FreeRTOS within ESP-IDF is mature and production-tested. Do not attempt to run BLE without an RTOS on any non-trivial product โ the event-driven nature of BLE does not map cleanly onto cooperative state machines.
One or two concerns sharing a simple time budget? Bare-metal with a super-loop is maintainable. Three or more concurrent tasks with different priorities and timing requirements? An RTOS task model pays for itself in reduced debugging time within the first two weeks of development.
If yes, and your budget is in months rather than quarters, use Zephyr (MCUboot integrated) or FreeRTOS on ESP32 (OTA partition scheme in ESP-IDF). Rolling a dual-bank bootloader in bare-metal is possible โ but it is a multi-week investment that rarely adds product differentiation.
Zephyr has a steep ramp. A team shipping their first RTOS project should choose FreeRTOS โ the documentation is better, examples more numerous, and the mental model simpler. A team that has shipped FreeRTOS products should learn Zephyr for any product targeting Nordic or Matter/Thread ecosystems.
SAFERTOS (a certified FreeRTOS derivative) is available for IEC 61508 and IEC 62443 certification paths. Zephyr's Linux Foundation governance and extensive code review make it the preferred base for products entering certification pipelines. Neither is a shortcut โ but both are better starting points than a homegrown scheduler.
We have been called into projects mid-flight where the RTOS decision was wrong. The rework is predictable and expensive.
| Migration Scenario | Typical Effort | Primary Pain Points | Risk Level |
|---|---|---|---|
| Bare-Metal โ FreeRTOS | 2โ4 weeks | Restructuring ISR-driven code into tasks; stack sizing; heap design | Medium |
| Bare-Metal โ Zephyr | 4โ8 weeks | Devicetree re-mapping all peripherals; West build system; BLE re-integration | High |
| FreeRTOS โ Bare-Metal | 1โ3 weeks | Collapsing tasks into cooperative state machines; eliminating heap dependencies | Medium |
| FreeRTOS โ Zephyr | 3โ6 weeks | API mapping; devicetree port; build system change; BLE stack re-integration | High |
| Zephyr โ FreeRTOS | 4โ8 weeks | Losing BLE/Thread stack; manual driver replacement; losing MCUboot integration | Very High |
The asymmetry matters: migrating from a simpler OS to a more complex one costs significantly less than the reverse. This is one reason we lean toward starting slightly over-specified (FreeRTOS over bare-metal, for example) when the project roadmap suggests feature growth โ the rework cost of under-specifying is higher than the cost of the extra overhead.
The embedded software stack that ships a product reliably on time is the right stack. Bare-metal C is not a compromise โ it is the optimal choice for constrained, single-purpose, battery-critical devices. FreeRTOS is not bloat โ it is a production-proven scheduler that has shipped billions of devices. Zephyr is not over-engineering โ it is the right foundation for any product targeting Nordic silicon, Matter, or multi-protocol wireless in 2025 and beyond.
The framework above gives you a starting position. Experienced firmware engineers will diverge from it based on team-specific knowledge and silicon availability โ and that is correct. What matters is that the decision is made consciously and early, with migration costs explicitly acknowledged as a risk in the project plan.
At DigitalMonk, our embedded software development services begin with a hardware and software architecture review precisely to answer this question before a single line of application code is written. Whether you are building on ESP32 or targeting Nordic nRF silicon, the OS decision is one of the highest-leverage choices in the project โ and it deserves more than a default answer.
Our engineers have shipped bare-metal, FreeRTOS, and Zephyr firmware across dozens of production products. Let's review your requirements and give you a direct recommendation โ no sales cycle.
Talk to an embedded engineer โHire ESP32 DeveloperHire nRF Developer