0% found this document useful (0 votes)
46 views48 pages

Unit 2 - Embedded Real-Time Operating Systems

The document provides an overview of Embedded Real-Time Operating Systems (RTOS), detailing their structure, functions, and key features. It explains the differences between RTOS and general-purpose operating systems, emphasizing determinism, task scheduling, and resource management. Additionally, it covers RTOS components such as task management, synchronization, inter-task communication, and introduces FreeRTOS as a lightweight option for embedded systems.

Uploaded by

sisaxozwa1
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
46 views48 pages

Unit 2 - Embedded Real-Time Operating Systems

The document provides an overview of Embedded Real-Time Operating Systems (RTOS), detailing their structure, functions, and key features. It explains the differences between RTOS and general-purpose operating systems, emphasizing determinism, task scheduling, and resource management. Additionally, it covers RTOS components such as task management, synchronization, inter-task communication, and introduces FreeRTOS as a lightweight option for embedded systems.

Uploaded by

sisaxozwa1
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 48

Unit 2

Embedded Real-Time Operating Systems

References:
1. Fast and Effective Embedded Systems Design: Applying the ARM mbed – by Rob Toulson and Tim
Wilmshurst
2. https://www.engineersgarage.com/article_page/rtos-real-time-operating-system/
3. https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/freertos_idf.html#a
pi-reference
4. NMU_Espressif_FreeRTOS_V2 PowerPoint – by Frank Adlam
Updated: 25 Feb 2025
Limits of conventional programming
• Conventional programs up to now:

• Task 1, 2, …n could include Boolean, Flowchart, or State Machine techniques


• At some point this structure is no longer adequate:
• Loops become too long
• Tasks are intermittent
• ISRs causes delays
2
Introduction to the Real-Time
Operating System (RTOS)
• RTOS provides a different approach to program development.
• With RTOS, control of the CPU and all system resources are handed to the
operating system (OS).
• It is the OS which now determines which section of the program is to run, for
how long, and how it accesses system resources.
• The application program itself is subservient to the OS.

3
RTOS Tasks
• A program written for an RTOS is structured into tasks or threads
• Each task is written as a self-contained program module.
• The tasks can be prioritised, though this is not always the case.
• RTOS performs 3 main functions:
• Decides which thread should run and duration
• Provides communication and synchronization between threads
• Controls use of resources between tasks, e.g. memory and hardware peripherals.
What is a thread?
• A group of instructions that execute to solve a portion of a problem.
• A “problem” could be:
• Design of a dishwasher system
• A “thread” for such a system can be:
• Manage water level thread
• Manage motor speed thread
• A single thread ‘thinks’ that it has the CPU available all the time.

4
RTOS Scheduling
• An RTOS has a thread scheduler, which will run all threads in a manner that
satisfies the constraints of the system.
• Scheduler uses a clock tick (from hardware internal timer) for scheduling
threads.
• At each tick, the scheduler determines if a different task should be given CPU
time.
• Different scheduling methods available, of which Round Robin is the most
common:

5
RTOS – Real-Time Operating System
• A Real-Time Operating System (RTOS) comprises of two components: “Real-
Time” and “Operating System”.

Operating system (OS)


• A collection of system calls or functions – provides an interface between
hardware and application programs.
• Manages the hardware resources and applications that run on the computer.
• Provides multitasking, synchronization, Interrupt and Event Handling, Input/
Output, Inter-task Communication, Timers and Clocks and Memory
Management.
• Core of the OS is the Kernel which is typically a small, highly optimised set of
libraries.

Real-time systems
• Systems in which the correctness of the system depends not only on the logical
result of computation, but also on the time at which the results are produced.
6
• RTOS does not necessarily increase the speed of execution, BUT provides much
more precise and predictable timing than general-purpose OS.
• RTOS is key to many embedded systems
• Embedded systems with relatively simple/small hardware/code might not
require an RTOS.
• Embedded systems with moderate-to-large software applications require some
form of scheduling, and hence RTOS.

7
Difference: RTOS v/s General Purpose OS
Determinism
• Key difference is “deterministic ” timing behaviour
• Deterministic timing – OS consume only known and expected amounts of time.
• In RTOS worst case latency is defined; Latency is not of a concern for General
Purpose OS.
Task Scheduling
• General purpose OS optimized to run applications and processes simultaneously
– all tasks receive at least some processing time.
• Consequence: Low-priority tasks may execute above other higher priority tasks
• RTOS uses priority-based preemptive scheduling – high-priority threads to meet
their deadlines consistently.
• All system calls are deterministic
• Important where delay could cause a safety hazard.
• The scheduling in RTOS is time based.
• In case of General purpose OS, like Windows/Linux, scheduling is process based.
8
Preemptive kernel
• In RTOS, all kernel operations are preemptible
• Means that a thread can be preempted (suspended) when a higher priority
thread has control
Priority Inversion
• A situation when lower priority thread holds a resource, while higher priority
thread is ready to use it.
• The lower priority thread prevents the higher priority thread to execute.
• RTOS have mechanisms to prevent priority inversion.
Usage
• RTOS used for embedded applications.
• General Purpose OS are used for Desktop PCs or other generally purpose PCs.

9
RTOS classification
• RTOS specifies a known maximum time for each of the operations that it
performs.
• Based upon the degree of tolerance in meeting deadlines, RTOS are classified
into following categories:
• Hard real-time – Degree of tolerance for missed deadlines is negligible. A missed
deadline can result in catastrophic failure of the system
• Firm real-time – Missing a deadline might result in an unacceptable quality reduction
but may not lead to failure of the complete system
• Soft real-time – Deadlines may be missed occasionally, but system doesn’t fail and
also, system quality is acceptable
• Hard real-time examples: motor vehicle airbags, automatic parachute
deployment, etc.
• Soft real-time examples: TV live broadcast etc.
• Determinism: An application is referred to as deterministic if its timing can be
guaranteed within a certain margin of error.
• Jitter: Timing error of a task over subsequent
iterations of a program or loop is referred to
as jitter; RTOS are optimized to minimize jitter.
10
RTOS features
• Multithreading and preemptability – The scheduler should be able to preempt
(suspend) any task in the system and allocate the resource to the thread that
needs it most even at peak load.
• Thread Priority – All tasks are assigned priority level to facilitate pre-emption.
The highest priority task that is ready to run will be the task that will be running.
• Inter Task Communication & Synchronization – Multiple tasks pass information
among each other in a timely fashion and ensuring data integrity
• Priority Inheritance – RTOS should have large number of priority levels and
should prevent priority inversion using priority inheritance.
• Short Latencies – The latencies are short and predefined.
• Task switching latency: The time needed to save the context of a currently executing
task and switching to another task.
• Interrupt latency: The time elapsed between execution of the last instruction of the
interrupted task and the first instruction in the interrupt handler.
• Interrupt dispatch latency: The time from the last instruction in the interrupt handler
to the next task scheduled to run.

11
RTOS architecture
Six types of common services are shown in the following figure below:

12
Task Management: Task/Thread Object
• RTOS application consist of small, schedulable, and sequential program units
known as “Tasks” or threads.
• Three time-critical properties
• Release time – the point in time from which the task can be executed.
• Deadline – point in time by which the task must complete.
• Execution time – time the task takes to execute.
• Each thread has its own registers and stack

• Threads share global memory and I/O ports

13
• A Thread can be in the following states:
• RUNNING: The thread that is currently running is in the RUNNING state. Only one
thread at a time can be in this state.
• READY: Threads which are ready to run are in the READY state. Once the RUNNING
thread has terminated or is WAITING the next READY thread with the highest priority
becomes the RUNNING thread.
• WAITING: Threads that are waiting for an event to occur are in the WAITING state.
• INACTIVE: Threads that are not created or terminated are in the INACTIVE state.
These threads typically consume no system resources.

• When CPU control is changed from one task to another, context switching
occurs:
• context of the to-be-suspended task will be saved
• context of the to-be-executed task will be retrieved

14
Task Management: Scheduler
• The scheduler:
• keeps record of the state of each task
• selects thread that are ready to execute
• allocates the CPU to one of them.
• Various scheduling algorithms are used in RTOS:
• Polled Loop: Sequentially determines if specific task requires time.

• Polled System with interrupts: In addition to polling, it takes care of critical tasks.

15
• Round Robin: Sequences from task to task, each task getting a slice of time

• Hybrid System: Sensitive to sensitive interrupts, with Round Robin system working in
background
• Interrupt Driven: System continuously wait for the interrupts
• Non pre-emptive scheduling or Cooperative Multitasking: Highest priority task
executes for some time, then relinquishes control, re-enters ready state.

• Preemptive scheduling Priority multitasking: Current task is immediately


suspended. Control is given to the task of the highest priority at all time.

16
Synchronisation and communication:
Task Synchronisation
• Synchronization is essential:
• for tasks to share mutually exclusive resources (devices, buffers, etc.)
• and/or allow multiple concurrent tasks to be executed (e.g. Task A needs a result from
task B, so task A can only run till task B produces it).
• Task synchronization is achieved using two types of mechanisms:

Event Objects
• Used when task synchronization is required without resource sharing.
• Allow one or more tasks to keep waiting for a specified event to occur.
• Events are signals to a task:
• That effect the execution of a task.
• Typically come from outside the task.
• Can be combinatorial
• External hardware events:
• Water level full in dishwasher.
• Hardware pushbutton pressed.
• Software events:
• Another task has completed its operation. 17
Semaphores
• A semaphore has an associated:
• resource count – indicates availability of resource.
• wait queue – manages the tasks waiting for resources from the semaphore.
• A semaphore functions like a key that define whether a task has the access to
the resource.
• A task gets an access to the resource when it acquires the semaphore.
• If the semaphore is already in use, the requesting thread is suspended until the
semaphore is released by the current owner
• There are three types of semaphores:
• Binary – A value of 0 or 1 Counting Semaphores
• Counting – non-negative integer value
• Zero
• Another task is in specific critical section
• Resource is busy
• Non-zero
• You can enter critical section of code
• Resource is available
• Mutually Exclusion(Mutex) Semaphores
• Issues: Priority Inversion
18
Mutually Exclusion (Mutex) Semaphores
• Prevents conflicting access to common resource:
• Hardware Registers
• Peripherals
• Data structures
• The same as binary semaphore
• Mutexes can lead to deadlocks occurring
• RTOS provide priority inheritance to overcome problem of priority inversion:
• Mutex may have inheritance

Deadlocks:
• Each task waits for the other to release the mutex:
• Neither threads completes execution.

19
Synchronisation and communication:
Intertask Communication
• Intertask communication involves sharing of data among tasks through sharing
of memory space, transmission of data, etc.
• Intertask communications is executed using following mechanisms:

Message queues
• Send or receive messages placed in a shared memory.
• The queue may follow 1) First In First Out (FIFO), 2) Last in First Out(LIFO) or 3)
Priority (PRI) sequence.
• Usually, a message queue comprises of an associated queue control block (QCB),
name, unique ID, memory buffers, queue length, maximum message length and
one or more task waiting lists.
• Standard method for inter-task communication: Queue is allocated storage.
Definable size and number of entries. May contain data or pointers.
• Tasks can add messages: Many tasks can write message to the queue
• Tasks can pend on the queue.

20
Mailbox
• A message queue with a length of 1 is commonly known as a mailbox.
• What is it?
• Method to send ‘pointer’ sized asynchronous data between tasks.
• Often implemented as a simple queue.
• Tasks must agree on what ‘pointer’ points to
• Multiple tasks can wait on a message to be posted:
• Highest priority task wins in retrieving message.
• Multiple tasks can post a message:
• Only one message can be present in the mailbox at any time.
Pipes
• Provide simple communication channel used for unstructured data exchange
• A pipe does not store multiple messages but stream of bytes.
• Data flow from a pipe cannot be prioritized.
Remote procedure call (RPC)
• Permits distributed computing where task can invoke the execution of another
task on a remote computer.

21
Other services
Memory Management
• Two types of memory managements are provided in RTOS:
• Stack management – used during context switching for TCBs.
• Heap management – Memory other than memory used for program code,
program data and system stack is called heap memory
• Typical RTOSs provide memory allocation facilities:
• Frequently fixed block scheme.
• Deterministic service calls.
• Avoid memory fragmentation.
• RTOS System Calls for Memory Allocation:
• Allocate –allocate a block from memory.
• Free –release a block of memory.
• Query –query fixed block size, number of available blocks, etc. in a memory area

Timer Management
• Tasks need to be performed after scheduled durations. To keep track of the
delays, timers- relative and absolute- are provided in RTOS.
22
Interrupt and event handling
• RTOS provides various functions for interrupt and event handling:
• Defining interrupt handler
• Creation and deletion of ISR
• Referencing the state of an ISR
• Enabling and disabling of an interrupt
• Etc.

Device I/O Management


• RTOS generally provides large number of APIs to support diverse hardware
device drivers.

23
Priority Inversion
• What is it?
• When a lower priority task holds a resource that a higher priority task needs, the
higher priority task must wait (as if it were a lower priority task) until the lower
priority task releases the resource. In such scenario, the lower priority task executes
as if it has higher priority.
• Problem typically encountered in dealing with RTOS service like Semaphore
• Can be solved by Priority Inheritance:
• Not always the best solution, design it out!

24
Critical Sections
• What is it?
• A sequence of code that must execute atomically.
• E.g. update system data-structures
• Semaphores and Mutexes used to guard Critical Sections
• Locking interrupts (or scheduler) may be desirable:
• If manipulating only one variable or so.
• Less OS overhead.
• This may degenerate Interrupt Response

25
FreeRTOS: Overview
• FreeRTOS (Free Real-Time Operating System) is an open-source, lightweight real-
time operating system (RTOS) designed for embedded systems,
microcontrollers, and IoT devices.
• It provides task scheduling, resource management, and synchronization
features, allowing multiple tasks to run independently and efficiently on the
same processor.

Key Features:
• Multitasking with Task Scheduling
• FreeRTOS allows multiple tasks (functions running in parallel) to share the CPU.
• It uses a preemptive or cooperative scheduler to decide which task gets CPU time.
• Task
• Lightweight and Efficient
• Designed for microcontrollers with limited resources.
• Requires as little as 4KB of Flash memory and a few hundred bytes of RAM.
• Can run on bare-metal hardware without an underlying OS.

26
FreeRTOS: Overview
• Inter-Task Communication
• Queues: Tasks can send and receive messages safely.
• Semaphores & Mutexes: Prevents multiple tasks from accessing shared resources at the
same time (avoiding race conditions).
• Event Groups: Tasks can signal each other using events.
• Timers & Delays
• FreeRTOS provides software timers for executing functions at specific intervals.
• Tasks can be delayed using vTaskDelay() or vTaskDelayUntil().
• Portability & Hardware Support
• Supports hundreds of microcontrollers, including ESP32, STM32, ARM Cortex-M, AVR,
and PIC.
• Can be integrated into frameworks like ESP-IDF (for ESP32) and CMSIS-RTOS (for ARM
Cortex).

Why Use FreeRTOS?


• Run multiple tasks in parallel (e.g., handling Wi-Fi, sensors, and motors at the same
time).
• Better control over CPU usage compared to simple loop() structures.
• Efficient power management (tasks can sleep when not needed). 27
How FreeRTOS and Arduino Works on ESP32
• FreeRTOS is the Native OS of ESP32
• The ESP32 microcontroller comes with FreeRTOS (a real-time operating system) pre-
installed in its firmware.
• Unlike traditional Arduino boards (e.g., Uno or Mega), which run a single loop
continuously, the ESP32's firmware is designed around FreeRTOS, allowing multiple
tasks to run independently.
• The Arduino Core Runs as a FreeRTOS Task
• When you program the ESP32 using the Arduino IDE, your setup() and loop()
functions are actually running inside a FreeRTOS task.
• The Arduino core creates this task at system startup and assigns it a priority.
• This means that your regular Arduino code is already running within FreeRTOS, even
if you don't explicitly create FreeRTOS tasks yourself.
• The Arduino framework (ESP-IDF-based) initializes FreeRTOS automatically.
• It creates a default task (the "Arduino main task") that executes setup() once and
then runs loop() continuously.
• The ESP32 scheduler ensures that other system tasks (Wi-Fi, Bluetooth, background
services) can run alongside your code.

28
ESP32 FreeRTOS APIs
• The ESP32 uses the ESP-IDF framework, which includes a customized version of
FreeRTOS.
• The official documentation can be found at:
https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system
/freertos_idf.html#tasks

• Although the code examples are written in an ESP-IDF style (which differs from
the Arduino framework), the FreeRTOS APIs can still be used directly in the
Arduino IDE with minor modifications.
• The remaining slides will focus solely on the fundamental principles necessary
for basic multithreaded applications.
• For more in-depth information and a comprehensive understanding, please
refer to the API documentation and examples provide on the Control Software
Moodle page.

29
FreeRTOS: vTaskDelay() vs. delay()
• vTaskDelay() is a non-blocking FreeRTOS function that puts the calling task into
a "Blocked" state for a specified time, allowing other tasks to execute.
vTaskDelay(xTicksToDelay);

Parameters:

• xTicksToDelay – Number of RTOS ticks to delay the task.

• You can use pdMS_TO_TICKS(ms) to convert milliseconds to ticks.

Example:

vTaskDelay(pdMS_TO_TICKS(1000)); // Delays task for 1000ms (1 sec)

• delay(ms) is an Arduino function that halts execution for a given number of


milliseconds.
• It blocks the entire core, preventing other tasks from running.

• It wastes CPU time instead of letting other tasks execute.

• Must be avoided when using threads

30
FreeRTOS: xTaskCreate()
• Creates a new task and adds it to the list of tasks that are ready to run.
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority,
pxCreatedTask);

Parameters:

• pvTaskCode – The function that will run as the task (must have void functionName(void *pvParameters) format).

• pcName – A human-readable name for the task (useful for debugging).

• usStackDepth – The amount of stack memory allocated to the task (measured in words, not bytes).

• pvParameters – A pointer to data passed into the task when it starts (useful for passing configurations or task-specific
data).

• uxPriority – The priority level of the task (higher values mean higher priority).

• pxCreatedTask – A pointer to a variable that stores the handle of the created task (useful if the task needs to be
managed later). If not needed, this can be NULL.

Example:

xTaskCreate(Led0Thread, "Led0 Task", 1000, NULL, 1, NULL);

31
Task function Task name Stack size (1000 words) No parameters Priority 1 No task handle needed
FreeRTOS: vTaskDelete
• A task can be deleted using vTaskDelete():
vTaskDelete(NULL); // Deletes the current task

If deleting another task, pass the task handle instead of NULL.

32
FreeRTOS: Task/Thread Function
• In FreeRTOS, a task (also called a thread) is a function that runs independently
and is managed by the FreeRTOS scheduler.
• A FreeRTOS task must follow this structure:
void TaskFunction(void *pvParameters) {
while(1) { // Infinite loop (tasks usually run forever)
// Task code here

vTaskDelay(pdMS_TO_TICKS(1000)); // Non-blocking
delay
}
}
• void *pvParameters – Allows passing parameters to the task.

• while(1) – Tasks usually run indefinitely unless deleted.

• vTaskDelay(pdMS_TO_TICKS(1000)) – Prevents CPU overuse and enables multitasking.

33
#define led0Pin 4 //LED0
Thread Example: #define led1Pin 16 //LED1
#define led2Pin 17 //LED2

// Task/thread that blinks LED0 at 200ms


void Led0Thread(void *parameter) {
while (1) {
digitalWrite(led0Pin, !digitalRead(led0Pin));
vTaskDelay(pdMS_TO_TICKS(200));
}
}

// Task/thread that blinks LED1 at 500ms


void Led1Thread(void *parameter) {
while (1) {
digitalWrite(led1Pin, !digitalRead(led1Pin));
vTaskDelay(pdMS_TO_TICKS(500));
}
}

void setup() {
pinMode(led0Pin, OUTPUT);
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);

xTaskCreate(Led0Thread, "Led0 Task", 1000, NULL, 1,


NULL);
xTaskCreate(Led1Thread, "Led1 Task", 1000, NULL, 1,
NULL);
}

// loop() is also a thread that blinks LED2 at 2sec


void loop() {
digitalWrite(led2Pin, !digitalRead(led2Pin));
34
vTaskDelay(pdMS_TO_TICKS(2000));
FreeRTOS: Event Groups
• Event groups are a lightweight synchronization mechanism used to manage
multiple binary flags (bits) within a single 32-bit variable.
• These flags help coordinate tasks by allowing them to set, clear, and wait for
specific events.
• An event group is a 32-bit variable where each bit represents a different event
flag.
• A task can set (turn 1) or clear (turn 0) specific bits.
• Other tasks can wait for one or multiple bits to be set before proceeding.

Creating an Event Group


• Before using event groups, create one with xEventGroupCreate():
EventGroupHandle_t myEventGroup;

void setup() {
// Create the event group
myEventGroup = xEventGroupCreate();
}

• xEventGroupCreate() initializes an empty event group (all bits = 0).


• myEventGroup is now ready for tasks to use. 35
FreeRTOS: Event Groups
Defining Event Flags
• Each bit position represents a different event. Define them using bitwise
notation:
#define EVENT_A 0b00000000000000000000000000000001
#define EVENT_B 0b00000000000000000000000000010000
#define EVENT_C 0b00000000000000000000000000000100

Setting and Clearing Bits


• Use xEventGroupSetBits() to set
• a specific bit:
xEventGroupSetBits(myEventGroup, EVENT_C); // Set Bit for EVENT C (Event occurs)
(bit2)
• multiple bits:
xEventGroupSetBits(myEventGroup, EVENT_A | EVENT_B | EVENT_C); //Set Bits for
all 3 EVENTS (bit0, bit4, bit2)
• Use xEventGroupClearBits() to clear
• a specific bit:
xEventGroupClearBits(myEventGroup, EVENT_C); // Clear Bit 0 Bit for EVENT C
(bit2)
• multiple bits:
xEventGroupClearBits(myEventGroup, EVENT_A | EVENT_C); // Clear Bits for EVENT A
and C (bit0, bit2)
36
FreeRTOS: Event Groups
Waiting for Events
• A task can wait for one or multiple bits using xEventGroupWaitBits():
EventBits_t events = xEventGroupWaitBits(
EventGroup,
BitsToWaitFor,
ClearOnExit,
WaitForAllBits,
TicksToWait
);

• events will be used later to test which bit was set exactly

Parameters:

• EventGroup – The handle to the event group that was created earlier.

• BitsToWaitFor – The bit (or bits) that the task is waiting for.

• ClearOnExit – Should the bit be cleared automatically after the task unblocks? (pdTRUE = yes, pdFALSE = no)

• WaitForAllBits – Should the function wait for all bits or just any one? (pdTRUE = yes, pdFALSE = no)

• TicksToWait – How long should the task wait?

• portMAX_DELAY – Wait indefinitely (forever) until the bit is set.

• pdMS_TO_TICKS(5000) – Wait 5 seconds, then timeout if the bit isn’t set. 37


FreeRTOS: Event Groups
• Waiting for a single event. It will unblock as soon as EVENT_A bit is set:
EventBits_t events = xEventGroupWaitBits(myEventGroup, EVENT_A, pdTRUE, pdFALSE,
portMAX_DELAY);

• Waiting for any one of multiple bits. This means that if any of EVENT_A or
EVENT_C bits are set, the task unblocks.
EventBits_t events = xEventGroupWaitBits(myEventGroup, EVENT_A | EVENT_C, pdTRUE, pdFALSE,
portMAX_DELAY);

• Waiting for all bits to be set before continuing.


EventBits_t events = xEventGroupWaitBits(myEventGroup, EVENT_A | EVENT_B, pdTRUE, pdTRUE,
portMAX_DELAY);

• Waiting for a single bit to be set OR a timeout of 5 seconds before continuing.


EventBits_t events = xEventGroupWaitBits(myEventGroup, EVENT_A, pdTRUE, pdFALSE,
pdMS_TO_TICKS(5000));

38
FreeRTOS: Event Groups
Testing which bits were set
• After calling xEventGroupWaitBits(), the returned value (events in our case)
contains the event bits that were set at the time the function unblocked.
• You can test which bits were set using bitwise AND (&) operations.
EventBits_t events = xEventGroupWaitBits(myEventGroup, EVENT_A | EVENT_B, pdTRUE,
pdFALSE, pdMS_TO_TICKS(5000));

if (events & EVENT_A) {


// EVENT_A bit was set
}
else if (events & EVENT_B) {
// EVENT_B bit was set
}
else if (events & (EVENT_A | EVENT_B)) {
// Either EVENT_A or EVENT_B bits (or both) were set
}
else if ((events & (EVENT_A | EVENT_B)) == (EVENT_A | EVENT_B)) {
//Both EVENT_A and EVENT_B bits were set
}
else {
//5 seconds passed without either EVENT_A or EVENT_B becoming set.
}

39
EventFlags Example:
Consider the following room temperature control system, which consist of:
• A heater – to increase the temperature in the room
• A temperature sensor – measures the temperature (0V = 0°C; 3V = 100°C)
• A LED – to indicate when temperature is too low or too high

The control sequence:


• Heater is OFF
• When temp < 30°C, heater must be 50% ON
• After 2 seconds the heater must be 100% ON. During 2 second delay
temperature input has no effect.
• When temp rises above 60°C, heater must be OFF
• At any stage when the temp < 30°C OR temp > 60°C, the LED must flash at
100mS intervals. When temp is in range again, the LED must be OFF.

Could do this with a State Machine and a Timer… (will attempt this first in class) OR
we could use RTOS…
40
define TEMP_HIGH 0b00000000000000000000000000000001
#define TEMP_LOW 0b00000000000000000000000000000100

#define LED_PIN 4 //LED0


#define HEATER_PIN 23 //LED7 (PWM)
#define TEMP_PIN 13 //POT

TaskHandle_t LedTaskHandle;
TaskHandle_t HeaterTaskHandle;
EventGroupHandle_t MyEventFlags;

void LedControlTask(void *parameter) {


while (1) {
// Wait for either TEMP_HIGH or TEMP_LOW flag
EventBits_t bits = xEventGroupWaitBits(MyEventFlags, TEMP_HIGH | TEMP_LOW,
pdTRUE, pdFALSE, portMAX_DELAY);

if (bits & (TEMP_HIGH | TEMP_LOW)) {


digitalWrite(LED_PIN, HIGH);
vTaskDelay(pdMS_TO_TICKS(100));
digitalWrite(LED_PIN, LOW);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
}

41
void HeaterControlTask(void *parameter) {
while (1) {
// Wait for only TEMP_LOW flag
xEventGroupWaitBits(MyEventFlags, TEMP_LOW, pdTRUE, pdTRUE, portMAX_DELAY);
ledcWrite(HEATER_PIN, 128); // 50% duty cycle (heater on)
vTaskDelay(pdMS_TO_TICKS(2000));
ledcWrite(HEATER_PIN, 255); // 100% duty cycle

// Wait for only TEMP_HIGH flag


xEventGroupWaitBits(MyEventFlags, TEMP_HIGH, pdTRUE, pdTRUE, portMAX_DELAY);
ledcWrite(HEATER_PIN, 0); // Heater off
}
}

void setup() {
pinMode(LED_PIN, OUTPUT);
pinMode(TEMP_PIN, INPUT);
ledcAttach(HEATER_PIN, 1000, 8); // 1 kHz PWM, 8-bit resolution

MyEventFlags = xEventGroupCreate();

xTaskCreate(LedControlTask, "LED Task", 1000, NULL, 1, &LedTaskHandle);


xTaskCreate(HeaterControlTask, "Heater Task", 1000, NULL, 1, &HeaterTaskHandle);
}

void loop() {
float tempValue = analogRead(TEMP_PIN) / 4095.0; // Normalize ADC value (0.0 -
1.0)

if (tempValue > 0.6)


xEventGroupSetBits(MyEventFlags, TEMP_HIGH);
if (tempValue < 0.3)
xEventGroupSetBits(MyEventFlags, TEMP_LOW);

vTaskDelay(pdMS_TO_TICKS(100)); // Small delay to avoid excessive ADC reads


42
}
FreeRTOS: Mutex
• A mutex (mutual exclusion) is a synchronization primitive used to protect shared
resources from concurrent access by multiple tasks.
• It ensures that only one task at a time can access a critical section (a portion of
code that manipulates shared resources), preventing race conditions and
maintaining data integrity.
• FreeRTOS implements mutexes as a special type of binary semaphore that
includes priority inheritance – prevents priority inversion (a situation where a
high-priority task gets blocked by a lower-priority task holding the mutex).
• If a high-priority task is waiting for a mutex held by a lower-priority task, FreeRTOS
temporarily raises the priority of the lower-priority task to prevent priority inversion.
• The Mutex methods cannot be called from ISR
• When to Use Mutex in FreeRTOS:
• When multiple tasks share a resource (e.g., LED, serial communication, memory
buffers).
• When data consistency is required across multiple tasks.
• When a task should not be interrupted while accessing a resource.
• Mutexes are not suitable for event signaling between tasks; binary semaphores
are better for that.
43
FreeRTOS: Mutex
Creating a Mutex
SemaphoreHandle_t myMutex = xSemaphoreCreateMutex();
• This returns a handle (myMutex) to the mutex, which can be used in task synchronization.

Acquiring the Mutex (Locking)


• When a task wants exclusive access to a shared resource, it takes the mutex:
xSemaphoreTake(Semaphore, BlockTime)
• If the mutex is available, the task gets ownership immediately.
• If another task is holding the mutex, the calling task blocks until the mutex is released (or a
timeout occurs).
Parameters:
• Semaphore – This is the handle of the semaphore or mutex that the task is attempting to take.

• BlockTime – Specifies how long the task should wait if the semaphore is not available.

Example:

xSemaphoreTake(myMutex, portMAX_DELAY);

• The portMAX_DELAY tells the task to wait indefinitely until the mutex is available. Other options:

• 0 – Do not wait; return immediately if the semaphore is not available.


44
• Any other positive value – Wait for that many ticks before giving up.
FreeRTOS: Mutex
Releasing the Mutex (Unlocking)
• Once the task is done with the shared resource, it gives the mutex back:
xSemaphoreGive(myMutex);
• This allows other waiting tasks to acquire it.

45
Mutex Example:
Consider the following system which consist of:
• A LED (LED0 on SwLed Shield)
• A push button (PB3 on SwLed Shield)
• A push button (PB0 on SwLed Shield)

The operation is as follows:


• LED is flashed at 500mS intervals
• When the PB3 is pressed, the LED must immediately be turned ON and stay ON
until the push button is released.
• When the PB0 is pressed, the LED must immediately be turned OFF and stay
OFF until the push button is released.
• In the case of both push buttons being pressed simultaneously, the button
pressed first takes preference.

46
Solution:
Could do this with a Flowchart and Interrups and Timers… (will attempt this first in
class) OR we could use RTOS…
Using threads we could … :
• Thread 1 (loop()) to flash LED
• Thread 2 to turn LED ON
• Thread 3 to turn LED OFF

#define ledPin 4 //LED0


#define pb0Pin 35 //PB0
#define pb3Pin 36 //PB3

SemaphoreHandle_t myMutex;

void test_thread2(void *pvParameters) { // Task for turning LED On


while (1) {
if (digitalRead(pb3Pin) == LOW) { // When pb3Pin is pressed
xSemaphoreTake(myMutex, portMAX_DELAY); // Lock access to LED
digitalWrite(ledPin, HIGH); // LED ON
while (digitalRead(pb3Pin) == LOW) { } //stay in the while loop until pb is released
xSemaphoreGive(myMutex); // Release access to LED
}
}
}

47
void test_thread3(void *pvParameters) { // Task for turning LED Off
while (1) {
if (digitalRead(pb0Pin) == LOW) { // When pb0Pin is pressed
xSemaphoreTake(myMutex, portMAX_DELAY); // Lock access to LED
digitalWrite(ledPin, LOW); // LED OFF
while (digitalRead(pb0Pin) == LOW) { } //stay in the while loop until pb is released
xSemaphoreGive(myMutex); // Release access to LED
}
}
}

void setup() {
pinMode(ledPin, OUTPUT);
pinMode(pb0Pin, INPUT_PULLUP);
pinMode(pb3Pin, INPUT_PULLUP);

myMutex = xSemaphoreCreateMutex();

xTaskCreate(test_thread2, "Task2", 2048, NULL, 1, NULL);


xTaskCreate(test_thread3, "Task3", 2048, NULL, 1, NULL);
}

void loop() { // Main task (flashes LED)


xSemaphoreTake(myMutex, portMAX_DELAY);
digitalWrite(ledPin, !digitalRead(ledPin)); // Toggle LED output
xSemaphoreGive(myMutex);
vTaskDelay(500 / portTICK_PERIOD_MS); // Wait 500ms
}

48

You might also like