What is a Real Time Operating System (RTOS)?
What is a Real Time Kernel?
What is a Real Time Scheduler?
How do I use FreeRTOS?
How do I get started?
Why use an RTOS?
FAQ Top
This is not a quick question to answer. I will summarise briefly here. For more information see the fundamentals section of How FreeRTOS Works.
A Real Time Operating System is an operating system that is optimised 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.
Using a real time operating system allows a software application to be written as a set of independent tasks. Each task is assigned a priority and it is the responsibility of the Real Time Operating System to ensure that the task with the highest priority that is able to run is the task that is running. Examples of when a task may not be able to run include when a task is waiting for an external event to occur, or when a task is waiting for a fixed time period.
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 intertask communication and synchronisation. 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 kernel that is responsible for deciding which task should be executing and switching between tasks.
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 kernel. See the main.c and project files (makefile or equivalent) included with each port for examples.
Start with one of the preconfigured demo applications that comes included in the download. This will ensure that you are using all the correct compiler switches - which in some cases is very important. When this is operational you can modify the project files (makefile or equivalent) to include your own application tasks.
If you don't have any hardware then have a look at the Keil ARM7 port. This can be executed in the simulator supplied with the evaluation version of the Keil development tools.
Why use an RTOS?
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.
In brief:
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.
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 behaviour of another module (depending on the prioritisation 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).
Organising 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.
Well defined inter task communication interfaces facilitates design and team development.
Task interfaces can be exercised without the need to add instrumentation that may have changed the behaviour of the module under test.
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.
Using FreeRTOS.org 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 utilisation. 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 visa 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.
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.
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 prioritisation - more so than might be achievable by using the priority assigned to each peripheral by the hardware itself (depending on the architecture being used).
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 prioritisation.
Gatekeeper tasks facilitate serialisation of access to peripherals - and provide a good mutual exclusion mechanism.