📖 Scenario: You are working on a small embedded system using FreeRTOS. Your system has multiple tasks running concurrently, sharing resources like variables and peripherals. Sometimes, the system behaves unexpectedly, such as tasks not running or data getting corrupted.Understanding common bugs in RTOS and how to debug them is important to make your system reliable.
🎯 Goal: Build a simple FreeRTOS program with two tasks sharing a variable. You will add a configuration to protect the shared variable, implement the core logic to update it safely, and finally print the result to observe correct behavior.
📋 What You'll Learn
Create two FreeRTOS tasks named Task1 and Task2
Use a shared variable called sharedCounter initialized to 0
Add a mutex called xMutex to protect access to sharedCounter
In each task, increment sharedCounter 5 times safely using the mutex
Print the final value of sharedCounter after both tasks complete
💡 Why This Matters
🌍 Real World
Embedded systems often run multiple tasks that share resources. Bugs like race conditions or deadlocks can cause system crashes or wrong data. Using mutexes and debugging carefully helps build reliable devices.
💼 Career
Understanding RTOS bugs and debugging is essential for embedded software engineers working on IoT devices, automotive systems, medical devices, and industrial controllers.
Progress0 / 4 steps
1
DATA SETUP: Create shared variable and tasks
Create a global integer variable called sharedCounter and set it to 0. Then create two FreeRTOS tasks named Task1 and Task2 with empty task functions.
FreeRTOS
Hint
Define sharedCounter as a global variable. Create two task functions Task1 and Task2 with infinite loops. Use xTaskCreate to create the tasks in main.
2
CONFIGURATION: Add a mutex to protect shared variable
Create a mutex handle called xMutex using SemaphoreHandle_t. Initialize xMutex by calling xSemaphoreCreateMutex() in main before starting the scheduler.
FreeRTOS
Hint
Include semphr.h. Declare xMutex as SemaphoreHandle_t. Initialize it in main before starting the scheduler.
3
CORE LOGIC: Increment sharedCounter safely using mutex
In both Task1 and Task2, write a loop that increments sharedCounter 5 times. Use xSemaphoreTake(xMutex, portMAX_DELAY) before incrementing and xSemaphoreGive(xMutex) after incrementing to protect the shared variable. Add a small delay of 100 ms between increments.
FreeRTOS
Hint
Use a for loop to increment sharedCounter 5 times in each task. Protect the increment with xSemaphoreTake and xSemaphoreGive. Add a delay of 100 ms between increments.
4
OUTPUT: Print the final value of sharedCounter
After starting the scheduler in main, add a task called PrintTask that waits for both Task1 and Task2 to finish, then prints the final value of sharedCounter using printf. The expected final value is 10.
FreeRTOS
Hint
Create a PrintTask that waits long enough for the other tasks to finish, then prints sharedCounter using printf. The expected output is Final sharedCounter value: 10.
Practice
(1/5)
1. Which of the following is a common cause of deadlocks in FreeRTOS applications?
easy
A. Not enabling the FreeRTOS scheduler
B. Using too much heap memory for dynamic allocation
C. Incorrect task priority assignment causing starvation
D. Two tasks waiting indefinitely for each other's resource
Solution
Step 1: Understand deadlock concept in RTOS
Deadlock happens when two or more tasks wait forever for resources held by each other.
Step 2: Identify the scenario causing deadlock
Two tasks waiting indefinitely for each other's resource is the classic deadlock cause.
Final Answer:
Two tasks waiting indefinitely for each other's resource -> Option D
Quick Check:
Deadlock = Mutual waiting [OK]
Hint: Deadlock means tasks wait forever for each other's resource [OK]
Common Mistakes:
Confusing deadlock with priority inversion
Thinking heap size causes deadlock
Assuming scheduler not started causes deadlock
2. Which FreeRTOS API call correctly creates a task?
easy
A. xTaskCreate(TaskFunction, "Task1", 1000, NULL, 2, NULL);
B. vTaskCreate(TaskFunction, "Task1", 1000, NULL, 2, NULL);
C. xTaskCreate(TaskFunction, 1000, "Task1", NULL, 2, NULL);
D. xTaskCreate(TaskFunction, "Task1", NULL, 1000, 2, NULL);
Solution
Step 1: Recall FreeRTOS task creation syntax
The correct syntax is xTaskCreate(TaskFunction, "Name", stackSize, parameters, priority, taskHandle).
Step 2: Match options with correct parameter order
xTaskCreate(TaskFunction, "Task1", 1000, NULL, 2, NULL); matches the correct order and types.
Final Answer:
xTaskCreate(TaskFunction, "Task1", 1000, NULL, 2, NULL); -> Option A
What is the likely effect if xSemaphoreGive(xMutex); is accidentally omitted?
medium
A. The mutex will be automatically released after timeout
B. The task will run normally without issues
C. Other tasks waiting for the mutex will block indefinitely
D. The system will reset due to stack overflow
Solution
Step 1: Understand semaphore usage in FreeRTOS
Mutex must be given back after taking it to allow other tasks to access the resource.
Step 2: Analyze effect of missing xSemaphoreGive
If xSemaphoreGive is omitted, the mutex stays taken, blocking other tasks indefinitely.
Final Answer:
Other tasks waiting for the mutex will block indefinitely -> Option C
Quick Check:
Missing give = Blocked tasks [OK]
Hint: Always pair xSemaphoreTake with xSemaphoreGive [OK]
Common Mistakes:
Assuming mutex auto-releases
Confusing blocking with stack overflow
Ignoring semaphore usage rules
4. You observe that a FreeRTOS task sometimes stops running unexpectedly. Which debugging strategy is best to identify if a stack overflow caused this?
medium
A. Enable configCHECK_FOR_STACK_OVERFLOW and use configASSERT
B. Increase task priority to highest level
C. Disable all interrupts temporarily
D. Use vTaskDelay to slow down the task
Solution
Step 1: Identify debugging features for stack overflow
FreeRTOS provides configCHECK_FOR_STACK_OVERFLOW and configASSERT to detect stack overflow at runtime.
Step 2: Choose the best debugging method
Enabling these features helps catch stack overflow errors causing task failure.
Final Answer:
Enable configCHECK_FOR_STACK_OVERFLOW and use configASSERT -> Option A
Hint: Use FreeRTOS built-in stack overflow checks [OK]
Common Mistakes:
Thinking priority change fixes stack overflow
Disabling interrupts hides bugs
Using delay does not detect stack issues
5. In a FreeRTOS system, priority inversion occurs when a low priority task holds a resource needed by a high priority task. Which strategy helps to solve this problem?
hard
A. Increase the stack size of the low priority task
B. Use priority inheritance protocol on mutexes
C. Disable preemption in the scheduler
D. Use vTaskDelay in the high priority task
Solution
Step 1: Understand priority inversion problem
Priority inversion happens when a low priority task blocks a high priority task by holding a resource.
Step 2: Identify solution using FreeRTOS features
Priority inheritance protocol temporarily raises the low priority task's priority to prevent inversion.
Final Answer:
Use priority inheritance protocol on mutexes -> Option B