Bird
Raised Fist0
FreeRTOSprogramming~10 mins

Event-driven architecture in FreeRTOS - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Event-driven architecture
Event Occurs
↓
Event Detected by ISR
↓
Send Event to Queue
↓
Task Waits on Queue
↓
Task Receives Event
↓
Task Processes Event
↓
Task Waits for Next Event
Events happen and are caught by an interrupt. The event is sent to a queue. A task waits for events and processes them one by one.
Execution Sample
FreeRTOS
void ISR_Handler() {
  EventType event;
  BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  xQueueSendFromISR(eventQueue, &event, &xHigherPriorityTaskWoken);
  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

void EventTask(void *pvParameters) {
  EventType event;
  while(1) {
    if(xQueueReceive(eventQueue, &event, portMAX_DELAY)) {
      processEvent(event);
    }
  }
}
An ISR sends events to a queue, and a task waits on the queue to process events as they arrive.
Execution Table
StepActionEvent Queue StateTask StateOutput
1ISR_Handler triggered by eventEvent added to queueWaiting on queueNo output yet
2EventTask unblocked by eventEvent removed from queueProcessing eventprocessEvent(event) called
3EventTask finishes processingQueue emptyWaiting on queueReady for next event
4No new eventsQueue emptyWaiting on queueIdle, waiting
💡 Execution waits indefinitely for new events; no exit unless system stops
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3Final
eventQueueempty1 eventemptyemptyempty
eventundefinedset by ISRreceived by taskprocessedready for next
xHigherPriorityTaskWokenpdFALSEpdTRUEN/AN/ApdFALSE
Key Moments - 3 Insights
Why does the task wait on the queue instead of polling?
The task uses xQueueReceive with portMAX_DELAY to block and wait efficiently, saving CPU instead of polling continuously. See execution_table step 4 where task waits idle.
What ensures the ISR does not block when sending to the queue?
ISR uses xQueueSendFromISR which is safe and non-blocking in interrupt context, as shown in execution_table step 1.
How does the system handle multiple events arriving quickly?
Events queue up in eventQueue. The task processes them one by one as it receives them from the queue, shown by eventQueue state changes in variable_tracker.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 2, what happens to the eventQueue?
AThe event is removed from the queue
BThe queue is cleared
CAn event is added to the queue
DThe queue is unchanged
💡 Hint
Check the 'Event Queue State' column at step 2 in execution_table
According to variable_tracker, what is the value of xHigherPriorityTaskWoken after step 1?
ApdFALSE
Bundefined
CpdTRUE
Devent
💡 Hint
Look at the 'xHigherPriorityTaskWoken' row after Step 1 in variable_tracker
If no new events occur, what is the task state at step 4 in execution_table?
AProcessing event
BWaiting on queue
CBlocked indefinitely
DTerminated
💡 Hint
See the 'Task State' column at step 4 in execution_table
Concept Snapshot
Event-driven architecture in FreeRTOS:
- ISR detects event and sends it to a queue
- Task waits (blocks) on queue for events
- Task processes events one by one
- Uses xQueueSendFromISR and xQueueReceive
- Efficient CPU use by blocking, not polling
Full Transcript
In FreeRTOS event-driven architecture, when an event happens, an interrupt service routine (ISR) catches it and sends the event to a queue using xQueueSendFromISR. A dedicated task waits on this queue using xQueueReceive with an indefinite timeout, so it blocks and saves CPU. When the task receives an event, it processes it and then waits again for the next event. This design avoids polling and allows responsive, efficient handling of asynchronous events.

Practice

(1/5)
1. What is the main benefit of using event-driven architecture in FreeRTOS?
easy
A. It makes the program run all tasks continuously without waiting.
B. It requires more CPU power to check all events constantly.
C. The program reacts only when an event occurs, saving CPU time.
D. It disables multitasking to focus on one task at a time.

Solution

  1. Step 1: Understand event-driven architecture basics

    Event-driven architecture means the program waits and reacts only when events happen, not running tasks all the time.
  2. Step 2: Connect to FreeRTOS event groups

    FreeRTOS event groups let tasks wait efficiently for events, saving CPU time by not running unnecessarily.
  3. Final Answer:

    The program reacts only when an event occurs, saving CPU time. -> Option C
  4. Quick Check:

    Event-driven = React on event, save CPU [OK]
Hint: Event-driven means react only on events, not always running [OK]
Common Mistakes:
  • Thinking event-driven runs all tasks continuously
  • Believing it uses more CPU by checking constantly
  • Confusing event-driven with disabling multitasking
2. Which of the following is the correct way to create an event group in FreeRTOS?
easy
A. EventGroup xEventGroup = xCreateEventGroup();
B. EventGroupHandle_t xEventGroup = xEventGroupCreate();
C. xEventGroup = EventGroupCreate();
D. EventGroupHandle_t xEventGroup = createEventGroup();

Solution

  1. Step 1: Recall FreeRTOS event group creation syntax

    The official FreeRTOS function to create an event group is xEventGroupCreate(), returning EventGroupHandle_t.
  2. Step 2: Match the correct syntax

    EventGroupHandle_t xEventGroup = xEventGroupCreate(); uses the correct function name and type: EventGroupHandle_t xEventGroup = xEventGroupCreate();
  3. Final Answer:

    EventGroupHandle_t xEventGroup = xEventGroupCreate(); -> Option B
  4. Quick Check:

    Correct function and type = EventGroupHandle_t xEventGroup = xEventGroupCreate(); [OK]
Hint: FreeRTOS event groups use xEventGroupCreate() function [OK]
Common Mistakes:
  • Using wrong function names like createEventGroup()
  • Missing the correct handle type EventGroupHandle_t
  • Incorrect capitalization or function syntax
3. Given the code snippet:
<pre>EventGroupHandle_t xEventGroup = xEventGroupCreate(); // Task A waits for bit 0 and bit 1 EventBits_t uxBits = xEventGroupWaitBits(xEventGroup, (1 << 0) | (1 << 1), pdTRUE, pdTRUE, portMAX_DELAY); // Task B sets bit 0 xEventGroupSetBits(xEventGroup, (1 << 0)); // Task C sets bit 1 xEventGroupSetBits(xEventGroup, (1 << 1)); // What is the value of uxBits after Task A unblocks?
medium
A. 0x03 (both bits 0 and 1 set)
B. 0x01 (only bit 0 set)
C. 0x02 (only bit 1 set)
D. 0x00 (no bits set)

Solution

  1. Step 1: Understand xEventGroupWaitBits parameters

    Task A waits for bits 0 and 1 together (bitmask 0x03), clears bits on exit (pdTRUE), waits for all bits (pdTRUE), and waits indefinitely.
  2. Step 2: Analyze bit setting by Task B and Task C

    Task B sets bit 0 (0x01), Task C sets bit 1 (0x02). When both bits are set, Task A unblocks and uxBits contains both bits set (0x03).
  3. Final Answer:

    0x03 (both bits 0 and 1 set) -> Option A
  4. Quick Check:

    Wait for bits 0 & 1 set = 0x03 [OK]
Hint: WaitBits returns all requested bits set when unblocked [OK]
Common Mistakes:
  • Assuming only one bit is set when unblocked
  • Ignoring that wait is for all bits (pdTRUE)
  • Confusing bit masks with decimal values
4. Identify the error in this FreeRTOS event group usage:
EventGroupHandle_t xEventGroup;
xEventGroupSetBits(xEventGroup, (1 << 0));
medium
A. xEventGroupSetBits requires a pointer, not a handle.
B. Bit mask (1 << 0) is invalid.
C. Event groups cannot set bits directly.
D. xEventGroup is not created before use.

Solution

  1. Step 1: Check event group initialization

    xEventGroup is declared but never created with xEventGroupCreate(), so it is uninitialized (likely NULL).
  2. Step 2: Understand consequences of uninitialized handle

    Calling xEventGroupSetBits with an uninitialized handle causes undefined behavior or crash.
  3. Final Answer:

    xEventGroup is not created before use. -> Option D
  4. Quick Check:

    Create event group before use [OK]
Hint: Always create event group before setting bits [OK]
Common Mistakes:
  • Forgetting to call xEventGroupCreate()
  • Thinking bit mask is invalid
  • Misunderstanding handle vs pointer usage
5. You want a FreeRTOS task to wait for either bit 2 or bit 3 to be set in an event group, but not both. Which call correctly implements this behavior?
hard
A. xEventGroupWaitBits(xEventGroup, (1 << 2) | (1 << 3), pdTRUE, pdFALSE, portMAX_DELAY);
B. xEventGroupWaitBits(xEventGroup, (1 << 2) | (1 << 3), pdTRUE, pdTRUE, portMAX_DELAY);
C. xEventGroupWaitBits(xEventGroup, (1 << 2) & (1 << 3), pdTRUE, pdFALSE, portMAX_DELAY);
D. xEventGroupWaitBits(xEventGroup, (1 << 2) | (1 << 3), pdFALSE, pdTRUE, portMAX_DELAY);

Solution

  1. Step 1: Understand the parameters for xEventGroupWaitBits

    The third parameter clears bits on exit (pdTRUE), the fourth parameter controls if waiting for all bits (pdTRUE) or any bit (pdFALSE).
  2. Step 2: Match requirement to wait for either bit 2 or bit 3, but not both

    Waiting for any bit means pdFALSE for the fourth parameter. Using bitmask (1 << 2) | (1 << 3) waits for either bit 2 or bit 3.
  3. Final Answer:

    xEventGroupWaitBits(xEventGroup, (1 << 2) | (1 << 3), pdTRUE, pdFALSE, portMAX_DELAY); -> Option A
  4. Quick Check:

    Wait for any bit = pdFALSE, bitmask ORed = xEventGroupWaitBits(xEventGroup, (1 << 2) | (1 << 3), pdTRUE, pdFALSE, portMAX_DELAY); [OK]
Hint: Use pdFALSE to wait for any bit, not all bits [OK]
Common Mistakes:
  • Using pdTRUE to wait for all bits instead of any
  • Using bitwise AND instead of OR for bitmask
  • Not clearing bits on exit when needed
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