Module 2 - Task Management

Learning Objectives

After completing this module, students are expected to be able to:

The Importance of Task Scheduling in IoT

One of the most important aspects in an RTOS is task scheduling since it defines the sequence in which many operations run on the CPU at the appropriate instant. Each process or task in the context of real-time applications has a particular function, such reading sensor data, handling images, or sending messages to other devices. 
 
Scheduling takes great significance in applications using the Internet of Things (IoT) as many devices connect with one other and engage their surroundings using sensors and actuators. Usually having strict timing demands, IoT applications need dependability and rather quick reactions. An IoT greenhouse system, for instance, has to continuously monitor temperature and moisture in real time while also controlling ventilation or irrigation on time to keep ideal conditions. 
 
Task scheduling in an RTOS is geared toward two primary objectives: 
 1. Feasibility: Every job needs to be finished by its deadline; nothing is left out. 
 2. Optimality: Optimize characteristics including CPU use, power consumption, and reaction time such that the system performs effectively. 
 
Attaining both objectives is difficult since there are usually several duties with varying priorities, execution periods, due dates, and dependencies. In addition, task scheduling helps considerably with: 

Categories of Task Scheduling Algorithms

Several task-scheduling techniques available in a Real-Time Operating System (RTOS) have both benefits and drawbacks depending on the the needs of the system and the nature of the tasks under execution. Among the most often used algorithms are:

1. Run for Completion (RTC)

The simplest approach is the Run to Completion algorithm. Every job runs till finished before moving onto the next one. Once all activities are finished, the sequence repeats itself from the start.

Advantages

Simple and quick to put into practice.

Disadvantages

Other tasks influence the completion time of a job, therefore reducing the determinacy of the system.

 

2. Round Robin (RR)

Round Robin is similar to RTC, but a task does not have to complete all its work before releasing the CPU. When it is scheduled again, the task resumes from where it left off.

Advantages
  • Provides a fairer time allocation to each task.
  • More adaptable than RTC.
Disadvantages

Still relies on how each job behaves and is unable to stop one from taking over the processor for too long.

 

3. Time Slice (TS)

A pre-emptive scheduling algorithm in which execution time is broken into minute pieces known as time slices or ticks (e.g., 1 ms). The scheduler picks one task from the whole task list to run every time an interrupt happens.

Advantages

Stops starvation (a job kept too long).

Disadvantages

Can lead to repeated context switching, hence raising system overhead.

 

4. Fixed Priority (FP)

Fixed Priority assigns a static priority based on urgency to every job. The scheduler always chooses the task with the highest priority to run first.

If:

Advantages

Uncomplicated and efficient; regularly used in real-time applications.

Disadvantages

Less flexible in response to workload or shifting system conditions.

 

5. Earliest Deadline First (EDF)


Dynamic priority according to the deadline of each assignment is provided by the Earliest Deadline First method. The one with the shortest deadline is always done first.

Theoretically, EDF is ideal since it can plan any possible collection of jobs.

Advantages

Offers best performance in deadline compliance.

Disadvantages

Practically verifying execution can be somewhat challenging and difficult.

 

Introduction to FreeRTOS

Particularly for IoT uses, FreeRTOS is a well-known open-source RTOS kernel found in embedded systems.

FreeRTOS has three basic ideas guiding its design:

Many architectures are supported by FreeRTOS, including ARM, AVR, PIC, MSP430, and ESP32. It also works with a variety of platforms, like Arduino, Raspberry Pi, and even AWS IoT.

Important aspects and services provided by FreeRTOS consist of:

1. Task

FreeRTOS lets you build and manage several tasks that may run simultaneously across several processor cores or on a single core. 
 Every task includes: 

API allow users to create, remove, suspend, resume, postpone, or synchronize tasks. 

2. Queue

For synchronization and inter-task communication, FreeRTOS offers queues.

3. Timer

FreeRTOS has software timers that allow:

4. Event Groups

Event groups are used to signal between tasks or between tasks and interrupts. Characteristics include:

5. Notification

FreeRTOS provides task notifications for lightweight and fast communication between tasks or between tasks and interrupts. Key points:

Practical Sections

Setting Up FreeRTOS on ESP-32

Two cores in ESP-32 let this low-power microcontroller operate:

Installing and configuring the ESP-32 Arduino Core: 
1. Obtain the most recent Arduino IDE and install it. 
2. Launch Arduino IDE then go to File / Preferences. Enter in the field Additional Boards Manager URLs:

https://dl.espressif.com/dl/package_esp32_index.json

3. Go to Tools / Board / Boards Manager, look for esp32, and install the most recent release from Espressif Systems. 
4. Go to Tools / Board / ESP32 Arduino and pick the right board (like ESP32 Dev Module or ESP32 Wrover Module).

All about FreeRTOS APIs

1. xTaskCreate()
BaseType_t xTaskCreate(
    TaskFunction_t pvTaskCode,
    const char * const pcName,
    const uint32_t usStackDepth,
    void * const pvParameters,
    UBaseType_t uxPriority,
    TaskHandle_t * const pvCreatedTask
);

Parameters

  1. pvTaskCode: Pointer to the function that implements the task. The function must have a prototype of void vTaskCode(void * pvParameters).
  2. pcName: Descriptive name of the task (helps with debugging).
  3. usStackDepth: Stack size in words (not bytes) for the task.
  4. pvParameters: Pointer to the arguments passed to the task function.
  5. uxPriority: Priority of the task execution (higher number = higher priority).
  6. pvCreatedTask: Pointer to the variable that will receive the created task handle.

Return Value

  1. pdPASS: The task was successfully created and added to the ready list.
  2. errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: The task could not be created because there is not enough heap memory available.

2. xTaskCreatePinnedToCore()
BaseType_t xTaskCreatePinnedToCore(
TaskFunction_t pvTaskCode,
const char * const pcName,
const uint32_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pvCreatedTask,
const BaseType_t xCoreID
);

Parameters

Same as xTaskCreate(), except for:

  1. xCoreID: The core number on which the task should run. Can be 0 or 1 for a dual-core target ESP, or any other valid number of cores for a multi-core target ESP, i.e. 2 cores, 3 cores, etc.

Return Value

Same as xTaskCreate().


3. vTaskDelete()
void vTaskDelete(TaskHandle_t xTask);

Parameters

  1. xTask: The handler of the task to be deleted. Passing NULL will delete the calling task.

Return Value

None.


4. vTaskDelay()
void vTaskDelay(const TickType_t xTicksToDelay);

Parameters

  1. xTicksToDelay: The number of ticks to delay. One tick = the unit of time specified by the configTICK_RATE_HZ configuration constant in FreeRTOSConfig.h.

Return Value

None.


5. vTaskDelayUntil()
void vTaskDelayUntil(TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement);

Parameters

  1. pxPreviousWakeTime: Pointer to a TickType_t variable that stores the time when the task was last unblocked. This variable must be initialized with the current time before the first call to the vTaskDelayUntil() function. The function will update the variable with the current time after each call.
  2. xTimeIncrement: The time period between executions (cycle time) in ticks. The task will be unblocked at times (pxPreviousWakeTime + xTimeIncrement), (pxPreviousWakeTime + xTimeIncrement2), and so on.

Return Value

None.


6. vTaskSuspend()
void vTaskSuspend(TaskHandle_t xTaskToSuspend);

Parameters

  1. xTaskToSuspend: The handle of the task to be suspended. Passing a NULL value will suspend the calling task.

Return Value

None.


7. vTaskResume()
void vTaskResume(TaskHandle_t xTaskToResume);

Parameters

  1. xTaskToResume: The handle of the task to be reactivated.

Return Value

None.


8. vTaskPrioritySet()
void vTaskPrioritySet(TaskHandle_t xTask, UBaseType_t uxNewPriority);

Parameters

  1. xTask: The handle of the task whose priority will be changed. Passing a NULL value will change the priority of the calling task.
  2. uxNewPriority: The new priority for the task.

Return Value

None.


9. uxTaskPriorityGet()
UBaseType_t uxTaskPriorityGet(TaskHandle_t xTask);

Parameters

  1. xTask: The handle of the task whose priority is to be obtained. Passing a NULL value will return the priority of the calling task.

Return Value


10. eTaskGetState()
eTaskState eTaskGetState(TaskHandle_t xTask);

Parameters

  1. xTask: The handle of the task whose status is to be obtained.

Return Value

  1. xTask: The handle of the task whose status is to be returned.

The following are the possible task states:

Status Description
eRunning The task is running.
eReady The task is ready to run.
eBlocked The task is blocked, waiting for an event.
eSuspended The task is temporarily suspended.
eDeleted The task has been deleted.
eInvalid The task marker is invalid.


Additional References