📖 Scenario: You are building a simple embedded system using FreeRTOS. The system has a button connected to an interrupt. When the button is pressed, the interrupt service routine (ISR) should notify a task to perform some action. To safely communicate between the ISR and the task, you will use a semaphore.
🎯 Goal: Create a FreeRTOS program where an ISR signals a task using a semaphore. The task waits for the semaphore and prints a message when the button is pressed.
📋 What You'll Learn
Create a binary semaphore variable called xButtonSemaphore.
Create a task called ButtonTask that waits for the semaphore.
Create an ISR function called ButtonISR_Handler that gives the semaphore from the ISR.
Use xSemaphoreGiveFromISR in the ISR and xSemaphoreTake in the task.
Print "Button pressed!" inside the task when the semaphore is received.
💡 Why This Matters
🌍 Real World
In embedded systems, buttons or sensors often trigger interrupts. Using semaphores to signal tasks from ISRs is a safe and common way to handle these events without blocking or unsafe operations inside the ISR.
💼 Career
Understanding ISR-to-task signaling with semaphores is essential for embedded software engineers working with real-time operating systems like FreeRTOS. It ensures responsive and safe handling of hardware events.
Progress0 / 4 steps
1
Create the semaphore variable
Create a binary semaphore variable called xButtonSemaphore using SemaphoreHandle_t and initialize it to NULL.
FreeRTOS
Hint
Use SemaphoreHandle_t to declare the semaphore variable and set it to NULL initially.
2
Create the semaphore in main
In the main function, create the binary semaphore by assigning xButtonSemaphore to the result of xSemaphoreCreateBinary().
FreeRTOS
Hint
Call xSemaphoreCreateBinary() and assign it to xButtonSemaphore inside main.
3
Write the ISR to give the semaphore
Write the ISR function called ButtonISR_Handler that calls xSemaphoreGiveFromISR(xButtonSemaphore, &xHigherPriorityTaskWoken) and then calls portYIELD_FROM_ISR(xHigherPriorityTaskWoken). Declare BaseType_t xHigherPriorityTaskWoken = pdFALSE; inside the ISR.
FreeRTOS
Hint
Inside the ISR, declare xHigherPriorityTaskWoken as pdFALSE, call xSemaphoreGiveFromISR with the semaphore and address of xHigherPriorityTaskWoken, then call portYIELD_FROM_ISR with xHigherPriorityTaskWoken.
4
Create the task to take the semaphore and print
Create a task function called ButtonTask that runs an infinite loop. Inside the loop, use xSemaphoreTake(xButtonSemaphore, portMAX_DELAY) to wait for the semaphore. When the semaphore is taken, print "Button pressed!" using printf. In main, create the task with xTaskCreate(ButtonTask, "ButtonTask", 1000, NULL, 1, NULL); and start the scheduler with vTaskStartScheduler();.
FreeRTOS
Hint
Inside ButtonTask, wait indefinitely for the semaphore using xSemaphoreTake. When received, print the message. In main, create the task and start the scheduler.
Practice
(1/5)
1. What is the main purpose of using a semaphore in FreeRTOS for ISR-to-task signaling?
easy
A. To disable interrupts during task execution
B. To create a new task inside an ISR
C. To safely notify a task from an interrupt service routine (ISR)
D. To allocate memory dynamically in an ISR
Solution
Step 1: Understand semaphore role in FreeRTOS
Semaphores are synchronization tools used to signal between tasks or between ISRs and tasks.
Step 2: Identify ISR-to-task signaling purpose
In FreeRTOS, semaphores let an ISR notify a task safely without blocking or complex synchronization.
Final Answer:
To safely notify a task from an interrupt service routine (ISR) -> Option C
Quick Check:
Semaphore signals task from ISR = A [OK]
Hint: Semaphores signal tasks from ISRs safely [OK]
Common Mistakes:
Thinking semaphores create tasks
Confusing semaphores with disabling interrupts
Using semaphores for memory allocation
2. Which FreeRTOS function is used inside an ISR to give a semaphore to a task?
easy
A. xSemaphoreGiveFromISR()
B. xSemaphoreTakeFromISR()
C. xSemaphoreCreateFromISR()
D. xSemaphoreGive()
Solution
Step 1: Recall ISR-safe semaphore functions
FreeRTOS provides special functions for ISR context to avoid blocking and ensure safety.
Step 2: Identify the correct ISR semaphore give function
The function to give a semaphore from an ISR is xSemaphoreGiveFromISR().
Final Answer:
xSemaphoreGiveFromISR() -> Option A
Quick Check:
Give semaphore from ISR = xSemaphoreGiveFromISR() [OK]
Hint: ISR uses xSemaphoreGiveFromISR() to signal tasks [OK]
Common Mistakes:
Using xSemaphoreGive() inside ISR (not safe)
Confusing take and give functions
Assuming xSemaphoreCreateFromISR() exists
3. Given the code snippet below, what will be the output printed by the task?
xSemaphoreGive() is not safe to call inside an ISR because it may block or cause race conditions.
Step 2: Identify correct ISR function
Use xSemaphoreGiveFromISR() inside ISRs to safely give semaphores.
Final Answer:
xSemaphoreGive() cannot be called from an ISR -> Option A
Quick Check:
Use xSemaphoreGiveFromISR() in ISR, not xSemaphoreGive() [OK]
Hint: Use xSemaphoreGiveFromISR() inside ISR, not xSemaphoreGive() [OK]
Common Mistakes:
Calling xSemaphoreGive() inside ISR
Ignoring ISR context restrictions
Assuming semaphore must be taken before giving
5. You want a task to respond immediately when a hardware interrupt occurs. Which sequence correctly uses a semaphore for ISR-to-task signaling in FreeRTOS?
hard
A. Create counting semaphore; task calls xSemaphoreGive(); ISR calls xSemaphoreTakeFromISR()
B. Create binary semaphore; ISR calls xSemaphoreGiveFromISR(); task calls xSemaphoreTake() with portMAX_DELAY
C. Create mutex; ISR calls xSemaphoreGive(); task calls xSemaphoreTake() with zero timeout
D. Create binary semaphore; task calls xSemaphoreGiveFromISR(); ISR calls xSemaphoreTake()
Solution
Step 1: Identify correct semaphore type and usage
Binary semaphore is suitable for signaling events from ISR to task.
Step 2: Confirm correct function calls and order
ISR must call xSemaphoreGiveFromISR() to signal; task waits with xSemaphoreTake() blocking indefinitely (portMAX_DELAY) until signaled.
Final Answer:
Create binary semaphore; ISR calls xSemaphoreGiveFromISR(); task calls xSemaphoreTake() with portMAX_DELAY -> Option B
Quick Check:
Binary semaphore + ISR give + task take = A [OK]
Hint: ISR gives semaphore, task takes with infinite wait [OK]
Common Mistakes:
Using mutex instead of semaphore
Calling give in task and take in ISR
Using zero timeout causing missed signals
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.