A Real Time Operating System is an operating system that is optimized for use in embedded/real time applications. Their primary objective is to ensure a timely and deterministic response to events. An event can be external, like a limit switch being hit, or internal like a character being received.
A Real Time Operating System can provide many resources to application writers – including TCP/IP stacks, files systems, etc. The Kernel is the part of the operating system that is responsible for task management, and inter-task communication and synchronization. FreeRTOS is a real time kernel.
Real Time Scheduler and Real Time Kernel are sometimes used interchangeably. Specifically, the Real Time Scheduler is the part of the RTOS kernel that is responsible for deciding which task should be executing.
FreeRTOS is supplied as source code. The source code should be included in your application project. Doing so makes the public API interface available to your application source code.
When using FreeRTOS your application should be written as a set of independent tasks. This means your main() function does not contain the application functionality, but instead creates the application tasks, then starts the RTOS kernel.
You do not need to use an RTOS to write good embedded software. At some point though, as your application grows in size or complexity, the services of an RTOS might become beneficial for one or more of the reasons listed below. These are not absolutes, but opinion. As with everything else, selecting the right tools for the job in hand is an important first step in any project.
- Abstract out timing information : The real time scheduler is effectively a piece of code that allows you to specify the timing characteristics of your application – permitting greatly simplified, smaller (and therefore easier to understand) application code.
- Maintainability/Extensibility: Not having the timing information within your code allows for greater maintainability and extensibility as there will be fewer interdependencies between your software modules. Changing one module should not effect the temporal behavior of another module (depending on the prioritization of your tasks). The software will also be less susceptible to changes in the hardware. For example, code can be written such that it is temporally unaffected by a change in the processor frequency (within reasonable limits).
- Modularity: Organizing your application as a set of autonomous tasks permits more effective modularity. Tasks should be loosely coupled and functionally cohesive units that within themselves execute in a sequential manner. For example, there will be no need to break functions up into mini state machines to prevent them taking too long to execute to completion.
- Cleaner interfaces: Well defined inter task communication interfaces facilitates design and team development.
- Easier testing (in some cases): Task interfaces can be exercised without the need to add instrumentation that may have changed the behavior of the module under test.
- Code reuse: Greater modularity and less module interdependencies facilitates code reuse across projects. The tasks themselves facilitate code reuse within a project. For an example of the latter, consider an application that receives connections from a TCP/IP stack – the same task code can be spawned to handle each connection – one task per connection.
- Improved efficiency? Using FreeRTOS permits a task to block on events – be they temporal or external to the system. This means that no time is wasted polling or checking timers when there are actually no events that require processing. This can result in huge savings in processor utilization. Code only executes when it needs to. Counter to that however is the need to run the RTOS tick and the time taken to switch between tasks. Whether the saving outweighs the overhead or vice versa is dependent of the application. Most applications will run some form of tick anyway, so making use of this with a tick hook function removes any additional overhead.
- Idle time: It is easy to measure the processor loading when using FreeRTOS.org. Whenever the idle task is running you know that the processor has nothing else to do. The idle task also provides a very simple and automatic method of placing the processor into a low power mode.
- Flexible: interrupt handling Deferring the processing triggered by an interrupt to the task level permits the interrupt handler itself to be very short – and for interrupts to remain enabled while the task level processing completes. Also, processing at the task level permits flexible prioritization – more so than might be achievable by using the priority assigned to each peripheral by the hardware itself (depending on the architecture being used).
- Mixed processing requirements Simple design patterns can be used to achieve a mix of periodic, continuous and event driven processing within your application. In addition, hard and soft real time requirements can be met though the use of interrupt and task prioritization.
- Easier control over peripherals Gatekeeper tasks facilitate serialization of access to peripherals – and provide a good mutual exclusion mechanism.
FreeRTOS is a class of RTOS for embedded devices which is small enough to be run on 8/16-bit microcontrollers, although its use is not limited to these microcontrollers. It is a completely open-source and it’s code is available on github. If we know some basic concepts of RTOS, then it is very easy to use FreeRTOS because it has well-documented APIs which can be directly used in the code without knowing the backend part of the coding. Complete FreeRTOS documentation can be found here.