Download as pdf or txt
Download as pdf or txt
You are on page 1of 24

Question 1

Run the following code!

The three LEDs are blinking synchronously  .

After leaving the non-existing state, the three tasks keep moving between
3

 states (write a number).

#include <Arduino_FreeRTOS.h>
const int red_led_pin = 6;
const int blue_led_pin = 4;
const int green_led_pin = 2;

TaskHandle_t Handle_of_red_task, Handle_of_blue_task, Handle_of_green_task;


void setup() {
xTaskCreate(blinkRedLED, "BLINKING RED LED", 128, NULL, 1, &Handle_of_red_task);
xTaskCreate(blinkBlueLED, "BLINKING BLUE LED", 128, NULL, 1, &Handle_of_blue_task);
xTaskCreate(blinkGrreenLED, "BLINKING GREEN LED", 128, NULL, 1, &Handle_of_green_task);
}
void loop() {}
void blinkRedLED (void *pvParameters) {
pinMode(red_led_pin, OUTPUT);
while (1) {
digitalWrite(red_led_pin, digitalRead(red_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void blinkBlueLED (void *pvParameters) {
pinMode(blue_led_pin, OUTPUT);
while (1) {
digitalWrite(blue_led_pin, digitalRead(blue_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}

void blinkGrreenLED (void *pvParameters) {


pinMode(green_led_pin, OUTPUT);
while (1) {
digitalWrite(green_led_pin, digitalRead(green_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
They move between Running, Ready, and Blocked.

They go to the state blocked due to calling the function vTaskDelay.


Question 2

The code below is almost the same like the previous one.
I just replaced vTaskDelay(pdMS_TO_TICKS(500)); with delay(500);
Run the code!
What do you observe?

The three LEDs are blinking synchronously  .

After leaving the non-existing state, the three tasks keep moving between
2

 states (write a number).


#include <Arduino_FreeRTOS.h>
const int red_led_pin = 6;
const int blue_led_pin = 4;
const int green_led_pin = 2;
TaskHandle_t Handle_of_red_task, Handle_of_blue_task, Handle_of_green_task;
void setup() {
xTaskCreate(blinkRedLED, "BLINKING RED LED", 128, NULL, 1, &Handle_of_red_task);
xTaskCreate(blinkBlueLED, "BLINKING BLUE LED", 128, NULL, 1, &Handle_of_blue_task);
xTaskCreate(blinkGrreenLED, "BLINKING GREEN LED", 128, NULL, 1, &Handle_of_green_task);
}
void loop() {}
void blinkRedLED (void *pvParameters) {
pinMode(red_led_pin, OUTPUT);
while (1) {
digitalWrite(red_led_pin, digitalRead(red_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void blinkBlueLED (void *pvParameters) {

pinMode(blue_led_pin, OUTPUT);
while (1) {

digitalWrite(blue_led_pin, digitalRead(blue_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void blinkGrreenLED (void *pvParameters) {
pinMode(green_led_pin, OUTPUT);
while (1) {
digitalWrite(green_led_pin, digitalRead(green_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
They move between Running and Ready.

They don't go to the state blocked because vTaskDelay is not used.


Question 3

Now insert the line vTaskPrioritySet(NULL, 2); directly after the line marked blue in the code below.
Run the code!
What do you observe?

Only the bluesLED is blinking  .

Replace vTaskPrioritySet(NULL, 2); with vTaskPrioritySet(Handle_of_blue_task, 2);


Run the code!
What do you observe?

Only the blue LED is blinking  .

Replace vTaskPrioritySet(Handle_of_blue_task, 2); with vTaskPrioritySet(Handle_of_red_task, 2);

Run the code!


What do you observe?

Only the red LED is blinking  .

#include <Arduino_FreeRTOS.h>
const int red_led_pin = 6;
const int blue_led_pin = 4;
const int green_led_pin = 2;
TaskHandle_t Handle_of_red_task, Handle_of_blue_task, Handle_of_green_task;
void setup() {

xTaskCreate(blinkRedLED, "BLINKING RED LED", 128, NULL, 1, &Handle_of_red_task);


xTaskCreate(blinkBlueLED, "BLINKING BLUE LED", 128, NULL, 1, &Handle_of_blue_task);
xTaskCreate(blinkGrreenLED, "BLINKING GREEN LED", 128, NULL, 1, &Handle_of_green_task);
}
void loop() {}
void blinkRedLED (void *pvParameters) {
pinMode(red_led_pin, OUTPUT);
while (1) {
digitalWrite(red_led_pin, digitalRead(red_led_pin)^1);
delay(500);
}
}

void blinkBlueLED (void *pvParameters) {


pinMode(blue_led_pin, OUTPUT);
while (1) {
digitalWrite(blue_led_pin, digitalRead(blue_led_pin)^1);
delay(500);
}
}
void blinkGrreenLED (void *pvParameters) {
pinMode(green_led_pin, OUTPUT);
while (1) {
digitalWrite(green_led_pin, digitalRead(green_led_pin)^1);
delay(500);
}
}

The uxPriority parameter of the xTaskCreate() API function assigns an initial priority to the task being created.
This initial priority can be changed after the scheduler has been started by using the vTaskPrioritySet() API function.
The vTaskPrioritySet() prototype is as follows:
void vTaskPrioritySet(TaskHandle_t pxTask, UBaseType_t uxNewPriority );
A task can change its own priority by with using its handle name or using the NULL pointer:

void vTaskPrioritySet(NULL, UBaseType_t uxNewPriority );


Question 4

In the following code I replaced all delay(500); with vTaskDelay(pdMS_TO_TICKS(500));

Now, like in the previous question, insert the line vTaskPrioritySet(NULL, 2); directly after the line marked blue in the code
below.
Run the code!

What do you observe?

All three LEDs keep blinking  .

Replace vTaskPrioritySet(NULL, 2); with vTaskPrioritySet(Handle_of_blue_task, 2);


Run the code!
What do you observe?

All three LEDs keep blinking  .

Replace vTaskPrioritySet(Handle_of_blue_task, 2); with vTaskPrioritySet(Handle_of_red_task, 2);

Run the code!


What do you observe?

All three LEDs keep blinking  .

#include <Arduino_FreeRTOS.h>
const int red_led_pin = 6;
const int blue_led_pin = 4;
const int green_led_pin = 2;

TaskHandle_t Handle_of_red_task, Handle_of_blue_task, Handle_of_green_task;


void setup() {
xTaskCreate(blinkRedLED, "BLINKING RED LED", 128, NULL, 1, &Handle_of_red_task);
xTaskCreate(blinkBlueLED, "BLINKING BLUE LED", 128, NULL, 1, &Handle_of_blue_task);
xTaskCreate(blinkGrreenLED, "BLINKING GREEN LED", 128, NULL, 1, &Handle_of_green_task);
}
void loop() {}
void blinkRedLED (void *pvParameters) {
pinMode(red_led_pin, OUTPUT);
while (1) {
digitalWrite(red_led_pin, digitalRead(red_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void blinkBlueLED (void *pvParameters) {
pinMode(blue_led_pin, OUTPUT);
while (1) {
digitalWrite(blue_led_pin, digitalRead(blue_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void blinkGrreenLED (void *pvParameters) {
pinMode(green_led_pin, OUTPUT);
while (1) {
digitalWrite(green_led_pin, digitalRead(green_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}

In the next questions we will try to explain this!


Question 5

So, in the version with delay(500); changing the priory using vTaskPrioritySet(); "worked as expected".

But, in the version with vTaskDelay(pdMS_TO_TICKS(500)); changing the priority using vTaskPrioritySet(); had no effect,
i.e., the three task kept running.
Can you explain why?
Question 6

The following statements should explain why priorities are treated differently in the delay() and vTaskDelay() versions.
Check the correct statements in the context of our examples!

1. In the delay(500) version, the tasks never transit to the Blocked state. So, a task that is not Running, will always 
be in the Ready state.

2. The scheduler picks from the Ready state the task with the the highest priority. 

3. This is why, only the task with the highest priority is executed. 

4. In the vTaskDelay() version, the tasks are most of the time in the Blocked state waiting for an event (reaching the 
set the number of tick interrupts).

5. When a task gets its event, it is moved to the Ready state, executed and then returned to the Blocked state, giving
chance to another task, even if the latter has a lower priority.

Moving tasks into the Blocked state through vTaskDelay (or other techniques that we will learn later) is the
only thing which makes using different priorities meaningful.
When the tasks are in the Ready state, otherwise, the scheduler would just pick the task with the highest
priority. Lower-priority tasks may never get a chance to be executed.
Question 7

The previous aspect can be highlighted even without vTaskPrioritySet();

The code below initializes the tasks with different priorities at the time of their creation.
Run it!

What do you observe?

All LEDs are blinking 

Now, replace all vTaskDelay(pdMS_TO_TICKS(500)); with delay(500); in the code.


Run it!
What do you observe?

Only the green LED is blinking because it has highest priority 

#include <Arduino_FreeRTOS.h>
const int red_led_pin = 6;
const int blue_led_pin = 4;
const int green_led_pin = 2;
TaskHandle_t Handle_of_red_task, Handle_of_blue_task, Handle_of_green_task;
void setup() {
xTaskCreate(blinkRedLED, "BLINKING RED LED", 128, NULL, 1, &Handle_of_red_task);
xTaskCreate(blinkBlueLED, "BLINKING BLUE LED", 128, NULL, 2, &Handle_of_blue_task);
xTaskCreate(blinkGrreenLED, "BLINKING GREEN LED", 128, NULL, 3, &Handle_of_green_task);
}
void loop() {}
void blinkRedLED (void *pvParameters) {
pinMode(red_led_pin, OUTPUT);
while (1) {
digitalWrite(red_led_pin, digitalRead(red_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}

void blinkBlueLED (void *pvParameters) {


pinMode(blue_led_pin, OUTPUT);

while (1) {
digitalWrite(blue_led_pin, digitalRead(blue_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}

void blinkGrreenLED (void *pvParameters) {


pinMode(green_led_pin, OUTPUT);
while (1) {
digitalWrite(green_led_pin, digitalRead(green_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
Question 8

Read in the FreeRTOS Tutorial (or Manual) to complete the following!

The maximum number of priorities is set by the an application-defined macro called configMAX_PRIORITIES in the
FreeRTOSConfig.h file.
Low numeric priority values denote low-priority tasks.

Smallest priority number is


0

 .

Largest priority number is


configMAX_PRIORITIES

 – 1.

The FreeRTOS scheduler will always ensure that the highest priority task that is able to run is the task selected to enter the
Running state. Where more than one task of the same priority is able to run, the scheduler will transition each task into
and out of the Running state, in turn.
Question 9

Run the code below!

Read Section 3.6 (Time Measurement and the Tick Interrupt) on Page 59 of the FreeRTOS Tutorial to answer the following!
Assume that the parameter configTICK_RATE_HZ is set to its typical value of 100 Hz.

Ignore the time required to switch tasks between the Ready and the Running states (Context Switch).
How many times per second does the task blinkRedLED go to Running state approximately?

50  times.

How long does the task blinkRedLED stay in Running state each time?

10  msec.

As for blinkBlueLED, the same applies  .

#include <Arduino_FreeRTOS.h>
const int red_led_pin = 6;
const int blue_led_pin = 4;
const uint32_t half_periode = 500;
TaskHandle_t Handle_of_red_task, Handle_of_blue_task;
uint32_t number_of_red_blinks, number_of_blue_blinks;
void setup() {
xTaskCreate(blinkRedLED, "BLINKING RED LED", 128, NULL, 1, &Handle_of_red_task);
xTaskCreate(blinkBlueLED, "BLINKING BLUE LED", 128, NULL, 1, &Handle_of_blue_task);
}
void loop() {}
void blinkRedLED (void *pvParameters) {
pinMode(red_led_pin, OUTPUT);
while (1) {
digitalWrite(red_led_pin, digitalRead(red_led_pin)^1);
delay(500);
}
}
void blinkBlueLED (void *pvParameters) {
pinMode(blue_led_pin, OUTPUT);
while (1) {
digitalWrite(blue_led_pin, digitalRead(blue_led_pin)^1);
delay(500);
}
}

The scheduler switches the tasks every 10 msec (1/100 Hz). This is called the tick period or the time slice.
So every task goes to the Running state (being executed) every 2nd 10 msec. That is every 20 msec. See the figure below!

So in every second, each task goes to the running state 1000/20 = 50 times.
This is based on the assumption that the context switch does not cost any time, which is just an approximation.
Question 10

Run the code below!

Assume that the parameter configTICK_RATE_HZ is set to its typical value of 100 Hz.
Ignore the time required to switch tasks between the Ready and the Running states (Context Switch).

How many times per second does the task blinkRedLED go to Running state approximately?

 times.
How long does the task blinkRedLED stay in Running state each time?

less than 10  msec.

#include <Arduino_FreeRTOS.h>

const int red_led_pin = 6;


const int blue_led_pin = 4;
const uint32_t half_periode = 500;
TaskHandle_t Handle_of_red_task, Handle_of_blue_task;

void setup() {
xTaskCreate(blinkRedLED, "BLINKING RED LED", 128, NULL, 1, &Handle_of_red_task);
xTaskCreate(blinkBlueLED, "BLINKING BLUE LED", 128, NULL, 1, &Handle_of_blue_task);
}
void loop() {}
void blinkRedLED (void *pvParameters) {
pinMode(red_led_pin, OUTPUT);
while (1) {
digitalWrite(red_led_pin, digitalRead(red_led_pin) ^ 1);
vTaskDelay(pdMS_TO_TICKS(half_periode));
}
}

void blinkBlueLED (void *pvParameters) {


pinMode(blue_led_pin, OUTPUT);

while (1) {
digitalWrite(blue_led_pin, digitalRead(blue_led_pin) ^ 1);
vTaskDelay(pdMS_TO_TICKS(half_periode));
}
}

Look at the blinkRedLED task and consider the timing diagram below (times are given for blinkRedLED).
Line 2 is executed in the first execution of this task only. In the next executions, Line 2 is not executed because the task
will be stuck in the infinite loop.
In each execution (i.e. when the task is in the Running state)
Line 4 is executed to flip the pin
Line 5 is executed to block the task for 500 msec.

This blocking means that the task will not be executed until this time has elapsed.

When the 500 msec have passed, the operating system wakes up the task and sends it to the Ready queue.
If this task has higher priority than all tasks in the Ready queue and the task under execution (Running), then the
unblocked task will be executed immediately.
In our example, both tasks have the same priority.
But the blinkBuleLED task is created after blinkRedLED.
Therefore, blinkRedLED is executed first, blocked first, and wakes up first.
So, when blinkRedLED wakes up, blikBlueLED is still sleeping (Blocked) and blinkRedLED will be executed directly.
In summary every second blinkRedLED is being executed almost twice per second.
However, each execution is very short because it is just about executing Line 4 (inverting the pin) and Line 5 (calling the OS to
block the task for 500 msec).
Question 11

The figure above, I put the timing diagrams close to each other for comparison.

From this, it seems that the delay() version causes less  overhead on the operating system.

This means that in the delay() version, the OS has to do less  work leaving more  time for the execution of
the actual tasks (blinkRedLED and blinkBlueLED).

In the vTaskDelay() version, the OS must move tasks between three states, while in the delay() version, the tasks are
moved between two states only.
Note: these timing diagrams are also called scheduling diagrams or Gantt charts.
Question 12

To confirm that the second version causes more operating systems' overhead.
Run the codes twice: once with delay() and once with vTaskDelay()!
Each time start a timer (e.g., on you mobile phone) for one minute and measure how many times the LEDs blink during
this minute:
In the delay() version, I counted
60

 blinks in the minute (write a number).


In the vTaskDelay() version, I counted
58

 blinks in the minute (write a number).


So, the delay() version is almost by
2

 blinks more accurate than the vTaskDelay() version.

In this specific example, using vTaskDelay() does not seem to be useful.


The main point here is that
both tasks have the same priority, and
there are no other tasks with higher or lower priority
In such a case, blocking the tasks does not bring a special advantage.
Remember that the Blocked state is very useful when you want to allow a lower-priority task to be executed while a
higher-priority task is bocked.
Question 13

Run the following code for different values of the execution_period.

Decrease the value of execution_period and test until you find the first value which causes the blue and green LEDs to stop
blinking.
What is this value?
1000

 (Write the biggest value of execution_period that prevents the blue and green LEDs from blinking. All smaller values
will cause the same)

#include <Arduino_FreeRTOS.h>
const int red_led_pin = 6;
const int blue_led_pin = 4;
const int green_led_pin = 2;

const uint32_t execution_period = 250;


TaskHandle_t Handle_of_red_task, Handle_of_blue_task, Handle_of_green_task;
void setup() {
xTaskCreate(blinkRedLED, "BLINKING RED LED", 128, NULL, 2, &Handle_of_red_task);
xTaskCreate(blinkBlueLED, "BLINKING BLUE LED", 128, NULL, 1, &Handle_of_blue_task);
xTaskCreate(blinkGrreenLED, "BLINKING GREEN LED", 128, NULL, 1, &Handle_of_green_task);
}
void loop() {}
void blinkRedLED (void *pvParameters) {
pinMode(red_led_pin, OUTPUT);
while (1) {
digitalWrite(red_led_pin, digitalRead(red_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(half_periode));
}
}

void blinkBlueLED (void *pvParameters) {


pinMode(blue_led_pin, OUTPUT);

while (1) {
digitalWrite(blue_led_pin, digitalRead(blue_led_pin)^1);
delay(500);
}
}
void blinkGrreenLED (void *pvParameters) {
pinMode(green_led_pin, OUTPUT);
while (1) {
digitalWrite(green_led_pin, digitalRead(green_led_pin)^1);
delay(500);
}
}
The tasks blinkBlueLED and blinkGreenLED are called continuous tasks because they are either in the Ready or in the
Running state.
blinkRedLED is called periodic task because it wakes up from time to time at a given period (here call execution_period).
Since the periodic task has higher priority than the continuous tasks, the OS serves it as soon as it wakes up.
When the periodic task wakes up too frequently (i.e., its period gets too short), the OS ignores any continuous task with
lower priority.

Response history
Step Time Action State Marks

1 7/03/21, 11:46 Started Not complete

2 7/03/21, 13:11 Submit: part 1: 1000 Incorrect 0.00


Question 14

I now set the first value for execution_period at which the blue and green LEDs stopped blinking.
However, I changed the priority of blinkBlueLED to 2.
Run the code.
What do you observe?

The red and the blue LEDs are blinking 

#include <Arduino_FreeRTOS.h>
const int red_led_pin = 6;
const int blue_led_pin = 4;
const int green_led_pin = 2;
const uint32_t execution_period = 16;
TaskHandle_t Handle_of_red_task, Handle_of_blue_task, Handle_of_green_task;
void setup() {
xTaskCreate(blinkRedLED, "BLINKING RED LED", 128, NULL, 2, &Handle_of_red_task);
xTaskCreate(blinkBlueLED, "BLINKING BLUE LED", 128, NULL, 2, &Handle_of_blue_task);
xTaskCreate(blinkGrreenLED, "BLINKING GREEN LED", 128, NULL, 1, &Handle_of_green_task);
}
void loop() {}
void blinkRedLED (void *pvParameters) {
pinMode(red_led_pin, OUTPUT);
while (1) {
digitalWrite(red_led_pin, digitalRead(red_led_pin)^1);
vTaskDelay(pdMS_TO_TICKS(half_periode));
}
}

void blinkBlueLED (void *pvParameters) {


pinMode(blue_led_pin, OUTPUT);
while (1) {
digitalWrite(blue_led_pin, digitalRead(blue_led_pin)^1);
delay(500);
}
}

void blinkGrreenLED (void *pvParameters) {


pinMode(green_led_pin, OUTPUT);
while (1) {
digitalWrite(green_led_pin, digitalRead(green_led_pin)^1);
delay(500);
}
}

The period of the periodic task got too short.


However, since blinkRedLED has the same priority as blinkBlueLED, both these tasks are served.
But not blinkGreenLED.
Question 15

One the codes you ran today has the timing diagram shown above.
As you can see, over considerable time slots, both task are blocked and no other tasks are in the ready state.
What does the processor do in these time slots?

Running a special task called idle 

Check the tutorial document for the answer!

There must always be at least one task that can enter the Running state1.
To ensure this is the case, an Idle task is automatically created by the scheduler when vTaskStartScheduler() is called.
The idle task does very little more than sit in a loop.

The idle task has the lowest possible priority (priority zero), to ensure it never prevents a higher priority application task from entering the
Running state.
The configIDLE_SHOULD_YIELD compile time configuration constant in FreeRTOSConfig.h can be used to prevent the Idle task from
consuming processing time that would be more productively allocated to applications tasks.

Running at the lowest priority ensures the Idle task is transitioned out of the Running state as soon as a higher priority task enters the Ready
state.

Idle Task Hook Functions


It is possible to add application specific functionality directly into the idle task through the use of an idle hook (or idle callback) function—a
function that is called automatically by the idle task once per iteration of the idle task loop.

Common uses for the Idle task hook include:


1. Executing low priority, background, or continuous processing functionality.
2. Measuring the amount of spare processing capacity.
3. Placing the processor into a low power mode.

An Idle task hook function must never attempt to block or suspend.


If the application makes use of the vTaskDelete() API function, then the Idle task hook must always return to its caller within a reasonable
time period. This is because the Idle task is responsible for cleaning up kernel resources after a task has been deleted. If the idle task remains
permanently in the Idle hook function, then this clean-up cannot occur.

You might also like