{"id":181013,"date":"2026-01-15T14:54:49","date_gmt":"2026-01-15T14:54:49","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=181013"},"modified":"2026-01-15T15:10:44","modified_gmt":"2026-01-15T15:10:44","slug":"esp32-freertos-mutex-arduino","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-freertos-mutex-arduino\/","title":{"rendered":"ESP32 FreeRTOS Mutex &#8211; Getting Started (Arduino IDE)"},"content":{"rendered":"\n<p>In this guide, you&#8217;ll learn how to use a FreeRTOS Mutex with the ESP32 programmed with Arduino IDE. A Mutex (Mutual Exclusion) is a special type of <a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-semaphores-arduino\/\" title=\"\">binary semaphore<\/a> 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&#8217;ll explain the basics of a Mutex and show you a simple example of how to implement them.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/ESP32-FreeRTOS-Mutex.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 with FreeRTOS - Getting Started with Mutex Arduino IDE Core\" class=\"wp-image-181438\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/ESP32-FreeRTOS-Mutex.jpg?w=1920&amp;quality=100&amp;strip=all&amp;ssl=1 1920w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/ESP32-FreeRTOS-Mutex.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/ESP32-FreeRTOS-Mutex.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/ESP32-FreeRTOS-Mutex.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/ESP32-FreeRTOS-Mutex.jpg?resize=1536%2C864&amp;quality=100&amp;strip=all&amp;ssl=1 1536w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclgreen\"><strong>New to FreeRTOS?&nbsp;<\/strong>Start with this tutorial:&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-arduino-tasks\/\">ESP32 with FreeRTOS (Arduino IDE)\u2014Getting Started Guide: Creating Tasks<\/a>.<\/p>\n\n\n\n<p><strong>Table of Contents<\/strong><\/p>\n\n\n\n<p>In this tutorial, we&#8217;ll cover the following subjects:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#mutex-intro\" title=\"\">Introducing Mutexes<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"#esp32-scenarios\" title=\"\">ESP32 Scenarios<\/a><\/li>\n\n\n\n<li><a href=\"#priority-inheritance\" title=\"\">Mutex and Priority Inheritance<\/a><\/li>\n\n\n\n<li><a href=\"#esp32-applications\" title=\"\">Application Examples of Mutex Use on ESP32 Projects<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><a href=\"#mutex-functions\" title=\"\">Mutex Basic Functions<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"#create-mutex\" title=\"\">Creating a Mutex<\/a><\/li>\n\n\n\n<li><a href=\"#take-mutex\" title=\"\">Taking a Mutex<\/a><\/li>\n\n\n\n<li><a href=\"#give-mutex\" title=\"\">Giving a Mutex<\/a><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><a href=\"#esp32-mutex-example\" title=\"\">ESP32 Mutex Example: Shared Serial Output<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"#esp32-shared-serial-output-example-no-mutex\" title=\"\">Shared Serial Output (Without Mutex)<\/a><\/li>\n\n\n\n<li><a href=\"#esp32-shared-serial-output-with-mutex\" title=\"\">Shared Serial Output (With Mutex)<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"mutex-intro\">Introducing Mutexes<\/h2>\n\n\n\n<p>A mutex is a special type of binary semaphore (<a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-semaphores-arduino\/\" title=\"\">check our tutorial about semaphores<\/a>) used to control access to a resource shared between two or more tasks. It is created with <span class=\"rnthl rntliteral\">xSemaphoreCreateMutex()<\/span> and ensures that only one task can use the resource at a time.<\/p>\n\n\n\n<p>The term &#8220;mutex&#8221; stands for &#8220;<strong>MUT<\/strong>ual <strong>EX<\/strong>clusion,&#8221; 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 &#8220;take&#8221; it with <span class=\"rnthl rntliteral\">xSemaphoreTake(mutex, timeout)<\/span> to become the <em>token holder<\/em> and enter the critical section (the code that accesses the resource). When the task finishes, it &#8220;gives&#8221; the mutex back with <span class=\"rnthl rntliteral\">xSemaphoreGive(mutex)<\/span>, unlocking it for other tasks. Only then can another task take the mutex and access the resource without conflicts.<\/p>\n\n\n\n<p>The following diagram shows how it works.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Mutual-Exclusion-Using-Mutex-FreeRTOS.jpeg?quality=100&#038;strip=all&#038;ssl=1\" target=\"_blank\" rel=\" noreferrer noopener\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"429\" height=\"896\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Mutual-Exclusion-Using-Mutex-FreeRTOS.jpeg?resize=429%2C896&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Diagram showing how mutual exclusion works with FreeRTOS tasks\" class=\"wp-image-181439\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Mutual-Exclusion-Using-Mutex-FreeRTOS.jpeg?w=429&amp;quality=100&amp;strip=all&amp;ssl=1 429w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Mutual-Exclusion-Using-Mutex-FreeRTOS.jpeg?resize=144%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 144w\" sizes=\"(max-width: 429px) 100vw, 429px\" \/><\/a><figcaption class=\"wp-element-caption\"><em>Using a mutex to guard access to a shared resource<\/em> (Image Source: <a href=\"https:\/\/www.freertos.org\/Documentation\/02-Kernel\/02-Kernel-features\/02-Queues-mutexes-and-semaphores\/04-Mutexes\" target=\"_blank\" rel=\"noopener\" title=\"\">freertos.org<\/a>)<\/figcaption><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"esp32-scenarios\">ESP32 Scenarios<\/h3>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"priority-inheritance\">Mutex and Priority Inheritance<\/h3>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>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 \u201cinherits\u201d 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\u2019s priority returns to its original level.<\/p>\n\n\n\n<p>So, in summary:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Priority inversion<\/strong> happens when a low-priority task holds a mutex and blocks a high-priority task that needs it.<\/li>\n\n\n\n<li>The high-priority task can\u2019t run until the low-priority task releases the mutex.<\/li>\n\n\n\n<li>FreeRTOS uses <strong>priority inheritance<\/strong> to fix this.<\/li>\n\n\n\n<li>The low-priority task temporarily inherits the high priority.<\/li>\n\n\n\n<li>This lets it finish its work faster and release the mutex sooner.<\/li>\n\n\n\n<li>Once released, the task\u2019s priority goes back to normal.<\/li>\n<\/ul>\n\n\n\n<p>Finally, another important thing about mutexes is that they <span style=\"text-decoration: underline;\"><em>should not be used from an interrupt<\/em><\/span> because (<a href=\"https:\/\/www.freertos.org\/Documentation\/02-Kernel\/02-Kernel-features\/02-Queues-mutexes-and-semaphores\/04-Mutexes\" target=\"_blank\" rel=\"noopener\" title=\"\">quoting FreeRTOS documentation<\/a>):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>They include a priority inheritance mechanism which only makes sense if the mutex is given and taken from a task, not an interrupt.<\/li>\n\n\n\n<li>An interrupt cannot block to wait for a resource that is guarded by a mutex to become available.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"esp32-applications\"><strong>Application Examples of Mutex Use on ESP32 Projects<\/strong><\/h3>\n\n\n\n<p>The use of FreeRTOS mutexes can be useful for your ESP32 IoT projects. For example:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Display-Data-Received-Via-ESP-NOW-Table.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 CYD Board Displaying Data received via ESP-NOW on a table\" class=\"wp-image-171765\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Display-Data-Received-Via-ESP-NOW-Table.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Display-Data-Received-Via-ESP-NOW-Table.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Shared Sensor Data<\/strong>: for example, multiple tasks need to read or update the same sensor values.<\/li>\n\n\n\n<li><strong>Display Output<\/strong>: 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&#8217;ll take a look at this example in this tutorial.<\/li>\n\n\n\n<li><strong>Wi-Fi Operations<\/strong>: if different tasks perform <a href=\"https:\/\/randomnerdtutorials.com\/esp32-https-requests\/\" title=\"\">HTTP requests<\/a>, <a href=\"https:\/\/randomnerdtutorials.com\/what-is-mqtt-and-how-it-works\/\" title=\"\">MQTT <\/a>publishing, or <a href=\"https:\/\/randomnerdtutorials.com\/esp32-websocket-server-sensor\/\" title=\"\">WebSocket communication<\/a>, a mutex prevents simultaneous access to the same network resource, avoiding connection errors or database corruption.<\/li>\n\n\n\n<li><strong>Logging data to SD Card or LittleFS<\/strong>: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-write-data-littlefs-arduino\/\" title=\"\">writing to the flash memory<\/a> or <a href=\"https:\/\/randomnerdtutorials.com\/esp32-microsd-card-arduino\/\" title=\"\">an SD card<\/a> must be done carefully to avoid corruption. With a mutex, we ensure that one task finishes the operation before the other can start.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"mutex-functions\">Mutex Basic Functions<\/h2>\n\n\n\n<p>Here are some basic functions for creating and handling a mutex using the ESP32 with Arduino IDE. We\u2019ll explore these functions in a practical example next.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"create-mutex\">Creating a Mutex<\/h3>\n\n\n\n<p>To create a mutex, use <span class=\"rnthl rntliteral\">xSemaphoreCreateMutex()<\/span>. It returns a <span class=\"rnthl rntliteral\">SemaphoreHandle_t<\/span> handle or <span class=\"rnthl rntliteral\">NULL<\/span> if the creation fails.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"take-mutex\">Taking a Mutex<\/h3>\n\n\n\n<p>To take a mutex (and gain access to the shared resource), use <span class=\"rnthl rntliteral\">xSemaphoreTake(mutex, timeout)<\/span>. The timeout is the maximum time the task will block waiting for the mutex to become available. Use <span class=\"rnthl rntliteral\">portMAX_DELAY<\/span> for the timeout if you want the task to wait indefinitely.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"give-mutex\">Giving a Mutex<\/h3>\n\n\n\n<p>To give the mutex (to release it so that other tasks can access the shared resource), use <span class=\"rnthl rntliteral\">xSemaphoreGive(mutex)<\/span>, unblocking a waiting task. This should always be called after the critical section to release the resource.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"esp32-mutex-example\">ESP32 Mutex Example: Shared Serial Output<\/h2>\n\n\n\n<p>To show you how you can use a Mutex with the ESP32 and how it works, we&#8217;ll take a look at a simple shared serial output example. We&#8217;ll test the code with and without a Mutex so that you can see how it works.<\/p>\n\n\n\n<p>Here&#8217;s the example we&#8217;ll run:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>We&#8217;ll create two different tasks.<\/li>\n\n\n\n<li>Each task will print two lines of text to the Serial Monitor, with a small delay between the lines.<\/li>\n\n\n\n<li>The tasks run at different intervals, so their outputs could overlap.<\/li>\n\n\n\n<li>We don&#8217;t want the overlap to happen.<\/li>\n\n\n\n<li>By using a <strong>mutex<\/strong>, we make sure each task finishes printing its two lines <strong>before<\/strong> the other task starts writing.<\/li>\n<\/ul>\n\n\n\n<p>First, we\u2019ll run the example without a mutex. Then, we\u2019ll run it again using a mutex to show the difference.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"esp32-shared-serial-output-example-no-mutex\">Shared Serial Output (Without Mutex)<\/h3>\n\n\n\n<p>Upload the following code to your ESP32 board.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-freertos-mutex-arduino\/\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\/\nvoid Task1(void *parameter) {\n  for (;;) {\n    Serial.println(&quot;Task1: Logging from Task 1&quot;);\n    vTaskDelay(1000 \/ portTICK_PERIOD_MS);\n    Serial.println(&quot;Task1: End of log from Task 1&quot;);\n    vTaskDelay(5000 \/ portTICK_PERIOD_MS);\n  }\n}\n\nvoid Task2(void *parameter) {\n  for (;;) {\n    Serial.println(&quot;Task2: Logging from Task 2&quot;);\n    vTaskDelay(800 \/ portTICK_PERIOD_MS);\n    Serial.println(&quot;Task2: End of log from Task 2&quot;);\n    vTaskDelay(3000 \/ portTICK_PERIOD_MS);\n  }\n}\n\nvoid setup() {\n  Serial.begin(115200);\n  delay(1000);\n  Serial.println(&quot;Starting FreeRTOS&quot;);\n\n  xTaskCreatePinnedToCore(\n    Task1,                  \/\/ Task function\n    &quot;Task1&quot;,                \/\/ Task name\n    3000,                   \/\/ Stack size\n    NULL,                   \/\/ Task parameters\n    1,                      \/\/ Priority\n    NULL,                   \/\/ Task handle\n    1                       \/\/ Core ID\n  );\n\n  xTaskCreatePinnedToCore(\n    Task2,                  \/\/ Task function\n    &quot;Task2&quot;,                \/\/ Task name\n    3000,                   \/\/ Stack size\n    NULL,                   \/\/ Task parameters\n    2,                      \/\/ Higher priority\n    NULL,                   \/\/ Task handle\n    1                       \/\/ Core ID\n  );\n}\n\nvoid loop() {\n\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/FreeRTOS\/Serial_Output_No_Mutex.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>This code creates two tasks. Both write two lines of text to the Serial Monitor.<\/p>\n\n\n\n<p>Here&#8217;s one task:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void Task1(void *parameter) {\n  for (;;) {\n    Serial.println(\"Task1: Logging from Task 1\");\n    vTaskDelay(1000 \/ portTICK_PERIOD_MS);\n    Serial.println(\"Task1: End of log from Task 1\");\n    vTaskDelay(5000 \/ portTICK_PERIOD_MS);\n  }\n}<\/code><\/pre>\n\n\n\n<p>And here&#8217;s the other:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void Task2(void *parameter) {\n  for (;;) {\n    Serial.println(\"Task2: Logging from Task 2\");\n    vTaskDelay(800 \/ portTICK_PERIOD_MS);\n    Serial.println(\"Task2: End of log from Task 2\");\n    vTaskDelay(3000 \/ portTICK_PERIOD_MS);\n  }\n}<\/code><\/pre>\n\n\n\n<p>Now, after uploading the code, press the ESP32 RST button and open the Serial Monitor. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"666\" height=\"382\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/ESP32-shared-serial-output-no-mutex.png?resize=666%2C382&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 shared serial output without mutex. One task runs before the other has finished\" class=\"wp-image-181296\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/ESP32-shared-serial-output-no-mutex.png?w=666&amp;quality=100&amp;strip=all&amp;ssl=1 666w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/ESP32-shared-serial-output-no-mutex.png?resize=300%2C172&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>You\u2019ll see that one task can print its output while the other is still running, causing their outputs to overlap. This example demonstrates what can happen in similar situations, such as printing data to a display or writing to a database. To prevent this, we can use a mutex\u2014see the following example.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"esp32-shared-serial-output-with-mutex\">Shared Serial Output (With Mutex)<\/h3>\n\n\n\n<p>This example works the same way as the previous one, but now we use a mutex so one task can\u2019t run until the other releases it.<\/p>\n\n\n\n<p>Here&#8217;s the code to upload to the ESP32:<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-freertos-mutex-arduino\/\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\/\n#define MUTEX_TIMEOUT 5000  \/\/ 5s timeout\n\nSemaphoreHandle_t serialMutex = NULL;\n\nvoid Task1(void *parameter) {\n  for (;;) {\n    if (xSemaphoreTake(serialMutex, MUTEX_TIMEOUT)) {\n      Serial.println(&quot;Task1: Logging from Task 1&quot;);\n      vTaskDelay(1000 \/ portTICK_PERIOD_MS);\n      Serial.println(&quot;Task1: End of log from Task 1&quot;);\n      xSemaphoreGive(serialMutex);\n    }\n    vTaskDelay(5000 \/ portTICK_PERIOD_MS);\n  }\n}\n\nvoid Task2(void *parameter) {\n  for (;;) {\n    if (xSemaphoreTake(serialMutex, MUTEX_TIMEOUT)) {\n      Serial.println(&quot;Task2: Logging from Task 2&quot;);\n      vTaskDelay(800 \/ portTICK_PERIOD_MS);\n      Serial.println(&quot;Task2: End of log from Task 2&quot;);\n      xSemaphoreGive(serialMutex);\n    }\n    vTaskDelay(3000 \/ portTICK_PERIOD_MS);\n  }\n}\n\nvoid setup() {\n  Serial.begin(115200);\n  delay(1000);\n  Serial.println(&quot;Starting FreeRTOS&quot;);\n\n  serialMutex = xSemaphoreCreateMutex();\n  if (serialMutex == NULL) {\n    Serial.println(&quot;Failed to create mutex!&quot;);\n    while (1);\n  }\n\n  xTaskCreatePinnedToCore(\n    Task1,                  \/\/ Task function\n    &quot;Task1&quot;,                \/\/ Task name\n    3000,                   \/\/ Stack size\n    NULL,                   \/\/ Task parameters\n    1,                      \/\/ Priority\n    NULL,                   \/\/ Task handle\n    1                       \/\/ Core ID\n  );\n\n  xTaskCreatePinnedToCore(\n    Task2,                  \/\/ Task function\n    &quot;Task2&quot;,                \/\/ Task name\n    3000,                   \/\/ Stack size\n    NULL,                   \/\/ Task parameters\n    2,                      \/\/ Higher priority\n    NULL,                   \/\/ Task handle\n    1                       \/\/ Core ID\n  );\n}\n\nvoid loop() {\n  \n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/FreeRTOS\/Serial_Output_with_Mutex.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How Does the Code Work?<\/h3>\n\n\n\n<p>We start by defining the timeout for the mutex. This is the maximum amount of time a task will wait for the mutex until it returns <span class=\"rnthl rntliteral\">pdFALSE<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define MUTEX_TIMEOUT 5000  \/\/ 5s timeout<\/code><\/pre>\n\n\n\n<p>Create a handle for the mutex. It is the same type of handle used with a regular semaphore. We&#8217;re calling it <span class=\"rnthl rntliteral\">serialMutex<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>SemaphoreHandle_t serialMutex = NULL;<\/code><\/pre>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, we create the mutex using the <span class=\"rnthl rntliteral\">xSemaphoreCreateMutex()<\/span> function as we&#8217;ve seen in the introduction section.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>serialMutex = xSemaphoreCreateMutex();\nif (serialMutex == NULL) {\n  Serial.println(\"Failed to create mutex!\");\n  while (1);\n}<\/code><\/pre>\n\n\n\n<p>Still in the <span class=\"rnthl rntliteral\">setup()<\/span>, we create our tasks.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>xTaskCreatePinnedToCore(\n  Task1,                  \/\/ Task function\n  \"Task1\",                \/\/ Task name\n  3000,                   \/\/ Stack size\n  NULL,                   \/\/ Task parameters\n  1,                      \/\/ Priority\n  NULL,                   \/\/ Task handle\n  1                       \/\/ Core ID\n);\n\nxTaskCreatePinnedToCore(\n  Task2,                  \/\/ Task function\n  \"Task2\",                \/\/ Task name\n  3000,                   \/\/ Stack size\n  NULL,                   \/\/ Task parameters\n  2,                      \/\/ Higher priority\n  NULL,                   \/\/ Task handle\n  1                       \/\/ Core ID\n);<\/code><\/pre>\n\n\n\n<p>Now, let&#8217;s take a look at the tasks&#8217; callback functions defined before the <span class=\"rnthl rntliteral\">setup()<\/span>. The following line shows <span class=\"rnthl rntliteral\">Task1<\/span>, and here we can see how we use the mutex. It uses the <a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-semaphores-arduino\/\" title=\"\">same API as semaphores<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void Task1(void *parameter) {\n  for (;;) {\n    if (xSemaphoreTake(serialMutex, MUTEX_TIMEOUT)) {\n      Serial.println(\"Task1: Logging from Task 1\");\n      vTaskDelay(1000 \/ portTICK_PERIOD_MS);\n      Serial.println(\"Task1: End of log from Task 1\");\n      xSemaphoreGive(serialMutex);\n    }\n    vTaskDelay(5000 \/ portTICK_PERIOD_MS);\n  }\n}<\/code><\/pre>\n\n\n\n<p>First, we check if we can get the mutex with <span class=\"rnthl rntliteral\">xSemaphoreTake()<\/span>. It will until a maximum time of <span class=\"rnthl rntliteral\">MUTEX_TIMEOUT<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (xSemaphoreTake(serialMutex, MUTEX_TIMEOUT)) {<\/code><\/pre>\n\n\n\n<p>If we can, we print the lines to the Serial Monitor, which means we enter the critical task (the shared resource).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.println(\"Task1: Logging from Task 1\");\nvTaskDelay(1000 \/ portTICK_PERIOD_MS);\nSerial.println(\"Task1: End of log from Task 1\");<\/code><\/pre>\n\n\n\n<p>Right after printing, since we already finished the critical section, which in this case is accessing the Serial Monitor, we can now release the mutex with <span class=\"rnthl rntliteral\">xSemaphoreGive(serialMutex)<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>xSemaphoreGive(serialMutex);<\/code><\/pre>\n\n\n\n<p>In case the <span class=\"rnthl rntliteral\">MUTEX_TIMEOUT<\/span> is exceeded while waiting for the mutex, it will proceed to the following line before checking for the mutex again.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>vTaskDelay(5000 \/ portTICK_PERIOD_MS);<\/code><\/pre>\n\n\n\n<p>The callback for <span class=\"rnthl rntliteral\">Task2<\/span> works similarly, but with different timings.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void Task2(void *parameter) {\n  for (;;) {\n    if (xSemaphoreTake(serialMutex, MUTEX_TIMEOUT)) {\n      Serial.println(\"Task2: Logging from Task 2\");\n      vTaskDelay(800 \/ portTICK_PERIOD_MS);\n      Serial.println(\"Task2: End of log from Task 2\");\n      xSemaphoreGive(serialMutex);\n    }\n    vTaskDelay(3000 \/ portTICK_PERIOD_MS);\n  }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demonstration<\/h3>\n\n\n\n<p>Upload the code to the ESP32. Then, open the Serial Monitor and press the ESP32 RST button so that it starts running the code.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"666\" height=\"416\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Serial-Output-Mutex.png?resize=666%2C416&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Shared Serial Output with Mutex\" class=\"wp-image-181299\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Serial-Output-Mutex.png?w=666&amp;quality=100&amp;strip=all&amp;ssl=1 666w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Serial-Output-Mutex.png?resize=300%2C187&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>Notice that this time, the second task only starts after the first one finishes printing its output. The mutex prevents the tasks from overlapping. Both tasks want to access the Serial Monitor, but only the task holding the mutex can write to it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In summary, using mutexes is a simple but powerful way to control access to shared resources in your ESP32 projects. Whether you&#8217;re printing to the Serial Monitor, updating a display, writing to a file, or sending data over Wi-Fi, updating a database, etc, mutexes help avoid conflicts between tasks in your code.<\/p>\n\n\n\n<p>For more information about FreeRTOS Mutexes, you can check the <a href=\"https:\/\/www.freertos.org\/Documentation\/02-Kernel\/02-Kernel-features\/02-Queues-mutexes-and-semaphores\/04-Mutexes\" target=\"_blank\" rel=\"noopener\" title=\"\">official documentation<\/a>.<\/p>\n\n\n\n<p>We hope you&#8217;ve found this tutorial useful. If you want to learn more about using FreeRTOS programming with the ESP32 on Arduino IDE, make sure you check our other tutorials in this series:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-arduino-tasks\/\">ESP32 with FreeRTOS (Arduino IDE)\u2014Getting Started Guide: Creating Tasks<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-queues-inter-task-arduino\/\">ESP32 with FreeRTOS Queues: Inter-Task Communication (Arduino IDE)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-semaphores-arduino\/\" title=\"\">ESP32 with FreeRTOS: Getting Started with Semaphores (Arduino IDE)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-software-timers-interrupts\/\">ESP32 with FreeRTOS: Software Timers\/ Timer Interrupts (Arduino IDE)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-dual-core-arduino-ide\/\" title=\"\">How to use ESP32 Dual Core with Arduino IDE (FreeRTOS)<\/a><\/li>\n<\/ul>\n\n\n\n<p>To learn more about the ESP32, make sure to check out our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE (eBook)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32\/\">All our ESP32 Projects and Guides<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, you&#8217;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 &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 FreeRTOS Mutex &#8211; Getting Started (Arduino IDE)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-mutex-arduino\/#more-181013\" aria-label=\"Read more about ESP32 FreeRTOS Mutex &#8211; Getting Started (Arduino IDE)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":181438,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[276,281,277,299,264],"tags":[],"class_list":["post-181013","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32","category-esp32-project","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/ESP32-FreeRTOS-Mutex.jpg?fit=1920%2C1080&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/181013","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=181013"}],"version-history":[{"count":22,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/181013\/revisions"}],"predecessor-version":[{"id":187397,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/181013\/revisions\/187397"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/181438"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=181013"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=181013"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=181013"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}