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 How to use a simple Binary Semaphore. Today we will learn the FreeRTOS Binary Semaphore from ISR in LPC2148. Let’s start.
Suggestion to read
- RTOS Basics – Part 1
- RTOS Basics – PART 2
- FreeRTOS Porting for LPC2148
- LPC2148 UART Tutorial
- LPC2148 Binary Semaphore
FreeRTOS Binary Semaphore from ISR 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
xTaskCreate ()
vTaskStartScheduler ()
vTaskDelay ()
vSemaphoreCreateBinary ()
xSemaphoreTakeFromISR ()
xSemaphoreGiveFromISR()
The first three APIs we have seen already in our previous tutorials. So we will concentrate on Semaphore ISR 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.
xSemaphoreTakeFromISR ()
If you are going to take a semaphore from ISR please use the below function.
#include “FreeRTOS.h”
#include “queue.h”
BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore,
signed BaseType_t *pxHigherPriorityTaskWoken );
A version of xSemaphoreTake() that can be called from an ISR. Unlike xSemaphoreTake(),
xSemaphoreTakeFromISR() does not permit a block time to be specified.
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.
- pxHigherPriorityTaskWoken : It is possible (although unlikely, and dependent on the semaphore type) that a semaphore will have one or more tasks blocked on it waiting to give the semaphore. Calling xSemaphoreTakeFromISR() will make a task that was blocked waiting to give the semaphore leave the Blocked state. If calling the API function causes a task to leave the Blocked state, and the unblocked task has a priority equal to or higher than the currently executing task (the task that was interrupted), then, internally, the API function will set *pxHigherPriorityTaskWoken to pdTRUE. If xSemaphoreTakeFromISR() sets *pxHigherPriorityTaskWoken to pdTRUE, then a context switch should be performed before the interrupt is exited. This will ensure that the interrupt returns directly to the highest priority Ready state task.
Return Value:
- pdPASS: The semaphore was successfully taken (acquired).
- pdFAIL: The semaphore was not successfully taken because it was not available.
xSemaphoreGiveFromISR()
A version of xSemaphoreGive() that can be used in an ISR. Unlike xSemaphoreGive(), xSemaphoreGiveFromISR() does not permit a block time to be specified.
#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken );
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. - *pxHigherPriorityTaskWoken : It is possible that a single semaphore will have one or more tasks blocked on it waiting for the semaphore to become available. Calling xSemaphoreGiveFromISR() can make the semaphore available, and so cause such a task to leave the Blocked state. If calling xSemaphoreGiveFromISR() causes a task to leave the Blocked state, and the unblocked task has a priority higher than or equal to the currently executing task (the task that was interrupted), then, internally, xSemaphoreGiveFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE. If xSemaphoreGiveFromISR() sets this value to pdTRUE, then a context switch should be performed before the interrupt is exited. This will ensure that the interrupt returns directly to the highest priority Ready state task.
Return Value:
- pdTRUE : The call to xSemaphoreGiveFromISR() was successful.
- errQUEUE_FULL : If a semaphore is already available, it cannot be given, and xSemaphoreGiveFromISR() will return errQUEUE_FULL.
Code
Here I’ve created one task. Whenever UART receives data from the user, it gives a semaphore to the task. That task waits until it gets semaphore. If it gets semaphore from ISR then it will print in UART. You can download the full project here.
#include<stdlib.h> #include "FreeRTOS.h" #include "task.h" #include "semphr.h" void initserial(void); void sendserial(unsigned char c); void rx1(void)__irq; void sendsserial(unsigned char *s); void initpll(void); void recsemaphore(void *q); xSemaphoreHandle binarysemaphore; int main() { vSemaphoreCreateBinary(binarysemaphore); initserial(); xSemaphoreTake(binarysemaphore,portMAX_DELAY); xTaskCreate(recsemaphore,"intertask",128,NULL,1,NULL); vTaskStartScheduler(); while(1); } void initpll(void) { PLL0CON=0x01; PLL0CFG=0x24; PLL0FEED=0xAA; PLL0FEED=0x55; while(!(PLL0STAT&1<<10)); PLL0CON=0x03; PLL0FEED=0xAA; PLL0FEED=0x55; VPBDIV=0x01; } void recsemaphore(void *q) { while(1) { if(xSemaphoreTake(binarysemaphore,portMAX_DELAY)==pdTRUE) { sendsserial("Received Semaphore From ISR"); sendsserial("\r\n"); sendsserial("\r\n"); } } } void initserial() { VPBDIV=0x01; PINSEL0|=0x5; U0LCR=0x83; U0DLL=136; //u0dll=60Mhz/(16*9600) U0DLM=1; U0LCR=0x03; U0TER=(1<<7); U0IER=0x01; //enables uart receive identification interrupt VICIntSelect=0x0000; //selecting as irq VICIntEnable|=0x0040; //enable uart1 VICVectAddr2=(unsigned long int)rx1; //assigning address VICVectCntl2=0x26; //need to assign slot no of interrupt source which has been activated } void sendserial(unsigned char dat) { U0THR=dat; while((U0LSR&(1<<5))==0); } void sendsserial(unsigned char *sdat) { while(*sdat) { sendserial(*sdat++); } } void rx1(void)__irq { unsigned char r; static portBASE_TYPE interrupttask; interrupttask=pdFALSE; if(U0IIR&0x04) { r=U0RBR; sendsserial("Received Data : "); U0THR=r; while(!(U0LSR&0x20)); sendsserial("\r\n"); sendsserial("Going to give semaphore"); sendsserial("\r\n"); xSemaphoreGiveFromISR(binarysemaphore,&interrupttask); sendsserial("Semaphore has given"); sendsserial("\r\n"); } VICVectAddr = 0x00; }
Output – FreeRTOS Binary Semaphore from ISR in LPC2148
In our next tutorial, we will see how to use the counting semaphore in the FreeRTOS.
You can also read the below tutorials.
Embedded Software | Firmware | Linux Devic Deriver | RTOS
Hi, I’m SLR. I am a tech blogger and an Embedded Engineer. I am always eager to learn and explore tech-related concepts. And also, I wanted to share my knowledge with everyone in a more straightforward way with easy practical examples. I strongly believe that learning by doing is more powerful than just learning by reading. I love to do experiments. If you want to help or support me on my journey, consider sharing my articles, or Buy me a Coffee! Thank you for reading my blog! Happy learning!