Reconfigurable computing
Small Embedded Systems
Unit 5.8 Real Time Operating Systems
Our Example System
In the last unit we looked at this system:
This simple example could (probably) be done satisfactorily with interrupts,
But as the tasks increase in number, interrupts become problematic
Task1(){
take_reading1();
compute_response1();
output_response1();
}
Task2(){
take_reading2();
compute_response2();
output_response2();
}
Time
Waiting
Active
Task 1
Task 2
Real Time Operating Systems
Real time operating system (RTOS) is OS that switches between tasks (threads) in a way designed to maximise chance of all real time tasks hitting their deadlines
Commonly RTOSs are very lightweight and do not provide most of the services provided by “normal” operating systems (file management, device drivers, memory protection, …)
They focus on
Fast switches between tasks
Fast interrupt handling
Predictable response time
Making intelligent choices as to which task should be switched into the processor when
RTOS scheduling
The RTOS tells a task when it can start
Tasks that have no further computation to do yield, and inform the RTOS of when they want to be re-started
RTOS
task1(){
take_reading1();
compute_response1();
output_response1();
yield (100);
}
Start
Yield
task2(){
take_reading2();
compute_response2();
output_response2();
yield (175);
}
Start
Yield
Time
Task 1
Task 2
Idle Task
Scheduling conflicts
What happens if we have two tasks that want the processor at the same time?
All RTOS tasks have an assigned priority
We’ll see later how priorities are decided
Time
Task 1
Task 2
Idle Task
Task Priority
If task 2 has a higher or equal priority,
It keeps the processor and task 1 will have to wait
If task 1 has higher priority:
task 2 is swapped out and task 1 takes over;
task 2 resumes when task 1 has finished
this is called pre-emption
Task 2 has been pre-empted by task 1
Time
Task 1
Task 2
Idle Task
Task 1 has higher priority
Time
Task 1
Task 2
Idle Task
Task 2 has higher or equal priority
Task States
Each tasks can be in one of 4 states:
Running
Single core processor can have only one running task
Ready
Ready to execute, but processor is currently busy with some other task whose priority is higher or equal
Blocked
Cannot execute until some event happens, e.g.
Waiting for a period of time to go by
Waiting for a resource (e.g. UART) to become available
Suspended
Time slicing
Time is divided into some quantum: “ticks”
Set by programmer: default is typically about 10 ms
In order to ensure fair allocation of processor time, RTOS will time slice tasks of equal priority
If a task has been running for a set number of tick periods, at the next tick the RTOS will look for another ready task of the same priority
If it finds such a task, the original task is swapped out and sent to the back of the queue of ready tasks
Real Time Operating Systems
RTOSs vary in complexity, power, memory footprint, type of computer system they run on, etc.
High end systems:
QNX
VxWorks
Low end microcontroller systems:
FreeRTOS (many microcontroller platforms)
Keil RTX5 (ARM Cortex-M microcontrollers)
Many RTOSs have versions that are adapted for safety critical systems and are safety certified
In our code examples we will use FreeRTOS
Using FreeRTOS with Arduino
We’ll look at a simple example with 2 tasks:
Task 1 blinks the LED on pin 1
Task 2 blinks the LED on pin 13
This will work easily on the Atmega328P-based boards
Uno, Nano, …
The ESP8266 is a lot more complicated to use
The procedure is:
Include the Arduino_FreeRTOS library and its headers
Define the individual tasks
Register the tasks with the RTOS (in setup() function)
Start the RTOS scheduler (in setup() function)
A FreeRTOS Task
A FreeRTOS task is a function
The task must be an inifinite loop that never terminates
vTaskDelay causes the task to block until a time delay has expired
The time units are “ticks”. To convert to milliseconds we use the constant portTICK_PERIOD_MS (defined in FreeRTOS header file)
#define LED1 1
void flashLED1() {
while(1) {
digitalWrite(LED1, !digitalRead(LED1));
vTaskDelay(1000/portTICK_PERIOD_MS);
}
Block for 1 sec
Flip LED1
Infinite loop
A FreeRTOS Task
Now we have our two tasks
LED1 blinks every 1 second; LED2 blinks every 1.5 s
#define LED1 1
#define LED2 13
void flashLED1() {
while(1) {
digitalWrite(LED1, !digitalRead(LED1));
vTaskDelay(1000/portTICK_PERIOD_MS);
}
void flashLED2() {
while(1) {
digitalWrite(LED2, !digitalRead(LED2));
vTaskDelay(1500/portTICK_PERIOD_MS);
}
Registering and Scheduling Tasks
This is how the setup() and loop() look
loop() is an empty function (but it has to be there for the Arduino environment to work)
#include
void setup() {
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
xTaskCreate(flashLED1, “LED1”, 128, NULL, 1, NULL);
xTaskCreate(flashLED2, “LED2”, 128, NULL, 1, NULL);
vTaskStartScheduler();
}
void loop(void) {
}
Registering and Scheduling Tasks
A task is registered with RTOS by xTaskCreate
Task needs a priority (higher number is higher priority)
Task needs to allocated a stack size
If this is too small stack overflow may occur
If it is too big, program may not fit into RAM
xTaskCreate(flashLED1, “LED1”, 128, NULL, 1, NULL);
Name of the function that implements the task
Stack size (words)
Priority
Pointer to parameters
Task handle
Text name for task for print out to debugger
Registering and Scheduling Tasks
We have given the two tasks the same priority
Once the tasks are registered, we start the scheduler
#include
void setup() {
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
xTaskCreate(flashLED1, “LED1”, 128, NULL, 1, NULL);
xTaskCreate(flashLED2, “LED2”, 128, NULL, 1, NULL);
vTaskStartScheduler();
}
void loop(void) {
}
Summary
Real time systems must produce a correct response by a deadline
Multiple tasks (threads) running on one processor require careful scheduling to ensure all deadlines are met
Real time operating systems (RTOSs) are designed to perform scheduling of tasks to maximise chances of hitting deadlines
We have looked at some basic FreeRTOS examples
/docProps/thumbnail.jpeg