Exp.
8 Date:
CREATING MULTIPLE TASKS IN FREERTOS WITH ARDUINO
AIM:
To create two tasks where task1 toggles the built-in LED with 200ms frequency while
task2 prints the incremented count value in the serial monitor with 500ms frequency.
REQUIREMENTS:
Hardware:
1. Desktop PC
2. Arduino Nano
3. Breadboard
Software:
1. Arduino IDE
THEORY:
For creating task, xTaskCreate() API is called in setup function with certain
parameters/arguments.
xTaskCreate( TaskFunction_t pvTaskCode, const char * const pcName, uint16_t
usStackDepth, void *pvParameters, UBaseType_t uxPriority, TaskHandle_t
*pxCreatedTask );
There are 6 arguments that should be passed while creating any task. Let’s see what these
arguments are
I. pvTaskCode: It is simply a pointer to the function that implements the task (in effect,
just the name of the function).
II. pcName: A descriptive name for the task. This is not used by FreeRTOS. It is
included purely for debugging purposes.
III. usStackDepth: Each task has its own unique stack that is allocated by the kernel to
the task when the task is created. The value specifies the number of words the stack
can hold, not the number of bytes. For example, if the stack is 32-bits wide
and usStackDepth is passed in as 100, then 400 bytes of stack space will be allocated
(100 * 4 bytes) in RAM. Use this wisely because Arduino Uno has only 2Kbytes of
RAM.
IV. pvParameters: Task input parameter (can be NULL).
V. uxPriority: Priority of the task ( 0 is the lowest priority).
VI. pxCreatedTask: It can be used to pass out a handle to the task being created. This
handle can then be used to reference the task in API calls that, for example, change
the task priority or delete the task (can be NULL).
Example of task creation
xTaskCreate(task1,"task1",128,NULL,1,NULL);
xTaskCreate(task2,"task2",128,NULL,2,NULL);
Here, Task2 has higher priority and hence executes first.
4. After creating the task, start the scheduler in a void setup
using vTaskStartScheduler(); API.
5. Void loop() function will remain empty as we don’t want to run any task manually and
infinitely. Because task execution is now handled by Scheduler.
6. Now, we have to implement task functions and write the logic that you want to execute
inside these functions. The function name should be the same as the first argument
of xTaskCreate() API.
void task1(void *pvParameters)
{
while(1) {
..
..//your logic
}
}
7. Most of the code needs delay function to stop the running task but in RTOS it is not
suggested to use Delay() function as it stops the CPU and hence RTOS also stops working.
So FreeRTOS has a kernel API to block the task for a specific time.
vTaskDelay( const TickType_t xTicksToDelay );
This API can be used for delay purposes. This API delay a task for a given number of ticks.
The actual time for which the task remains blocked depends on the tick rate. The
constant portTICK_PERIOD_MS can be used to calculate real-time from the tick rate.
This means if you want a delay of 200ms, just write this line
vTaskDelay( 200 / portTICK_PERIOD_MS );
So for this tutorial, we will use these FreeRTOS APIs to implement three tasks.
APIs to be used:
1. xTaskCreate();
2. vTaskStartScheduler();
3. vTaskDelay();
PROGRAM:
#include <Arduino_FreeRTOS.h>
void TaskBlink1( void *pvParameters );
void TaskBlink2( void *pvParameters );
void Taskprint( void *pvParameters );
void setup() {
Serial.begin(9600);
xTaskCreate(TaskBlink1,"Task1",128,NULL,1,NULL);
xTaskCreate(Taskprint,"Task3",128,NULL,1,NULL);
vTaskStartScheduler();
void TaskBlink1(void *pvParameters)
pinMode(LED_BUILTIN, OUTPUT);
while(1)
digitalWrite(LED_BUILTIN, HIGH);
vTaskDelay( 200 / portTICK_PERIOD_MS );
digitalWrite(LED_BUILTIN, LOW);
vTaskDelay( 200 / portTICK_PERIOD_MS );
void Taskprint(void *pvParameters)
{
int counter = 0;
while(1)
counter++;
Serial.println(counter);
vTaskDelay( 500 / portTICK_PERIOD_MS );
void loop(){
RESULT:
Exp. 9 Date:
USING MUTEX SEMAPHORE IN FREERTOS WITH ARDUINO
AIM :
To use a Serial monitor as a shared resource and two different tasks to access the
serial monitor to print some message with the help of mutex semaphore using Arduino.
REQUIREMENTS:
Hardware:
1. Desktop PC
2. Arduino Nano
3. Breadboard
Software:
1. Arduino IDE
THEORY:
Mutex is a locking mechanism unlike the semaphore that has separate functions for increment
and decrement but in Mutex, the function takes and gives in itself. It is a technique to avoid
the corruption of shared resources. To protect the shared resource, one assigns a token card
(mutex) to the resource. Whoever has this card can access the other resource. Others should
wait until the card returned. In this way, only one resource can access the task and others wait
for their chance.
Mutexs are also used in the same way as semaphores. First, create it, then give and take using
respective APIs.
Creating a Mutex:
To create a Mutex, use xSemaphoreCreateMutex() API. As its name suggests that Mutex is a
type of Binary semaphore. They are used in different contexts and purposes. A binary
semaphore is for synchronizing tasks while Mutex is used for protecting a shared resource.
This API does not take any argument and returns a variable of type SemaphoreHandle_t. If
the mutex cannot be created, xSemaphoreCreateMutex() return NULL.
Taking a Mutex:
When a task wants to access a resource, it will take a Mutex by
using xSemaphoreTake() API. It is the same as a binary semaphore. It also takes two
parameters.
xSemaphore: Name of the Mutex to be taken in our case mutex_v.
xTicksToWait: This is the maximum amount of time that the task will wait in Blocked state
for the Mutex to become available. In our project, we will
set xTicksToWait to portMAX_DELAY to make the task_1 to wait indefinitely in Blocked
state until the mutex_v is available.
Giving a Mutex:
After accessing the shared resource, the task should return the Mutex so that other tasks can
access it. xSemaphoreGive() API is used to give the Mutex back.
The xSemaphoreGive() function takes only one argument which is the Mutex to be given in
our case mutex_v.
Program:
#include <Arduino_FreeRTOS.h>
#include <semphr.h>
SemaphoreHandle_t mutex_v;
void setup() {
Serial.begin(9600);
mutex_v = xSemaphoreCreateMutex();
if (mutex_v == NULL) {
Serial.println("Mutex cannot be created");
xTaskCreate(Task1, "Task 1", 128, NULL, 1, NULL);
xTaskCreate(Task2, "Task 2", 128, NULL, 2, NULL);
void Task1(void *pvParameters) {
while(1) {
xSemaphoreTake(mutex_v, portMAX_DELAY);
Serial.println("Hi from Task1");
xSemaphoreGive(mutex_v);
vTaskDelay(pdMS_TO_TICKS(1000));
}
void Task2(void *pvParameters) {
while(1) {
xSemaphoreTake(mutex_v, portMAX_DELAY);
Serial.println("Hi from Task2");
xSemaphoreGive(mutex_v);
vTaskDelay(pdMS_TO_TICKS(500));
void loop(){
RESULT: