FreeRTOS vs Zephyr: How to Choose an RTOS for a Connected Sensor
Flux, the AI hardware engineer, writes the firmware for this kind of device on either RTOS. Tell Flux to use FreeRTOS or Zephyr, and it sets up the tasks, queues, timers, and interrupts, maps each pin and peripheral to the nets in your schematic, builds the firmware, and reports flash and RAM use. It also sets up signed OTA updates with two firmware slots and rollback. The firmware stays in step with the schematic, the PCB, and the enclosure in the same project.
FreeRTOS vs Zephyr comes down to how much of the system you want the RTOS to supply. FreeRTOS is a small, MIT-licensed scheduler kernel: tasks, queues, semaphores, and software timers. You add it to the vendor SDK of your microcontroller, and the SDK supplies the drivers and the radio stack. Zephyr is a complete RTOS from the Linux Foundation, under the Apache 2.0 license. It brings its own drivers, devicetree hardware description, Bluetooth and IP networking, a build system, and an OTA bootloader.
So the hardware decides. If the chip vendor's SDK is built on FreeRTOS, use FreeRTOS. If the chip vendor's SDK is built on Zephyr, or the product needs Bluetooth, networking, and signed updates across more than one board, use Zephyr. Below, one connected sensor is worked through both ways so you can see where each choice comes from.
The example: a battery-powered environmental sensor
The device is a wall-mounted sensor for a building-monitoring product:
- A BME280 temperature, humidity, and pressure sensor on I2C, read once every 30 seconds.
- An accelerometer with an interrupt pin that wakes the device when someone removes it from the wall.
- A Bluetooth Low Energy link to a gateway. A second product variant uses Wi-Fi.
- Two AA cells, with a battery-life target of two years.
- Signed over-the-air (OTA) updates with rollback, because nobody opens 2,000 enclosures to reflash them.
- A molded enclosure with a PCB antenna that needs a keep-out zone at the board edge.
The firmware has the same three jobs on either RTOS:
- Sensor task: wake on a timer, read the BME280, and put the reading in a queue.
- Radio task: take readings from the queue and send them, then let the radio sleep.
- Tamper interrupt: wake on the accelerometer pin and send an alarm at once.
FreeRTOS vs Zephyr at a glance
The sensor on FreeRTOS
With FreeRTOS, you write the task structure yourself and call the vendor SDK for the I2C driver and the radio. The
sensor task uses vTaskDelayUntil() so the 30-second period does not drift, and it hands each reading
to the radio task through a queue:
The tamper interrupt puts a message with tamper = true at the front of the same queue with
xQueueSendToFrontFromISR(). The radio task wakes and sends the alarm before the next reading. For low
power, you enable tickless idle with configUSE_TICKLESS_IDLE so the core sleeps between ticks, and the
vendor port puts the chip in its deepest sleep mode that keeps the timer running.
This is the shortest path on the Wi-Fi variant. The ESP32 family's ESP-IDF already runs FreeRTOS, its Wi-Fi stack and OTA component run as FreeRTOS tasks, and the code above is what an ESP-IDF application looks like. The cost: the BME280 driver, the pin assignments, and the update flow are your code, tied to one vendor's SDK. If the next product uses a different chip, you rewrite those parts.
The sensor on Zephyr
With Zephyr, you describe the hardware and enable the features, and the RTOS supplies the driver. The BME280 goes in a devicetree overlay for the board:
The features go in prj.conf:
The bootloader goes in sysbuild.conf:
The application reads the sensor through the generic sensor API, so the same code works with another supported sensor:
The radio thread takes values from readings and updates a GATT characteristic. When every thread
sleeps, the power management subsystem puts the SoC in its low-power state. With sysbuild,
west build --sysbuild builds MCUboot with the application, signs the application image, and puts two
image slots in the board's flash partitions. After an update, the new image confirms itself with
boot_write_img_confirmed(). If it does not, MCUboot goes back to the previous image at the next reset.
This is the shortest path on the BLE variant with a Nordic nRF52840 or nRF54 part. The nRF Connect SDK is built on
Zephyr, so the Bluetooth stack, power management, and update flow come from the same tree. The cost is the learning
curve: devicetree, Kconfig, and west are three new tools for an engineer who knows only a vendor IDE,
and the image is larger than a bare FreeRTOS kernel.
Compare memory with a real build, not a datasheet
The FreeRTOS kernel is small, but the kernel is not the firmware. A connected sensor also carries a radio stack, a TLS or BLE security layer, a sensor driver, and a bootloader. On both RTOSes, the radio stack usually uses most of the flash and RAM. Compare the two choices on the same features:
- Build both versions for the target with BLE or Wi-Fi, the sensor, low power, and OTA enabled.
- Read the flash and RAM totals from the linker map, and list the largest symbols.
- Check the result against the part's flash after you reserve the second OTA slot. Two slots halve the space for the application.
- Check the stack size of each task under the worst case, for example during a BLE connection and a sensor read at the same time.
Zephyr gives you west build -t rom_report and ram_report for this. On FreeRTOS, read the
map file from the SDK build and check stack use with uxTaskGetStackHighWaterMark().
How the hardware picks the RTOS
How Flux writes the firmware for either RTOS
The RTOS choice depends on the schematic, and the schematic depends on the enclosure, the antenna, and the battery. In Flux, all of them are in one project, and you ask the agent for the firmware with the hardware it runs on:
- Tasks, queues, and timers on either RTOS. Tell Flux to set up FreeRTOS or Zephyr, or bare-metal timer interrupts, with the task priorities and data flow you need. It writes the firmware starter document with the microcontroller, framework, build system, and libraries.
- A pin map from the schematic. Flux maps the I2C bus, the interrupt pin, and the boot pins from the schematic nets, and names each firmware define after its net. When you move a pin, it updates the map and the source.
-
Real builds and memory reports. Flux compiles for ARM, RISC-V, ESP32-class, nRF, RP2040, AVR,
and STM32 targets. It returns
.elf,.bin,.hex, and.mapfiles, reports flash and RAM use, and lists the largest symbols. That is the memory comparison above, in minutes. - Host unit tests before the board arrives. Flux runs tests for the sensor conversion and the message format without hardware, and writes a CI workflow that builds and tests every change.
- OTA with rollback. Flux adds a bootloader with two firmware slots, signed images, rollback, and the update flow in the app or the cloud.
- Battery life from the power budget. Flux sets the sleep mode, the wake sources, and the duty cycle, then estimates battery life from the power budget.
- Mechanical values in firmware. Flux reads the sensor position and the enclosure dimensions from the mechanical model and adds them as named firmware constants. When the enclosure changes, it updates them.
Prompts like these do the work in a Flux project:
- “Use Zephyr for this nRF52840 sensor. Read the BME280 every 30 seconds, send it over BLE, wake on the accelerometer interrupt, and add MCUboot OTA with rollback.”
- “Set up FreeRTOS tasks on this ESP32-S3 board for sensor sampling and Wi-Fi, with the sensor readings in a queue. Build it and report flash and RAM use.”
- “Estimate battery life on two AA cells for this firmware. Show the active time, sleep current, and wake sources.”
- “Move the antenna keep-out to the top edge of the enclosure, update the board outline, and keep the firmware pin map in step with the new schematic.”
Without Flux, an RTOS evaluation takes a week or two: one engineer ports the sensor to two SDKs, another changes the board, and the enclosure waits. In Flux, the agent builds both versions, reports the numbers, and keeps the schematic, PCB, enclosure, and firmware in the same project in a few hours. Read more about electronics design in Flux and the firmware docs. For the chip choice that comes before the RTOS, read STM32 vs ESP32.
Open a project and tell Flux what the sensor must do. It writes the firmware for the board and the enclosure you design with it.
FAQs
FreeRTOS is a small scheduler kernel that you add to a vendor SDK, which supplies the drivers and the radio stack. Zephyr is a complete RTOS with its own drivers, devicetree hardware description, Kconfig configuration, Bluetooth and IP networking, a CMake and west build system, and MCUboot for OTA updates.
Neither is better for every device. Zephyr is the faster path for a Bluetooth sensor on a Nordic part, or a product line on several MCU families. FreeRTOS is the faster path on an ESP32 with ESP-IDF, on an STM32 with an existing STM32Cube codebase, or on a small MCU with tight flash.
The FreeRTOS kernel alone is typically 6 to 12 KB of flash, and a Zephyr image includes the drivers and subsystems you enable, so a minimal Zephyr build is larger. In a connected sensor, the radio stack and the bootloader use most of the memory on both. Build both versions with the same features and compare the linker map.
Yes. ESP-IDF, the Espressif SDK, runs on FreeRTOS. Zephyr also supports many ESP32 parts upstream. For a Wi-Fi product that uses the ESP-IDF Wi-Fi stack and OTA component, FreeRTOS is the shorter path.
Yes. Tell Flux which RTOS to use and how the tasks work together. Flux sets up tasks, queues, timers, and interrupts on FreeRTOS or Zephyr, maps the pins from your schematic, builds the firmware, and reports flash and RAM use. It can also add OTA updates with rollback and estimate battery life from the power budget.
Related Content
Let’s start building.
Let’s build your idea together. All you need to do is describe what you want to make, or what problem you want to solve. Flux will work with you to make it a reality.