Bare-metal vs RTOS programming

Bare-metal application

A bare-metal application, at its core, is just a big loop in the main function right after you have initialized the hardware/software at the device powerup/reset routines. All the execution is sequential logic, in other words, all instructions are executed in sequence unless interrupted by an interrupt service routine (ISR). So the only non-sequential logic you have in bare-metal programming makes use of exceptions.

In general, a bare-metal program is typically more power-efficient, uses less memory, and in some situations runs faster. For applications with simple to average complexity, it is a good enough solution to have one sequential logic in a loop. Especially considering bare-metal programs are more power-efficient and use less memory. However, your application can very easily get quite complex in terms of maintaining the architecture as sequential logic. This is where using a real-time operating system (RTOS) becomes advantageous.

RTOS-based application

Designing your application on top of an operating system allows you to have multiple concurrent logics in your application running in different execution units called threads, making your architecture simple, as opposed to just one sequential logic running in your main function in standalone mode.

The core of an RTOS is called the kernel and controls everything in the system. The other big added advantage is the huge resources of libraries, drivers, and protocol stacks that are natively available by an RTOS like Zephyr.

Interrupt Service Routines (ISRs) are available in both RTOS-based applications and bare-metal applications. They are generated asynchronously by the different devices drivers configured(including callback functions) and protocols stacks.

Visualization of bare-metal (left) and RTOS-based (right) application


Having the main() function is optional in Zephyr RTOS-based applications. This is because the main thread automatically spawned by the RTOS will do the necessary RTOS initialization, including scheduler/kernel setup, and core drivers setup.

After that, it will try to call the user-defined main(), if one exists. If no main() function exists, the main thread will exit. The system will still be functional and other threads can be scheduled normally.

Register an account
Already have an account? Log in
(All fields are required unless specified optional)

Forgot your password?
Enter your email address, and we will send a link to reset your password.