FreeRTOS – LPC2148 Mutex Tutorial

This article is a continuation of the  Series on FreeRTOS and carries the discussion on FreeRTOS and its usage. The aim of this series is to provide easy and practical examples that anyone can understand. In our previous tutorial, we have seen the Counting Semaphore. Now we are going to see FreeRTOS Mutex Tutorial using LPC2148. let’s start.

Suggestion to read

FreeRTOS Mutex Tutorial using LPC2148

Introduction

Before we starting this tutorial we should know about the semaphore. If you go through the RTOS Basics two parts you can go ahead.For others I will give you the small introduction about semaphore.

Semaphore

A semaphore (sometimes called a semaphore token) is a kernel object that one or more threads of execution can acquire or release for the purposes of synchronization or mutual exclusion. This is useful for when two or more task accessing same resource. A binary semaphore used for synchronization does not need to be ‘given’ back after it has been successfully ‘taken’ (obtained).

A kernel can support many different types of semaphores, including

  • binary,
  • counting, and
  • mutual‐exclusion (mutex) semaphores.

Binary Semaphore

  • Similar to mutex
  • Can have a value 1  or  0
  • Whenever a task asks for a semaphore, the OS checks if the semaphore’s value is 1
  • If so, the call succeeds and the value is set to 0
  • Else, the task is blocked

Binary semaphores are treated as global resources,

  • They are shared among all tasks that need them.
  • Making the semaphore a global resource allows any task to release it, even if the task did not initially acquire it?

Counting Semaphores

  • Semaphores with an initial value greater than 1
  • can give multiple tasks simultaneous access to a shared resource, unlike a mutex
  • Priority inheritance, therefore, cannot be implemented

Mutexes

Are powerful tools for synchronizing access to shared resources. A mutual exclusion (mutex) semaphore is a special binary semaphore that supports

  • ownership,
  • recursive access,
  • task deletion safety, and
  • one or more protocols for avoiding problems inherent to mutual exclusion.

A task that obtains a mutex that is used for mutual exclusion must always give the mutex back – otherwise, no other task will ever be able to obtain the same mutex. But in semaphore, any task can take a semaphore and any task can give semaphore.

Problems that may arise with mutexes

  • Deadlock
  • priority Inversion

Notes

Binary semaphores and mutexes are very similar, but do have some subtle differences. Mutexes include a priority inheritance mechanism, binary semaphores do not. This makes binary semaphores the better choice for implementing synchronization (between tasks or between tasks and an interrupt), and mutexes the better choice for implementing simple mutual exclusion.

Mutex vs Semaphore

Consider the standard producer-consumer problem. Assume, we have a buffer of 4096 byte length. A producer thread collects the data and writes it to the buffer. A consumer thread processes the collected data from the buffer. Objective is, both the threads should not run at the same time.

Using Mutex

  • A mutex provides mutual exclusion, either producer or consumer can have the key (mutex) and proceed with their work. As long as the buffer is filled by the producer, the consumer needs to wait, and vice versa.
  • At any point of time, only one thread can work with theentire  The concept can be generalized using semaphore.

Using Semaphore

A semaphore is a generalized mutex. In lieu of a single buffer, we can split the 4 KB buffer into four 1 KB buffers (identical resources). A semaphore can be associated with these four buffers. The consumer and producer can work on different buffers at the same time.

Misconception

  • There is an ambiguity between binary semaphore and mutex. We might have come across that a mutex is a binary semaphore. But they are not! The purpose of mutex and semaphore are different. Maybe, due to similarity in their implementation a mutex would be referred as a binary semaphore.
  • Strictly speaking, a mutex is locking mechanism used to synchronize access to a resource. Only one task (can be a thread or process based on OS abstraction) can acquire the mutex. It means there is ownership associated with a mutex, and only the owner can release the lock (mutex).
  • Semaphore is a signaling mechanism (“I am done, you can carry on” kind of signal). For example, if you are listening to songs (assume it as one task) on your mobile and at the same time, your friend calls you, an interrupt is triggered upon which an interrupt service routine (ISR) signals the call processing task to wakeup.

APIs Used

  1. xSemaphoreCreateMutex()
  2. xSemaphoreGetMutexHolder()
  3. xSemaphoreGive ()
  4. xSemaphoreTake()

Here we have already know the last two APIs. Because we were already discussed in our previous tutorials.

xSemaphoreCreateMutex()

Creates a mutex type semaphore, and returns a handle by which the mutex can be referenced. Each mutex type semaphore requires a small amount of RAM that is used to hold the semaphore’s state. If a mutex is created using xSemaphoreCreateMutex() then the required RAM is automatically allocated from the FreeRTOS heap. If a mutex is created using xSemaphoreCreateMutexStatic() then the RAM is provided by the application writer, which requires an additional parameter, but allows the RAM to be statically allocated at compile time.

#include “FreeRTOS.h”
#include “semphr.h”

SemaphoreHandle_t xSemaphoreCreateMutex( void );

for Mutex you should add below line in the FreeRTOSConfig.h

#define configUSE_MUTEXES 1

Parameters:

None

Return:

  • NULL Returned if the semaphore cannot be created because there is insufficient
    heap memory available for FreeRTOS to allocate the semaphore data structures.
  • Any other value The semaphore was created successfully. The returned value is a handle
    by which the created semaphore can be referenced.

xSemaphoreGetMutexHolder()

Return the handle of the task that holds the mutex specified by the function parameter, if any

#include “FreeRTOS.h”
#include “semphr.h”

TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex );

Parameters:

  • xMutex : The handle of the mutex being queried.

Return:

NULL Either:

  • The semaphore specified by the xMutex parameter is not a mutex type semaphore, or
  • The semaphore is available, and not held by any task.

Any other value The handle of the task that holds the semaphore specified by the xMutex parameter.

Notes
xSemaphoreGetMutexHolder() can be used reliably to determine if the calling task is the mutex holder, but cannot be used reliably if the mutex is held by any task other than the calling task. This is because the mutex holder might change between the calling task calling the function, and the calling task testing the function’s return value.

configUSE_MUTEXES and INCLUDE_xSemaphoreGetMutexHolder must both be set to 1 in FreeRTOSConfig.h for xSemaphoreGetMutexHolder() to be available.

Code

This program contains two tasks. Initially, task 1 takes the mutex and prints the data. Then that task release the mutex. Then task2 takes the mutex and prints data. Finally, task2 releases the data. So here unlike semaphore, who acquire the mutex they only need to release. If you want to download full project, please visit Here.

#include <stdlib.h>
#include "FreeRTOS.h"
#include "task.h"
#include "uart0.h"
#include "semphr.h"

void initpll(void);
void task1(void *p);
void task2(void *p);

xSemaphoreHandle xMutex=NULL;

int main()
{	
  initpll();
	initserial();  

	xMutex=xSemaphoreCreateMutex();  //xMutex will be storing NULL when Mutex not created
	if(xMutex!=NULL) {
		xTaskCreate(task1,"task1",128,NULL,1,NULL);
		xTaskCreate(task2,"task2",128,NULL,1,NULL);
		vTaskStartScheduler();
	}
  while(1);
}

void task1(void *p)
{
	while(1) {
		xSemaphoreTake(xMutex,portMAX_DELAY );
		sendsserial("Task1 functioning");
		sendsserial("\r\n");
		xSemaphoreGive( xMutex );
		vTaskDelay(5);
  }
}

void task2(void *p)
{
	while(1)
	{
		xSemaphoreTake(xMutex,portMAX_DELAY );
		sendsserial("Task2 functioning");
		sendsserial("\r\n");
		xSemaphoreGive(xMutex);
		vTaskDelay(5);
  }
}
void initpll(void)
{
	PLL0CON=0x01;
	PLL0CFG=0x24;
	PLL0FEED=0xAA;
	PLL0FEED=0x55;
	while(!(PLL0STAT&1<<10));
	PLL0CON=0x03;
	PLL0FEED=0xAA;
	PLL0FEED=0x55;
	VPBDIV=0x01;
}

Output – FreeRTOS Mutex Tutorial using LPC2148

[Download This Project]

In our next tutorial, we will see how to use the queue in the FreeRTOS.

You can also read the below tutorials.

Linux Device Driver TutorialsC Programming Tutorials
FreeRTOS TutorialsNuttX RTOS Tutorials
RTX RTOS TutorialsInterrupts Basics
I2C Protocol – Part 1 (Basics)I2C Protocol – Part 2 (Advanced Topics)
STM32 TutorialsLPC2148 (ARM7) Tutorials
PIC16F877A Tutorials8051 Tutorials
Unit Testing in C TutorialsESP32-IDF Tutorials
Raspberry Pi TutorialsEmbedded Interview Topics
Reset Sequence in ARM Cortex-M4BLE Basics
VIC and NVIC in ARMSPI – Serial Peripheral Interface Protocol
STM32F7 Bootloader TutorialsRaspberry PI Pico Tutorials
STM32F103 Bootloader TutorialsRT-Thread RTOS Tutorials
Zephyr RTOS Tutorials - STM32Zephyr RTOS Tutorials - ESP32
AUTOSAR TutorialsUDS Protocol Tutorials
Product ReviewsSTM32 MikroC Bootloader Tutorial
VHDL Tutorials
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Table of Contents