NOTES:
As the MBED simulator does not support the RTOS elements, we will need to do this in platformIO and test on the boards.
We also need to make a change to the platformio.ini file to ake sure the RTOS elements are incuded when compiling. If we add the line below, everything works.
build_flags = -D PIO_FRAMEWORK_MBED_RTOS_PRESENT
\clearpage
Our first multithreaded program
In this example we will write code to blink 2 LEDS.
One LED will be contrlled by the Main Loop The Second LED will have its own thread.
#include "mbed.h"
DigitalOut led1(LED1);
DigitalOut led2(LED2);
//Create an empty thread object ready to attach a function
Thread thread;
//Function to deal with blinking the second LED
void led2_thread() {
//Loop forever
while (true) {
led2 = !led2;
wait(1);
}
}
//Main Program
int main() {
//Attach the function to the Thread then Start it
thread.start(led2_thread);
while (true) {
led1 = !led1;
wait(0.5);
}
}
Lets break that down a bit:
The led2_thread
function is a seperate block of code that deals with blinking the second LED.
The main
function (remeber this is also a thread) contains code the flash the first LED.
What Happens when the code executes
- Main thread is created
- Spawns a second thread attached to the function
- Main thead is is Running
- Second thread is on Ready
Scheduler then allocates a time slice to each thread switiching between the threads every N time slices. Note the code here is very simple with only a few instructions per interation. It is likey that the code will execute within one time slice.
Therefore:
- Main Thread executes code untill it hits the
wait()
statement- Thread State changed to waiting
- Scheduler selects a thread from ready and moves it to Running
- Second thread runs till it hits the
wait()
statement- Thread state is chaged to waiting.
As it is probable that both threads are now waiting. Therefore there are no threads ready, and the system goes into low power mode.
When the timer for either threads wait
command is complete, the
thread is moved from waiting to ready, and can be selected by
the scheduler for execution
Approx Time | Thread 1 | Thread 2 | ||
---|---|---|---|---|
0 | Start | Running | Ready | |
0 | Thread 1 hits Wait | Waiting | Ready | |
0 | Scheduler | Waiting | Running | |
0 | Thread 2 hits wait | Waiting | Waiting | |
0-0.5 | Time Passes | Waiting | Waiting | |
0.5 | Thread 1 Wait finished | Ready | Waiting | |
0.5 | Scheduler | Running | Waiting | |
0.5 | Thread 1 hits wait | Waiting | Waiting | |
1.0 | Thread 2 Wait finished | Waiting | Ready | |
1.0 | Thread 1 Wait finished | Ready | Ready | |
1.0 | Scheduler... |
Task
Modify the code to blink all 4 LEDS
\clearpage
Revisiting the Interrupt
Process | Arrives At | Execute Time |
---|---|---|
A | 1 | 1 |
B | 2 | 5 |
C | 3 | 3 |
Example
Here we want to add state to the Threads. This is a basic form of message passing.
Here we add a global variable, buttonstate that can be upaded by our Interrupt routine. Therefore we just use the Interrupt routine to updat the state, avioding the problem of the routine takeing controll f the main execution.
#include "mbed.h"
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
//InterruptIn button(p12);
InterruptIn button(BUTTON1);
//Create an empty thread object ready to attach a function
Thread thread;
//And a Global Variable to hold state
int buttonState = 0;
//Function to deal with blinking the second LED
void led2_thread() {
while(true){
//for (int x=0; x<5; x++) {
if (buttonState){
for (int x=0;x<4;x++){
led2 = !led2;
wait(0.1);
}
buttonState = 0;
}
wait(0.1);
}
}
//Deal with Button Press
void handler(){
buttonState = !buttonState;
led3 = buttonState; //Debug with lights
}
//Main Program
int main() {
button.rise(&handler);
//Attach the function to the Thread then Start it
thread.start(led2_thread);
while (true) {
led1 = !led1;
wait(0.25);
//Debug with Light
led3=buttonState;
}
}
\clearpage
Sending Signals to Threads
#include "mbed.h"
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
//InterruptIn button(p12);
InterruptIn button(BUTTON1);
//Create an empty thread object ready to attach a function
Thread thread;
//Function to deal with blinking the second LED
void led2_thread() {
while(true){
//Wait on the Signal to be sent: Note Automatically cleared
Thread::signal_wait(0x01);
for (int x=0;x<4;x++){
led2 = !led2;
wait(0.25);
}
}
}
//Deal with Button Press
void handler(){
led3 = !led3;
thread.signal_set(0x01); //Send the signal (id 0x01) to the Thread
}
//Main Program
int main() {
button.rise(&handler);
//Attach the function to the Thread then Start it
thread.start(led2_thread);
while (true) {
led1 = !led1;
wait(0.25);
}
}
Threads and State Tasks
- Modify the Four threads example from before:
- Led1 Blinks Continuously
- On Button Press: Two things happen simultaneously
- Led2 Blinks 10 Times
- Led3 Blinks 20 Times
- After Led3 Finishes: LED4 Blinks 10 Times