IoT/ESP32 B.Tech/Diploma Beginner

ESP32 FreeRTOS Mutex – Getting Started (Arduino IDE)

Learn how to use a FreeRTOS Mutex with the ESP32 programmed with Arduino IDE. A Mutex (Mutual Exclusion) is a special type of binary semaphore that controls access to shared resources between two or more tasks

  • Suitable forB.Tech/Diploma IoT/ESP32 students
  • Build time1-2 weeks
  • LevelBeginner
  • Available atAjvika Labs, Kakinada

About this project

In this guide, you’ll learn how to use a FreeRTOS Mutex with the ESP32 programmed with Arduino IDE. A Mutex (Mutual Exclusion) is a special type of
binary semaphore
that controls access to shared resources between two or more tasks. This guarantees that only one task can access a critical resource at a time. We’ll explain the basics of a Mutex and show you a simple example of how to implement them.
New to FreeRTOS?
Start with this tutorial:
ESP32 with FreeRTOS (Arduino IDE)—Getting Started Guide: Creating Tasks
Table of Contents
In this tutorial, we’ll cover the following subjects:
Introducing Mutexes
ESP32 Scenarios
Mutex and Priority Inheritance
Application Examples of Mutex Use on ESP32 Projects
Mutex Basic Functions
Creating a Mutex
Taking a Mutex
Giving a Mutex
ESP32 Mutex Example: Shared Serial Output
Shared Serial Output (Without Mutex)
Shared Serial Output (With Mutex)
Introducing Mutexes
A mutex is a special type of binary semaphore (
check our tutorial about semaphores
) used to control access to a resource shared between two or more tasks. It is created with
xSemaphoreCreateMutex()
and ensures that only one task can use the resource at a time.
The term “mutex” stands for “
MUT
ual
EX
clusion,” and it works like a token that allows whichever task holds the token to access the shared resource safely. To use a mutex, a task must first “take” it with
xSemaphoreTake(mutex, timeout)
to become the
token holder
and enter the critical section (the code that accesses the resource). When the task finishes, it “gives” the mutex back with
xSemaphoreGive(mutex)
, unlocking it for other tasks. Only then can another task take the mutex and access the resource without conflicts.
The following diagram shows how it works.
Using a mutex to guard access to a shared resource
(Image Source:
freertos.org
)
ESP32 Scenarios
For example, imagine a scenario where two tasks are making HTTP requests to save data to a database. Without a mutex, both tasks might try to access and write to the database at the same time, risking data corruption because one task starts a new HTTP request before the other finishes. With a mutex, you can guarantee that only one task accesses the database at a time, ensuring safe, sequential operations.
This concept applies to many scenarios, such as shared access to the Serial port by multiple tasks, the I2C bus for sensors and displays, multiple tasks reading from the same sensor, multiple tasks writing data to the same display, etc.
Mutex and Priority Inheritance
In FreeRTOS, when a task holds a mutex, it keeps control of the shared resource until it releases the token. If a low-priority task is holding the mutex and a high-priority task tries to take it, the high-priority task will be forced to wait. This situation is called priority inversion because a low-priority task is effectively blocking a higher-priority one from running.
To handle this, FreeRTOS implements priority inheritance. When a high-priority task is waiting for a mutex held by a lower-priority task, the lower-priority task temporarily “inherits” the higher priority. This allows it to finish its work and release the mutex sooner, reducing the delay for the high-priority task. Once the mutex is released, the task’s priority returns to its original level.
So, in summary:
Priority inversion
happens when a low-priority task holds a mutex and blocks a high-priority task that needs it.
The high-priority task can’t run until the low-priority task releases the mutex.
FreeRTOS uses
priority inheritance
to fix this.
The low-priority task temporarily inherits the high priority.
This lets it finish its work faster and release the mutex sooner.
Once released, the task’s priority goes back to normal.
Finally, another important thing about mutexes is that they
should not be used from an interrupt
because (
quoting FreeRTOS documentation
):
They include a priority inheritance mechanism which only makes sense if the mutex is given and taken from a task, not an interrupt.
An interrupt cannot block to wait for a resource that is guarded by a mutex to become available.
Application Examples of Mutex Use on ESP32 Projects
The use of FreeRTOS mutexes can be useful for your ESP32 IoT projects. For example:
Shared Sensor Data
: for example, multiple tasks need to read or update the same sensor values.
Display Output
: multiple tasks need to print to the Serial Monitor or to a display. We must ensure that only one task outputs data at a time so that its outputs do not overlap. We’ll take a look at this example in this tutorial.
Wi-Fi Operations
: if different tasks perform
HTTP requests
MQTT
publishing, or
WebSocket communication
, a mutex prevents simultaneous access to the same network resource, avoiding connection errors or database corruption.
Logging data to SD Card or LittleFS
:
writing to the flash memory
or
an SD card
must be done carefully to avoid corruption. With a mutex, we ensure that one task finishes the operation before the other can start.
Mutex Basic Functions
Here are some basic functions for creating and handling a mutex using the ESP32 with Arduino IDE. We’ll explore these functions in a practical example next.
Creating a Mutex
To create a mutex, use
xSemaphoreCreateMutex()
. It returns a
SemaphoreHandle_t
handle or
NULL
if the creation fails.
Taking a Mutex
To take a mutex (and gain access to the shared resource), use
xSemaphoreTake(mutex, timeout)
. The timeout is the maximum time the task will block waiting for the mutex to become available. Use
portMAX_DELAY
for the timeout if you want the task to wait indefinitely.
Giving a Mutex
To give the mutex (to release it so that other tasks can access the shared resource), use
xSemaphoreGive(mutex)
, unblocking a waiting task. This should always be called after the critical section to release the resource.
ESP32 Mutex Example: Shared Serial Output
To show you how you can use a Mutex with the ESP32 and how it works, we’ll take a look at a simple shared serial output example. We’ll test the code with and without a Mutex so that you can see how it works.
Here’s the example we’ll run:
We’ll create two different tasks.
Each task will print two lines of text to the Serial Monitor, with a small delay between the lines.
The tasks run at different intervals, so their outputs could overlap.
We don’t want the overlap to happen.
By using a
mutex
, we make sure each task finishes printing its two lines
before
the other task starts writing.
First, we’ll run the example without a mutex. Then, we’ll run it again using a mutex to show the difference.
Shared Serial Output (Without Mutex)
Upload the following code to your ESP32 board.
/*
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
void Task1(void *parameter) {
for (;;) {
Serial.println(\"Task1: Logging from Task 1\");
vTaskDelay(1000 / portTICK_PERIOD_MS);
Serial.println(\"Task1: End of log from Task 1\");
vTaskDelay(5000 / portTICK_PERIOD_MS);
}
}

void Task2(void *parameter) {
for (;;) {
Serial.println(\"Task2: Logging from Task 2\");
vTaskDelay(800 / portTICK_PERIOD_MS);
Serial.println(\"Task2: End of log from Task 2\");
vTaskDelay(3000 / portTICK_PERIOD_MS);
}
}

void setup() {
Serial.begin(115200);
delay(1000);
Serial.println(\"Starting FreeRTOS\");

xTaskCreatePinnedToCore(
Task1, // Task function
\"Task1\", // Task name
3000, // Stack size
NULL, // Task parameters
1, // Priority
NULL, // Task handle
1

Technologies used

ESP32ArduinoMQTTBLEI2CArduino IDE

Hardware components

  • ESP32
  • Arduino
  • SD Card

Software & tools

  • Arduino IDE
  • MQTT

What you get

  • Working project / hardware kit, tested before delivery
  • Complete source code with explanation
  • Project demo and guidance for your viva
  • Project report, PPT and IEEE paper support (on request)
Delivery & Payment
Delivery takes a minimum of two weeks from the date your inquiry is confirmed. Payment is in two parts: • 50% advance to start the project • Remaining 50% before delivery Note: • Documentation and PPT are not included by default • If you need documentation/PPT, it can be arranged for extra time and cost We'll confirm the exact timeline and cost with you after reviewing your requirements.