This tutorial covers the basic use of Mutual Exclusion Semaphores (Mutex). These are particular semaphores used to 'protect' unique resources used by several tasks. You'll see what this means next.
Just try this simple application:
/*
* main.c
*
* Created on: 24/02/2018
* Author: Laurent
*/
#include "main.h"
// Static functions
static void SystemClock_Config (void);
// FreeRTOS tasks
void vTask1 (void *pvParameters);
void vTask2 (void *pvParameters);
// Main program
int main()
{
// Configure System Clock
SystemClock_Config();
// Initialize LED pin
BSP_LED_Init();
// Initialize the user Push-Button
BSP_PB_Init();
// Initialize Debug Console
BSP_Console_Init();
// Start Trace Recording
vTraceEnable(TRC_START);
// Create Tasks
xTaskCreate(vTask1, "Task_1", 256, NULL, 1, NULL);
xTaskCreate(vTask2, "Task_2", 256, NULL, 2, NULL);
// Start the Scheduler
vTaskStartScheduler();
while(1)
{
// The program should never be here...
}
}
/*
* Task_1
*/
void vTask1 (void *pvParameters)
{
while(1)
{
my_printf("With great power comes great responsibility\r\n");
vTaskDelay(20);
}
}
/*
* Task_2
*/
void vTask2 (void *pvParameters)
{
while(1)
{
my_printf("#");
vTaskDelay(1);
}
}
Here, Task_1 and Task2 are just sending messages to the console. The problem is that the message printing process in Task_1 takes 4 to 5ms. In this delay, Task_2 is activated several times. As Task_2 has higher priority level, Task_1 is suspended while Task_2 executes.
As a result, we've got the Task_1 message cluttered with '#'... hum, that's not good.
...
// Kernel Objects
xSemaphoreHandle xConsoleMutex;
...
Second, we need to create the Mutex object, within main() function:
...
// Create a Mutex for accessing the console
xConsoleMutex = xSemaphoreCreateMutex();
// Give a nice name to the Mutex in the trace recorder
vTraceSetMutexName(xConsoleMutex, "Console Mutex");
...
Finally, the Mutex can be used to 'protect' the unique resources:
*
* Task_1
*/
void vTask1 (void *pvParameters)
{
while(1)
{
// Take Mutex
xSemaphoreTake(xConsoleMutex, portMAX_DELAY);
// Send message to console
my_printf("With great power comes great responsibility\r\n");
// Release Mutex
xSemaphoreGive(xConsoleMutex);
vTaskDelay(20);
}
}
/*
* Task_2
*/
void vTask2 (void *pvParameters)
{
while(1)
{
// Take Mutex
xSemaphoreTake(xConsoleMutex, portMAX_DELAY);
// Send message to console
my_printf("#");
// Release Mutex
xSemaphoreGive(xConsoleMutex);
vTaskDelay(1);
}
}
Unlike the binary semaphore, which is usually first given and then taken by two different tasks, the Mutex is first taken, and then released by the same task. It's a way for that task to say others "Hey, if you want to use that resource I'm using now, please don't interrupt me!".
Now watch the result of the above code: problem solved!
End of story!
![]() |
![]() ![]() |