FreeRTOS – LPC2148 Binary Semaphore

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 tutorials, we have seen How to create the task using FreeRTOS API. Today we will see the FreeRTOS Binary Semaphore Tutorial in LPC2148. Let’s start.

Suggestion to read

FreeRTOS Binary Semaphore Tutorial in 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 a 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 when two or more tasks accessing the 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 of 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.

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.

API Used

  1. xTaskCreate()
  2. vTaskStartScheduler()
  3. vTaskDelay()
  4. vSemaphoreCreateBinary()
  5. xSemaphoreTake()
  6. xSemaphoreTakeFromISR()
  7. xSemaphoreGive()
  8. xSemaphoreGiveFromISR()

The first three APIs we have seen already in our previous tutorials. And Semaphore in ISR APIs we will in next tutorials. So we will concentrate on Semaphore APIs.

vSemaphoreCreateBinary ()

NOTE: The vSemaphoreCreateBinary() macro remains in the source code to ensure backward compatibility, but it should not be used in new designs. Use the xSemaphoreCreateBinary() function instead.
A macro that creates a binary semaphore. A semaphore must be explicitly created before it
can be used.

void vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore );

Parameters:

  • xSemaphore : Variable of type SemaphoreHandle_t that will store the handle of the semaphore being created.

Return Value:

None.

If following a call to vSemaphoreCreateBinary(), xSemaphore is equal to NULL, then the semaphore cannot be created because there is insufficient heap memory available for FreeRTOS to allocate the semaphore data structures. In all other cases, xSemaphore will hold the handle of the created semaphore.

xSemaphoreTake ()

‘Takes’ (or obtains) a semaphore that has previously been created using a call to vSemaphoreCreateBinary().

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

BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,

                             TickType_t xTicksToWait );

Parameters:

  • xSemaphore : The semaphore being ‘taken’. A semaphore is referenced by a variable of type SemaphoreHandle_t and must be explicitly created before being used.
  • xTicksToWait : The maximum amount of time the task should remain in the Blocked state to wait for the semaphore to become available, if the semaphore is not available immediately. If xTicksToWait is zero, then xSemaphoreTake() will return immediately if the semaphore is not available.

Return Value:

  • pdPASS : Returned only if the call to xSemaphoreTake() was successful in obtaining the semaphore.
  • pdFAIL : Returned if the call to xSemaphoreTake() did not successfully obtain the semaphore

xSemaphoreGive ()

‘Gives’ (or releases) a semaphore that has previously been created using a call to vSemaphoreCreateBinary(), xSemaphoreCreateCounting() or xSemaphoreCreateMutex() – and has also been successfully ‘taken’.

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

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

Parameters:

  • xSemaphore: The Semaphore being ‘given’. A semaphore is referenced by a variable of type SemaphoreHandle_t and must be explicitly created before being used.

Return Value:

  • pdPASS: The semaphore give was successful.
  • pdFAIL: The semaphore give was not successful.

Code

Here I’m creating two tasks with the same priority. These two tasks will contentiously print data in the serial terminal. Here Common resource is UART. In the output section, I have shown differences between semaphore and without semaphore. Go through the Code. Here I’m adding only the main file. If you want to download the full project, please visit here (GitHub).

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

void task1(void *q);
void task2(void *a);
void initpll(void);

xSemaphoreHandle binarysem;

int main(void)
{
	initpll();
	initserial();
	vSemaphoreCreateBinary(binarysem);
	xTaskCreate(task1,"task1",128,NULL,1,NULL);
	xTaskCreate(task2,"task2",128,NULL,1,NULL);
	vTaskStartScheduler();
	while(1);
}
void task1(void *q)
{	
	while(1) {	
		xSemaphoreTake(binarysem,portMAX_DELAY);
		sendsserial("Task1 functioning");
		sendsserial("\r\n");
		xSemaphoreGive(binarysem);
		vTaskDelay(1);
	}
}

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

Output

Without Semaphore:

Here prints are improper.

With Semaphore:

After adding semaphore, now it’s coming properly.

[Download This Project]

In our next tutorial, we will see how to use Binary semaphore in ISR using 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.

0 Comments
Inline Feedbacks
View all comments
Table of Contents