Featured post

Arduino FreeRTOS Mutex Examples

In this section, we will explain using an example to demonstrate mutexes in Arduino using freeRTOSThere are two freeRTOS Mutex examples in this tutorial, the first example demands some hardware (LCD) While the second does not need any hardware, you can try out both if you have the resources.

In the last tutorial, we considered in detail: semaphores and mutexes and we also established the difference between binary semaphores and mutexes.
Just for a review:Recall that a mutex is a locking mechanism that implements the take and gives functionality in itself, unlike a binary semaphore. See this tutorial if you have not before continuing.
Example 1: Protecting the LCD Resource Using Mutex in freeRTOS
Program Description

In this program, we Demonstrated the use a 16x2 LCD display to implement a mutex.

The LiquidCrystal library works with all LCD displays that are compatible with the Hitachi HD44780 driver. you can usually tell them by their 16-pin interface.

THE CIRCUIT

* LCD RS pin to digital…

Arduino FreeRTOS Tutorial 04: Understanding Task Scheduling and Control

In the last Free RTOS Arduino tutorial, we were able to show how a task can be implemented and executed. We also saw how to delete a task that we no longer need after a while.

In this tutorial, we are going to learn and understand how task scheduling and execution work.

To properly understand this, we will be using an example to illustrate this.

In this example, we are creating two tasks with the same priority and in the second example, with two different priorities.
#include <Arduino_FreeRTOS.h>

void setup()
{
  Serial.begin(9600);
  xTaskCreate(Task1, "Task 1", 100, NULL, 1, NULL);
  xTaskCreate(Task2, "Task 2", 100, NULL, 1, NULL);
  vTaskStartScheduler(); // hands over control to kernel. Task execution begins
 
}
void loop(){
  }
==============================
void Task1(void* pvParameters)
{
 for(;;)
  {
    Serial.println("Task1 is currently being executed");
    vTaskDelay(500/portTICK_PERIOD_MS);
  }
}
void Task2(void* pvParameters)
{
 for(;;)
  {
    Serial.println("Task2 is currently being executed");
    vTaskDelay(500/portTICK_PERIOD_MS);
  }
}

If you run this program, open your serial monitor and observe what happens. The tasks execute one after the other. This is because they have the same priority.

Now we are going to consider what happens when one task has a higher priority. To do this, we change the priority of task 2 to 2.
#include <Arduino_FreeRTOS.h>

void setup()
{
  Serial.begin(9600);
  xTaskCreate(Task1, "Task 1", 100, NULL, 1, NULL);
  xTaskCreate(Task2, "Task 2", 100, NULL, 2, NULL);
  vTaskStartScheduler(); // hands over control to kernel. Task execution begins
 
}
void loop(){
  }
==============================
void Task1(void* pvParameters)
{
 for(;;)
  {
    Serial.println("Task1 is currently being executed");
    vTaskDelay(500/portTICK_PERIOD_MS);
  }
}
void Task2(void* pvParameters)
{
 for(;;)
  {
    Serial.println("Task2 is currently being executed");
    vTaskDelay(500/portTICK_PERIOD_MS);
  }
}

Observe the serial monitor and answer the following questions.

  • Which task executed first?

  • Did Task 1 ever pre-empt task 2?

  • What happens if task2 do not contain a vTaskDelay() [Remove the task delay from task 2 and observe what happens]

Drop your response at the comment box.

You would observe that task 2 executed first. Anytime you turn it on, it executes first because it is of a higher priority. The task scheduler (real time kernel) always executes the higher priority tasks first, until their execution is complete, they can never be pre-empted by any other task with less priority.

You would also observe that after removing the vTaskDelay from task 2, Task 1 was never able to run. That leads us to our next section.

Understanding vTaskDelay() and vTaskDelayUntil() in freeRTOS


As could be seen in the example questions above, Task1 was never able to run when vTaskDelay was removed from Task2.

So what does  vTaskDelay() has to do with this? 

Recall the states of a task which we treated in this article. We reiterated that tasks have states which are broadly divided into running state and not-running states. See the tutorial to learn about this.

The vTaskDelay() pushes a task to the blocked state, until expiration of the delay. Unlike delay() function in arduino that freezes the cpu, the vTaskDelay() pushes the task onto the blocked state thereby removing it from the running state, granting space for another ready task to be executed.

So what about vTaskDelayUntil()?

vTaskDelayUntil() is different from vTaskDelay() in that it adds additional features of periodicity to vTaskDelay().

What does this mean? 

vTaskDelay only specifies the number of ticks (time) required for the task to get out of the blocked state. But vTaskDelayUntil specifies the absolute time required to get the task back into the running state. It takes into account, the time it went to the blocked state and the time required to get back into the running state.

The  syntax for vTaskDelayUntil(LastWakeTime, TicksToWait).

LastWakeTime:  This points to the variable holds the time at which the task was last unblocked. The variable must be initialised with the current time prior to its first use.

TicksToWait: The cycle time period. The task will be unblocked at time (LastWakeTime + TicksToWait).

See the code below for a better explanation.
#include <Arduino_FreeRTOS.h>
#include <FreeRTOS.h>

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
xTaskCreate(Task1, "Task 1", 200, NULL, 1, NULL);
xTaskCreate(Task2, "Task 2", 600, NULL, 1, NULL);
}

void loop() {
//leave empty
}

void Task1(void *pvParameters){
for(;;){
Serial.println("Task 1 is running");
vTaskDelay(1000/portTICK_PERIOD_MS);
}

}
void Task2(void *pvParameters){
while(1){
portTickType LastWakeTime; //the variable to store the last wake time is of type prtTickType
LastWakeTime = xTaskGetTickCount();//get the last current wake time
Serial.print("Last Run: ");
Serial.print(LastWakeTime);
Serial.println();
vTaskDelayUntil(&LastWakeTime, 200); //run again after LastWaketime + 200 ticks

}
}

Try Changing the Proiorities of Task1 and then Task2 and see what happens.

Comment on your observations.

Conclusion

In this section we have examined how pre-emptive task scheduling works, and how a task is moved to blocked state using vTaskDelay(), we have also shown the periodic execution using vTaskDelayUntil(), and we observed using some examples. In the next tutorial, we will be taking a look at Queues and how to use them.

Drop your observations and comments below, I will ensure I see to them.

Comments

Popular posts from this blog

Arduino FreeRTOS Tutorial 05: Binary Semaphores and Mutexes

Digital Systems and Stability Analysis using Jury's Stability Test

Understanding the operation of I2C Bus