What is a real-time OS?
An RTOS gives you all the benefits of an operating system (threads, synchronization, memory management, hardware abstraction) but also allows you to enforce deadlines for functions so you can guarantee responsiveness. In an embedded system it’s common to only run a single “application” inside the operating system. Application-switching is usually not part of the RTOS feature set.
How does an RTOS relate to embedded systems?
An RTOS is the operating system of choice for most embedded systems. Listed below are some of the qualities an embedded system’s operating system should have and how an RTOS provides these qualities:
- An embedded system’s OS should be reliable because it is not shut down or rebooted often. An RTOS is designed to run indefinitely without rebooting.
- An embedded system’s OS should be light weight because it has limited resources and only kilobytes or megabytes of RAM. An RTOS consumes less memory than general purpose operating systems, such as Linux, Windows, and Mac OS.
- An embedded system’s OS should be time-critical because it needs to prioritize certain tasks over others to meet the timing requirements. An RTOS provides priority scheduling and preemption, the ability to suspend a task to complete a task of a higher priority.
Using an RTOS is necessary when the task becomes too complex for a state machine, or where multiple tasks should run in parallel. However, often it’s worth the effort to switch to an RTOS early, to make the code structure more intuitive. For example, a motor controller might have control input, power output, encoder feedback, and LED indication. You could write this all in a single loop that runs at 1kHz, using a counter variable to control the timing of the LED flashes. Or, you could use an RTOS and make three loops: One for input, one for output/feedback, and one for indication. The RTOS gives you the advantage that the LED timing is no longer dependent on the rate of the control loop, and each loop is now simpler and easier to debug. It’s also easier to add more features, such as ramp up/down or even additional motors.
What are some challenges in designing an RTOS?
There are two main challenges that occur when designing an RTOS: Timing and Scheduling. RTOS’s must meet strict timing requirements in order to meet the “real time” demands of the system. This means that the operation of the RTOS must be predictable and consistent. Predictability is acquired through a combination of Hardware, Software, and RTOS implementation. Consistency is maintained through the scanning of the environment surrounding the system.
There are two different scheduling paradigms used in RTOS: periodic and aperiodic. Periodic scheduling requires that a task be triggered within a specific interval of time. Aperiodic scheduling requires that a task be triggered through external stimulus. Another major challenge with scheduling is latency. There are two main forms of latency: interrupt and dispatch. Interrupt latency is the time between the arrival of the interrupt signal and the start of the interrupt routine. Dispatch latency is the time between the scheduler stopping one task and starting another.
How do I write software that is real-time?
- Provide a timeout for each function, or a method of guaranteeing that the function will execute within a certain amount of time. Think about what you want to happen if it takes too long – is there a safe value you can return if it fails? Is there some way of letting the application know that the function timed out? A function to read a digital pin value probably doesn’t need a timeout, but a function to receive user input definitely does, since it’s waiting on external input.
- You cut down on many unneeded features. The majority of microcontrollers don’t have a lot of space to work with, so you’ll need to write code that works with the bare essentials, i.e, scheduling logic, interrupt-driven code, etc.
- Reduce the frequency of memory allocations, and try to work with fixed-size structures. Because memory is very limited, dynamic memory allocation is considered bad practice. This means that all memory must be statically-allocated at compile time. FreeRTOS offers a comparison between memory allocation schemes.
- Ensure that your data processing can keep up with the data collection.
- There are two common design methodologies: Event-driven and time-sharing.
- Event driven is when process switching occurs on an event that’s higher priority than the current or queued events.
- Time-sharing is where the process switches on a regular interval, usually a regularly-timed interrupt.
What do you do if a function takes too long?
- Optimize the function to reduce processing time. Focus on functions that are called often or actions that happen inside a loop
- If the time is spent waiting, make sure your wait is non-blocking. It shouldn’t prevent other processes from happening.
- Consider using a queue in a producer-consumer pattern, so your data collection is decoupled from your data processing.
- Check your compiler flags, maybe you can increase the optimization level. In GCC, -Og is a good choice for debugging, but -Os will optimize for size and -O3 will optimize for speed.
- Consider using different datatypes. If your microcontroller’s FPU only supports single-floating-point, you may see a significant performance boost by switching away from double floating point. If there is no FPU at all, consider using fixed-point. The ARM CMSIS libraries have very efficient implementations for microcontrollers with DSP acceleration like the Cortex M4, M7, and M9.
- If you really don’t have enough processor time, consider using a more powerful processor, or even a hardware solution such as an FPGA.
Monolithic vs Microkernel RTOS
RTOSs’ come in many different flavors but one important differentiation between them is the amount of tasks the kernel handles. This can be broken up into two main groups:
- A monolithic kernel handles all system tasks inside kernel space (this includes file system, networking, device drivers etc.).
- A microkernel breaks up the kernels tasks and adds them as optional co-processing systems that can be ran in user space. This means that the kernel only contains the bare necessities for the OS to run. Things like file system operations and device drivers would not be inside the kernel.
Advantages and Disadvantages of a Monolithic RTOS
- One large OS binary increases system performance and complexity
- All services are ran in kernel space and create attack vectors for malicious code
- Adding or modifying services requires the complete recompilation of the OS
- Does not adhere to engineering principles of modularity as well as microkernels
- Service error can crash the entire system
Advantages and Disadvantages of a Microkernel RTOS
- Failure isolation when a service errors
- Modularity allows new system extensions to be added easily
- Smaller Footprint
- Less vulnerable as the attack surface is smaller
- OS overhead is higher, thus performance may take a hit
What are some common RTOS options I can try?
- FreeRTOS is available for many platforms.
- ChibiOS supports STM32 ARM boards and some AVR.
- Contiki OS is a unique option for that uses protothreads to reduce memory consumption, aimed towards lightweight IoT solutions.