Use Embedder to move firmware from one RTOS to another on the same board. Embedder inspects the RTOS dependencies, plans the port with you, adapts one service at a time, and compares the result against the original firmware.
Start by defining the behavior the application must preserve: startup order, deadlines, data flow, recovery, and memory limits. The example on this page covers FreeRTOS to Zephyr. If the MCU or board also changes, use Platform migrations to track the hardware work alongside the RTOS port.
Prepare the migration
If you are new to Embedder, follow the Quickstart first. Open the firmware workspace, run /init to create or refresh EMBEDDER.md, and record these details in it:
- The source RTOS version, vendor SDK or fork, toolchain, and build configuration.
- The destination RTOS release, board target, required drivers, and middleware dependencies.
- The build, test, flash, and observation commands, including the connected board and its probe or port.
- Application interfaces, timing tolerances, RAM, flash, and power budgets, and any behavior changes you accept.
Confirm that the destination RTOS supports your exact board and the peripheral features you use, including DMA or asynchronous transfers. Provide the board revision, schematics, and relevant hardware documentation, and note any board or driver work the port needs.
Keep a reproducible source build and its firmware artifact, so you can rerun the original behavior at any point.
Capture the source behavior
In Act mode, ask Embedder to run the existing tests and a bounded hardware check before changing code:
Choose pass conditions for normal operation, peak load, and recovery from a failed peripheral or a timed-out request. Use the same workload and measurement method for both RTOS implementations.
Review the porting plan
Run /plan to switch to Plan mode. Ask Embedder to trace RTOS use through the codebase, including wrappers, middleware, interrupt handlers, build variants, and generated files. The plan should identify:
- Tasks, priorities, stacks, timers, synchronization, and shared-resource ownership.
- Blocking calls, timeouts, interrupt context, and scheduling assumptions.
- Startup, allocation, drivers, power management, and build configuration.
- Affected files, implementation order, checks for each stage, and unresolved dependencies.
Check which application interfaces stay stable and which change. Then approve the plan. Embedder switches to Act mode and starts implementing it. See Plan mode for the approval options.
Establish a bootable destination image and an observation path before moving dependent services.
Example: FreeRTOS to Zephyr
This example keeps the existing board and migrates a sensor application with a periodic acquisition task, a sample queue, and a UART reporting task. Replace the details and limits with your project’s requirements:
Establish the Zephyr application
Ask Embedder to prepare the target build for the selected Zephyr release and board target. Review CMakeLists.txt, prj.conf, any board overlay, and the workspace’s pinned dependencies. Zephyr uses Kconfig for software configuration and devicetree for hardware description. Follow the selected release’s application setup.
Start with a minimal image that boots and prints console output. Then enable the sensor bus and UART, checking pins, clocks, and device readiness.
To confirm the effective configuration, inspect the generated .config and zephyr.dts for the application image. A conventional single-image build places them under build/zephyr/. See Zephyr’s devicetree checks.
Review the behavior behind each API
Ask Embedder to explain each proposed replacement against the RTOS versions in your workspace. Check these areas:
- Tasks and priorities. Move task entry points to Zephyr threads and map their relative urgency explicitly. FreeRTOS uses larger numbers for higher priority. Zephyr uses smaller numbers, with negative values for cooperative threads and nonnegative values for preemptible threads. Include system threads in the priority review, and check time slicing and startup order. See FreeRTOS task scheduling and Zephyr threads.
- Stacks and allocation. Upstream FreeRTOS
xTaskCreate takes a stack depth in StackType_t elements, often called words; ESP-IDF uses bytes. Zephyr’s K_THREAD_DEFINE takes bytes. Use Zephyr’s stack-definition or stack-allocation APIs, then measure stack usage again under load. Check heap use, static allocation, and allocation-failure behavior too. See FreeRTOS task creation and Zephyr thread APIs.
- Queues and synchronization. A fixed-size sample queue may fit
k_msgq. Check item size, copy versus pointer ownership, capacity, return values, and full-queue behavior. Review mutex priority inheritance and notification or event-bit semantics separately before choosing replacements. See Zephyr message queues.
- Periods and timeouts. Preserve the acquisition task’s periodic deadline and overrun policy. Replacing a delay-until loop with a relative sleep after each iteration’s work can introduce drift. Convert tick-based waits deliberately, and check rounding, no-wait, and indefinite-wait behavior against the chosen API. See Zephyr kernel timing.
- Timers and interrupt handlers. FreeRTOS software timer callbacks run in a timer service task and must not block. Zephyr timer expiry functions run in interrupt context. Defer work that needs thread context to a suitable worker or thread. Audit every
FromISR call and critical section for the destination’s context rules. Zephyr treats kernel API use from zero-latency interrupts as undefined behavior. See FreeRTOS software timers, Zephyr timers, and interrupt handling.
- Deferred work. A shared workqueue can delay processing behind other work. Submitting a work item that is already queued doesn’t queue a second event. If every sample matters, keep samples in a queue or buffer and verify the consumer’s latency. See Zephyr workqueues.
- Drivers and middleware. Decide which existing code can stay behind the application interface and which should move to Zephyr drivers or subsystems. Check who owns interrupts, clocks, DMA, and the system tick before keeping vendor HAL initialization.
Port one complete data path
In Act mode, start with the path from sensor acquisition to UART output:
Bring over other services only after their dependencies work. Keep the original firmware build available until the destination passes the agreed checks.
Verify the migrated firmware
Build and flash the destination image on the confirmed board, then repeat the baseline tests. For the sensor example:
A successful build and boot don’t prove scheduling, timing, or recovery behavior. Verify those under load:
Record logging, instrumentation, and debugger settings that can affect the result. Test the ported subsystems together under expected peak load. Strict timing requirements may also need worst-case analysis.
Finish by updating EMBEDDER.md with the destination setup and verified commands. Record intentional behavior changes, remaining test gaps, and how to rebuild the source baseline before you retire the old RTOS configuration. Last modified on October 13, 2026