Extra 5% OFF Use Code: OL05
Free Shipping over ₹999

Mutexes in FreeRTOS

Mutexes (mutual exclusions) are special types of semaphores used in FreeRTOS for managing access to shared resources between tasks. They ensure that only one task can access a shared resource at a time, helping to prevent data corruption and conflicts in a multitasking environment.

Key Features of Mutexes

  • Ownership: Unlike binary semaphores, mutexes have the concept of ownership. Only the task that “takes” the mutex can “give” it back, preventing other tasks from accessing the resource.
  • Priority Inheritance: FreeRTOS can temporarily raise the priority of a task holding a mutex if a higher-priority task is waiting for it. This helps prevent priority inversion.

Example: Using Mutexes in FreeRTOS

In this example, we will create two tasks: one that increments a shared counter (the producer) and another that decrements it (the consumer). We will use a mutex to manage access to the shared counter and prevent conflicts.

Step 1: Set Up the Environment

Ensure you have ESP-IDF installed and your environment set up:

. $HOME/esp/esp-idf/export.sh

Step 2: Create a New Project

Create a new folder for your project and initialize it.

Step 3: Write the Code

Here’s a simple FreeRTOS application using a mutex:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

#define TASK_COUNT 5

// Declare a mutex handle
SemaphoreHandle_t mutex;

// Shared resource (counter)
volatile int sharedCounter = 0;

// Task that increments the shared counter
void increment_task(void *pvParameter) {
    for (int i = 0; i < TASK_COUNT; i++) {
        // Wait for the mutex to become available
        if (xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE) {
            // Critical section: Increment the shared counter
            sharedCounter++;
            printf("Incremented Counter: %d\n", sharedCounter);
            // Release the mutex
            xSemaphoreGive(mutex);
        }
        // Simulate work
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}

// Task that decrements the shared counter
void decrement_task(void *pvParameter) {
    for (int i = 0; i < TASK_COUNT; i++) {
        // Wait for the mutex to become available
        if (xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE) {
            // Critical section: Decrement the shared counter
            sharedCounter--;
            printf("Decremented Counter: %d\n", sharedCounter);
            // Release the mutex
            xSemaphoreGive(mutex);
        }
        // Simulate work
        vTaskDelay(150 / portTICK_PERIOD_MS);
    }
}

// Main application entry point
void app_main(void) {
    // Create the mutex
    mutex = xSemaphoreCreateMutex();

    // Create the increment and decrement tasks
    xTaskCreate(increment_task, "Increment Task", 2048, NULL, 1, NULL);
    xTaskCreate(decrement_task, "Decrement Task", 2048, NULL, 1, NULL);
}

Explanation of the Code

  1. Mutex Declaration:
    • A mutex handle mutex is declared.
  2. Shared Resource:
    • A shared counter variable sharedCounter is defined as volatile to ensure proper access across multiple tasks.
  3. Increment Task (increment_task):
    • This task increments the sharedCounter.
    • It waits for the mutex to become available using xSemaphoreTake(). If successful, it enters the critical section, increments the counter, and prints the new value.
    • After finishing the critical section, it releases the mutex with xSemaphoreGive().
    • A delay simulates some work.
  4. Decrement Task (decrement_task):
    • This task decrements the sharedCounter.
    • It waits for the mutex, enters the critical section, decrements the counter, prints the value, and releases the mutex, similar to the increment task.
    • A delay simulates some work.
  5. Main Function (app_main):
    • The mutex is created using xSemaphoreCreateMutex().
    • The increment and decrement tasks are created using xTaskCreate().

Step 4: Build and Flash the Project

  1. Build the project:
idf.py build

2. Flash the project to the ESP32:

idf.py -p /dev/ttyUSB0 flash

Output Explanation

When you run the project, you will see output similar to this:

Incremented Counter: 1
Decremented Counter: 0
Incremented Counter: 1
Decremented Counter: 0
Incremented Counter: 2
Decremented Counter: 1
...

The output shows that the increment and decrement tasks are operating correctly, updating the sharedCounter safely using the mutex. The use of xSemaphoreTake() ensures that only one task can access the shared resource at a time, preventing race conditions.

Summary

In this example, we demonstrated how to use mutexes in FreeRTOS to prevent conflicts when multiple tasks access a shared resource. The mutex ensured that only one task could modify the sharedCounter at any given time, thus preventing potential data corruption. Understanding how to use mutexes is essential for developing robust and safe multitasking applications in embedded systems.

    Leave a Reply

    Your email address will not be published.

    Need Help?