In the previous FreeRTOS articles I have shown you how FreeRTOS threads work, and how to use a Queue to communicate data between threads. In this article I will introduce you to another important RTOS concept, the Semaphore. The Semaphore or in this case the FreeRTOS Binary Semaphore is a multi-threaded safe mechanism for signaling between threads. I use the word “signal” because the word “semaphore” is an old-time word for a system of flags that were used to communicate between boats. Here is a modern example of a flag semaphore, the Cypress Indycar winning finish line checkered flag earlier this year:
In RTOS, a binary semaphore is exactly the same thing as a checkered flag. It is one thread waving another thread to indicate some specific message. Specifically, what does the message flag mean? It means whatever you define it to mean. In this example, it will mean that a message can be printed on the screen.
In this article I will modify the queue example program from the previous article to add a semaphore that will:
- Print a message when a specific key on the keyboard is pressed
- Print a message when a mechanical button on the development kit is pressed
FreeRTOS Binary Semaphore Task
I will start by copying the “3-Queue” example and creating a new project called “4-Binary Semaphore”. At the top of the program I will add a global variable of type “SemaphoreHandle_t” to hold my semaphore. I use a global variable so that all of the threads will have access to the handle.
Before you can use the semaphore you must set it up. At the start of main I initialize the semaphore:
switchSemaphore = xSemaphoreCreateBinary();
Now, I will create a new thread that will just sit and wait for the Semaphore flag. On line 122, the xSemaphoreTake function will put that thread to sleep util one of the other threads has “given” the signal using the xSemaphoreGive function. When that occurs, I print out the message and then loop back around and wait again.
void semaphore_Task(void *arg)
UART_UartPutString("Taken Switch Semaphore\n");
Giving the FreeRTOS Binary Semaphore
Inside of the “UART_Task” on line 107, when the ‘s’ key is pressed, wave the FreeRTOS Binary Semaphore Flag… actually “give” the semaphore. When this happens the “semaphore_Task” wakes up and prints out the message.
With Semaphores there is an annoying level of inconsistency in the language. Sometimes (as in FreeRTOS) it is “give/take” in WICED it is “set/get”, but they mean the same thing.
Using a Semaphore: Interrupt Service Routine
It is a very good practice to minimize the amount of work done inside of an interrupt service routine. The FreeRTOS binary Semaphore is the perfect tool for achieving that objective. When an interrupt occurs, set the semaphore flag then let the RTOS take care of the rest. To show this example I add a digital input pin to the schematic and attach it to an interrupt.
The pin is configured to trigger the interrupt on a falling edge (the switch on the board is active low).
Now I create an ISR called “isr_1_Handler”. All it does is clear the pin interrupt and then give the semaphore. The only trick is that the FreeRTOS Binary Semaphore has a different give function for use inside of ISR. In general, the FreeRTOS API adds “FromISR” onto the API to indicate that it is safe to use inside of an ISR.
The last thing to add is at the start of main I install the interrupt handler.
Now when you press the mechanical switch on the devkit, you will get the message that the FreeRTOS Binary Semaphore has been set.
In the next article I will show you another type of semaphore, the counting semaphore.
FreeRTOS: A PSoC4 FreeRTOS Port
An introduction to making FreeRTOS work on PSoC 4
FreeRTOS PSoC Examples
Using multiple tasks in FreeRTOS
FreeRTOS Queue Example
Using a queue to communicate between tasks
PSoC 6 FreeRTOS - The First Example
Booting FreeRTOS on PSoC 6
FreeRTOS Binary Semaphore
An first example of a binary semaphore
FreeRTOS Binary Semaphore (Part 2)
Removing polling in the UART Task
FreeRTOS Counting Semaphore
An example using a counting semaphore
Reading I2C Sensors with a shared I2C Bus