Bird
Raised Fist0
FreeRTOSprogramming~10 mins

Binary semaphore creation and usage in FreeRTOS - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Binary semaphore creation and usage
Start
↓
Create Binary Semaphore
↓
Check Semaphore Created?
No→Error Handling
Yes↓
Task 1: Take Semaphore
↓
Critical Section
↓
Task 1: Give Semaphore
↓
Task 2: Take Semaphore
↓
Critical Section
↓
Task 2: Give Semaphore
↓
End
This flow shows creating a binary semaphore, tasks taking and giving it to control access to a shared resource.
Execution Sample
FreeRTOS
SemaphoreHandle_t xSemaphore;
xSemaphore = xSemaphoreCreateBinary();

if (xSemaphore != NULL) {
  xSemaphoreGive(xSemaphore); // Initialize semaphore
}

// Task 1
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
  // Critical section
  xSemaphoreGive(xSemaphore);
}
This code creates a binary semaphore, initializes it, and shows a task taking and giving the semaphore.
Execution Table
StepActionSemaphore StateResultNotes
1Call xSemaphoreCreateBinary()Semaphore created (empty)Semaphore handle returnedSemaphore created but initially empty
2Check if semaphore handle is NULLSemaphore handle validProceedSemaphore successfully created
3Call xSemaphoreGive() to initializeSemaphore given (full)Semaphore is now availableBinary semaphore is now available for take
4Task 1 calls xSemaphoreTake()Semaphore taken (empty)pdTRUETask 1 successfully takes semaphore
5Task 1 enters critical sectionSemaphore emptyN/ATask 1 has exclusive access
6Task 1 calls xSemaphoreGive()Semaphore given (full)N/ASemaphore released for others
7Task 2 calls xSemaphoreTake()Semaphore taken (empty)pdTRUETask 2 successfully takes semaphore
8Task 2 enters critical sectionSemaphore emptyN/ATask 2 has exclusive access
9Task 2 calls xSemaphoreGive()Semaphore given (full)N/ASemaphore released again
10No more tasks taking semaphoreSemaphore given (full)N/ASemaphore remains available
💡 Execution stops when no tasks are waiting to take the semaphore.
Variable Tracker
VariableStartAfter Step 3After Step 4After Step 6After Step 7After Step 9Final
xSemaphoreNULLGiven (full)Taken (empty)Given (full)Taken (empty)Given (full)Given (full)
Key Moments - 3 Insights
Why do we call xSemaphoreGive() right after creating the binary semaphore?
Because xSemaphoreCreateBinary() creates the semaphore in the empty state, calling xSemaphoreGive() makes it available for tasks to take, as shown in execution_table step 3.
What happens if a task calls xSemaphoreTake() when the semaphore is empty?
The task blocks (waits) until the semaphore is given by another task. In the table, tasks successfully take the semaphore only when it is given (full).
Can two tasks be in the critical section at the same time using a binary semaphore?
No, because the semaphore can only be taken by one task at a time, ensuring exclusive access as shown in steps 4-6 and 7-9.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the semaphore state after step 4 when Task 1 takes it?
ASemaphore given (full)
BSemaphore created (empty)
CSemaphore taken (empty)
DSemaphore handle NULL
💡 Hint
Check the 'Semaphore State' column at step 4 in the execution_table.
At which step does the semaphore become available for the first time after creation?
AStep 2
BStep 3
CStep 1
DStep 4
💡 Hint
Look for when xSemaphoreGive() is called to make the semaphore available.
If we skip calling xSemaphoreGive() after creation, what happens when Task 1 calls xSemaphoreTake()?
ATask 1 blocks waiting for semaphore
BTask 1 takes semaphore immediately
CSemaphore handle becomes NULL
DSemaphore is given automatically
💡 Hint
Refer to the key moment about why xSemaphoreGive() is needed after creation.
Concept Snapshot
Binary semaphore controls access to a resource.
Create with xSemaphoreCreateBinary().
Initially empty; call xSemaphoreGive() to make available.
Tasks call xSemaphoreTake() to enter critical section.
Only one task holds semaphore at a time.
Call xSemaphoreGive() to release it.
Full Transcript
This visual execution trace shows how to create and use a binary semaphore in FreeRTOS. First, the semaphore is created with xSemaphoreCreateBinary(), which returns a handle but starts empty. To make it available, xSemaphoreGive() is called. Tasks then use xSemaphoreTake() to wait for and take the semaphore before entering a critical section. After finishing, they call xSemaphoreGive() to release it for others. The semaphore ensures only one task accesses the shared resource at a time. The execution table tracks semaphore state changes step-by-step, and the variable tracker shows the semaphore handle state. Key moments clarify why initialization with xSemaphoreGive() is needed and how tasks block if the semaphore is empty. The quiz tests understanding of semaphore states and behavior during task synchronization.

Practice

(1/5)
1. What is the primary purpose of a binary semaphore in FreeRTOS?
easy
A. To store multiple values for task communication
B. To signal and control access to shared resources between tasks
C. To create multiple tasks automatically
D. To allocate memory dynamically

Solution

  1. Step 1: Understand the role of binary semaphores

    Binary semaphores are used to signal availability or control access to resources between tasks.
  2. Step 2: Compare options with this role

    Only To signal and control access to shared resources between tasks describes signaling and controlling access, which matches the purpose of binary semaphores.
  3. Final Answer:

    To signal and control access to shared resources between tasks -> Option B
  4. Quick Check:

    Binary semaphore = resource signaling [OK]
Hint: Binary semaphore controls resource access between tasks [OK]
Common Mistakes:
  • Confusing binary semaphore with counting semaphore
  • Thinking it stores multiple values
  • Assuming it creates tasks
2. Which of the following is the correct way to create a binary semaphore in FreeRTOS?
easy
A. xSemaphoreCreateBinary();
B. xSemaphoreCreateCounting(1, 0);
C. xSemaphoreCreateMutex();
D. xSemaphoreCreateBinary(1);

Solution

  1. Step 1: Recall the function to create a binary semaphore

    The correct function is xSemaphoreCreateBinary() with no parameters.
  2. Step 2: Check each option

    xSemaphoreCreateBinary(); matches the correct function. xSemaphoreCreateCounting(1, 0); creates a counting semaphore, C creates a mutex, and D is invalid syntax.
  3. Final Answer:

    xSemaphoreCreateBinary(); -> Option A
  4. Quick Check:

    Create binary semaphore = xSemaphoreCreateBinary() [OK]
Hint: Use xSemaphoreCreateBinary() with no arguments [OK]
Common Mistakes:
  • Using counting semaphore creation instead
  • Adding parameters to xSemaphoreCreateBinary()
  • Confusing mutex creation with binary semaphore
3. Consider the following FreeRTOS code snippet:
SemaphoreHandle_t xBinarySemaphore = xSemaphoreCreateBinary();

void Task1(void *pvParameters) {
    if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE) {
        // Critical section
    }
}

void Task2(void *pvParameters) {
    xSemaphoreGive(xBinarySemaphore);
}
What will happen when Task1 runs before Task2?
medium
A. Task1 will enter the critical section immediately
B. Task1 will skip the critical section
C. Task1 will cause a runtime error
D. Task1 will block indefinitely until Task2 gives the semaphore

Solution

  1. Step 1: Analyze xSemaphoreTake with portMAX_DELAY

    Task1 calls xSemaphoreTake with portMAX_DELAY, so it waits indefinitely for the semaphore.
  2. Step 2: Consider initial semaphore state and Task2 action

    The semaphore is created but not given initially, so Task1 blocks until Task2 calls xSemaphoreGive.
  3. Final Answer:

    Task1 will block indefinitely until Task2 gives the semaphore -> Option D
  4. Quick Check:

    xSemaphoreTake with portMAX_DELAY blocks until given [OK]
Hint: xSemaphoreTake with portMAX_DELAY waits until given [OK]
Common Mistakes:
  • Assuming semaphore is initially available
  • Thinking Task1 runs critical section immediately
  • Confusing blocking with error
4. Identify the error in this FreeRTOS binary semaphore usage:
SemaphoreHandle_t xBinarySemaphore = xSemaphoreCreateBinary();

void Task(void *pvParameters) {
    if (xSemaphoreTake(xBinarySemaphore, 0) == pdTRUE) {
        // Do work
        xSemaphoreGive(xBinarySemaphore);
    }
}
medium
A. xSemaphoreCreateBinary requires a parameter
B. xSemaphoreGive should be called before xSemaphoreTake
C. Semaphore is never given before take, so take always fails
D. xSemaphoreTake timeout cannot be zero

Solution

  1. Step 1: Check initial semaphore state after creation

    xSemaphoreCreateBinary creates a semaphore that is initially empty (not given).
  2. Step 2: Analyze xSemaphoreTake with zero timeout

    With zero timeout, xSemaphoreTake returns immediately. Since semaphore is empty, it returns pdFALSE, so the if block never runs.
  3. Final Answer:

    Semaphore is never given before take, so take always fails -> Option C
  4. Quick Check:

    Binary semaphore empty at creation, take with zero timeout fails [OK]
Hint: Binary semaphore must be given before take succeeds [OK]
Common Mistakes:
  • Assuming semaphore is initially given
  • Thinking zero timeout means wait forever
  • Confusing function parameters
5. You want to synchronize two tasks so that Task B only runs after Task A signals completion using a binary semaphore. Which sequence correctly implements this?
hard
A. Task A calls xSemaphoreGive() after work; Task B calls xSemaphoreTake() with portMAX_DELAY before work
B. Task B calls xSemaphoreGive() before work; Task A calls xSemaphoreTake() after work
C. Both tasks call xSemaphoreTake() simultaneously; semaphore is given once at start
D. Task A and Task B both call xSemaphoreGive() without taking

Solution

  1. Step 1: Understand synchronization with binary semaphore

    Task B must wait for Task A's signal, so Task B should take the semaphore and block until given.
  2. Step 2: Match sequence to this logic

    Task A gives the semaphore after finishing work; Task B takes it with portMAX_DELAY to wait indefinitely.
  3. Final Answer:

    Task A calls xSemaphoreGive() after work; Task B calls xSemaphoreTake() with portMAX_DELAY before work -> Option A
  4. Quick Check:

    Give after work, take before work = sync tasks [OK]
Hint: Give semaphore after work; take before work to sync tasks [OK]
Common Mistakes:
  • Reversing give and take roles
  • Both tasks giving without taking
  • Taking without giving semaphore
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard