What is a Real-Time Operating System (RTOS)?
2021-01-04 | By ShawnHymel
License: Attribution Arduino
A real-time operating system (RTOS) is an operating system (OS) (often a lightweight OS) that runs multi-threaded applications and can meet real-time deadlines. Most RTOSes include a scheduler, resource management, and device drivers. Note that when we talk about “deadlines,” we do not necessarily mean “fast.” Instead, meeting deadlines indicates a level of determinism, meaning we can figure out when certain tasks will execute prior to runtime.
In this series, we will cover various RTOS concepts and demonstrate them using an ESP32 and with the Arduino IDE. This information will be covered in a series of videos. Most videos will end with a challenge we encourage you to try. Solutions to these challenges will be provided on these Maker.IO pages.
General Purpose Operating System vs. Real-Time Operating System
Often, when we think of “operating systems,” we think of things like Windows, macOS, and Linux. These are examples of general purpose operating systems (GPOS). Most often, these operating systems are designed for user interaction and provide some kind of interface, whether that’s a command line interface (CLI) or graphical user interface (GUI). They are also designed to run multiple applications, often with multi-threading, and offer other benefits like resource/file management and device drivers.
Because user interaction is usually the main focus for GPOS design, some latency is acceptable (so long as users don’t notice a long lag time). As a result, exact task deadlines are hard (if not impossible) to predict in a GPOS.
Contrast this to an RTOS. Most RTOSes are designed to run on microcontrollers. As a result, they can often forgo complex user interfaces (e.g. no command line or GUI) in order to accomplish a few tasks at a time without needing to handle user input. Additionally, applications written for microcontrollers may have strict timing deadlines that need to be met, such as firing a spark plug every so many milliseconds, controlling a medical device to keep someone alive, and fire thrusters on a satellite at a precise time to stay in orbit.
Many RTOSes also come with resource management libraries, such as the ability to read and write to files, as well as low-level device drivers, such as WiFi and Bluetooth stacks and LCD drivers. Note that device drivers in an RTOS are usually much simpler than those found in an GPOS, as microcontrollers are not usually asked to do things like control graphics cards!
Super Loop vs. Multi-threaded Application
If you’ve written an embedded application before (including something for Arduino), you’re probably familiar with the super loop architecture (also known as “bare-metal programming”). Here, there is no operating system, and the structure is fairly simple: in your main() function, you set up any variables, drivers, libraries, etc. and then perform one or more periodic tasks in a while(true) loop. In Arduino, this is embodied by the setup() and loop() functions (which are just functions called from main() in the Arduino library).
There is nothing wrong with the super loop application. In fact, it’s still one of the most popular ways to program a microcontroller, as it’s easy to implement and easy to debug. You can even add in interrupts by using interrupt service routines (ISRs) that cause the program to halt and execute some arbitrary code when an external event occurs (such as a timer expiring or a button being pushed).
If you have multiple tasks to accomplish during the main loop, you generally execute them in a round-robin fashion. The problem comes in when you start adding so many tasks that some start missing deadlines or preventing other features from working. This is where an RTOS can help. Rather than execute everything in a round-robin fashion, you can essentially execute everything concurrently.
You can still have interrupts--they would halt whatever task was being run at the moment to execute the ISR and then return execution to the task.
Note that there is some terminology that can get confusing here:
- A task is a set of instructions loaded into memory. It can also mean some unit of work or goal that needs to be accomplished.
- A thread is a unit of central processor (CPU) utilization with its own program counter and stack memory.
- A process is an instance of a computer program. A process may have multiple threads. Most embedded programs are written as a single process, but a GPOS usually has many processes running at the same time.
In FreeRTOS, these terms can get murkier. FreeRTOS uses the term “task” to mean “threads.” As a result, you will often see these terms used interchangeably, especially in the FreeRTOS documentation. In this series of videos and posts, I will stick to the FreeRTOS practice of calling units of CPU utilization “tasks,” but know that they are analogous to “threads” in other frameworks (e.g. POSIX).
So, we get to the ultimate question: should you use an RTOS? The answer is "yes" if you need to run multiple tasks/threads on your microcontroller to accomplish your goals. The ability to meet real-time deadlines may or may not be important depending on your needs. If you don’t need multi-threading, it’s best to stick to the super loop architecture, as it’s much easier to debug.
If you need multi-threading support, an RTOS also has several other benefits. Namely, it allows you to modularize your code more easily, as tasks can be written separately. If you are working on a team, individual tasks can be assigned to different team members to allow concurrent development. Note that there will still be debugging at the end to ensure everything is integrated correctly.
RTOS Requirements
An RTOS does require some overhead, as a background task (the scheduler) needs to be run on a regular basis to switch tasks. This takes up memory and some CPU cycles. As a result, many RTOSes have minimum clock speed and memory requirements.
While you can technically run a number of different RTOSes on an Arduino UNO (ATmega 328p), the overhead for the scheduler is so great that you’re not left with many resources for your own application. Because of this, many 8- and 16-bit microcontrollers are best used with the simpler super loop (bare metal) architecture.
As you begin using more powerful 32-bit microcontrollers with faster clocks (e.g. over 20 MHz) and more memory (e.g. over 32 kB RAM), you will have more resources available to run RTOSes. Note that these are not hard requirements--different RTOSes require different amounts of resources.
In this series, we will use the ESP32, which has a 240 MHz clock, 512 kB of RAM, and 2 cores. Because it was designed as an Internet of Things (IoT) system, the ESP32 benefits from an RTOS. In fact, the Arduino version of the ESP32 supports FreeRTOS out of the box (a modified version, to be precise). The WiFi and Bluetooth stacks alone necessitate an RTOS, as they must run concurrently with the user application so they can respond to network requests in the requisite amount of time.
According to a 2018 survey by the Eclipse Foundation, Linux was still the most popular operating system for IoT devices. However, note that Linux is a full GPOS, even if it’s being used in a lightweight manner. Additionally, it usually requires a full microprocessor (not a microcontroller) to run.
After Windows (another GPOS), we see that FreeRTOS was the most popular RTOS. Close behind that was bare-metal programming (super loop). The rest do not seem to compare to the popularity of these 4. That being said, I recommend keeping an eye on the Zephyr Project, as it’s a newcomer to the RTOS field, and it’s backed by the Linux Foundation.
An RTOS can be a powerful tool if you’re creating complex embedded programs. They help you separate tasks and give you the ability to run them concurrently (or appear to run concurrently). You can set prioritization levels of tasks in most RTOSes, which allow some tasks to interrupt and run before other tasks. This is known as “preemption.”
If you need concurrency or are getting into deeper embedded concepts like IoT or machine learning, I encourage you to add RTOSes and multi-threaded programming to your toolkit!
Recommended Reading
If you’d like to dig deeper into FreeRTOS and RTOSes in general, I recommend checking out these great articles:
- FreeRTOS slide presentation: http://www.lirmm.fr/~bosio/HMEE209/06 - freertos.pdf
- FreeRTOS book and reference manual: https://www.freertos.org/Documentation/RTOS_book.html
- “What is an RTOS?” article: https://www.freertos.org/about-RTOS.html
- RTOS: https://www.guru99.com/real-time-operating-system.html
- Introduction to RTOS - Solution to Part 2 (FreeRTOS)
- Introduction to RTOS - Solution to Part 3 (Task Scheduling)
- Introduction to RTOS - Solution to Part 4 (Memory Management)
- Introduction to RTOS - Solution to Part 6 (FreeRTOS Mutex Example)
- Introduction to RTOS - Solution to Part 7 (FreeRTOS Semaphore Example)
- Introduction to RTOS - Solution to Part 8 (Software Timers)
- Introduction to RTOS - Solution to Part 9 (Hardware Interrupts)
- Introduction to RTOS - Solution to Part 10 (Deadlock and Starvation)
- Introduction to RTOS - Solution to Part 11 (Priority Inversion)
- Introduction to RTOS - Solution to Part 12 (Multicore Systems)
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum