1. Concept of Event Groups
An event group is a communication mechanism between tasks, primarily used for synchronizing operations in a multi-task environment. It achieves collaborative work between tasks by setting and clearing event flags without passing data. An event group allows a task to wait for one or more events to occur, and then wakes the task to perform the corresponding action based on preset conditions (e.g., all events occur or any one event occurs).
2. Characteristics of Event Groups
-
No Data Transfer: Event groups are used solely for task synchronization and do not involve data transfer.
-
Many-to-Many Synchronization: Event groups allow multiple tasks to synchronize multiple events. A task can wait for multiple events to occur simultaneously, and multiple tasks can wait for a specific event to occur.
-
Independent Synchronization and Associated Synchronization:
-
Independent Synchronization (Logical OR): A task is interested in multiple events, and it will be awakened when any one of the events occurs.
-
Associated Synchronization (Logical AND): A task is interested in multiple events, and it will only be awakened when all events occur, regardless of the order in which they occur.
3. Implementation of Event Groups
In FreeRTOS, an event group is represented by a variable of type EventGroupHandle_t
. The state of the events is stored in a variable of type EventBits_t
, which is located within the structure of the event group.
-
Event Bits: The event state of each event group is saved by a variable
uxEventBits
. The number of bits in this variable depends on the definition of the macroconfigUSE_16_BIT_TICKS
: -
If
configUSE_16_BIT_TICKS
is defined as 1, thenuxEventBits
is 16 bits, of which 8 bits can be used for the event flag group. -
If
configUSE_16_BIT_TICKS
is defined as 0, thenuxEventBits
is 32 bits, of which 24 bits can be used for the event flag group (this is usually the case in STM32).
Each bit represents an event, and tasks can check these bits through logical operations (such as logical AND &
or logical OR |
) and associate them with one or more events to form an event group.
4. API Functions of Event Groups
1. Create Event Group
EventGroupHandle_t xEventGroupCreate(void);
-
This function creates a new event group and returns the handle of the event group.
2. Set Events
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet); // Use this function to set bits in an event group from an interrupt BaseType_t xEventGroupSetBitsFromISR(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken);
-
This function is used to set one or more event bits in the specified event group.
-
xEventGroup
: Event group handle. -
uxBitsToSet
: The event bits to set. -
pxHigherPriorityTaskWoken
: Must be initialized topdFALSE
before use.
3. Wait for Events
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait);
-
This function is used to wait for one or more events to occur.
-
uxBitsToWaitFor
: The event bits of interest to the task. -
xClearOnExit
: IfpdTRUE
, the event bits are cleared upon exit. -
xWaitForAllBits
: IfpdTRUE
, the task waits for all interested events to occur; ifpdFALSE
, the task waits for any one event to occur. -
xTicksToWait
: The maximum time (in ticks) the task will wait.
4. Clear Events
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear);
-
This function is used to clear one or more event bits in the specified event group.
5. Delete Event Group
void vEventGroupDelete(EventGroupHandle_t xEventGroup);
-
This function deletes an event group and releases the associated resources.
5. Use Cases for Event Groups
-
Synchronizing Multiple Tasks: Multiple tasks can wait for different events within the same event group and perform corresponding task operations upon event occurrence.
-
Complex Condition Synchronization: Event groups allow tasks to wait for combinations of multiple events to occur, for example, a task may need to start data processing only after receiving signals from multiple sensors.
6. Example Code for Event Groups
#define BIT_0 (0x01 << 0)#define BIT_1 (0x01 << 1) // Create Event Group EventGroupHandle_t xEventGroup = NULL; void vTask1(void *pvParameters) { // Set event bits xEventGroupSetBits(xEventGroup, BIT_0); while (1) { vTaskDelay(20); }} void vTask2(void *pvParameters) { EventBits_t r_event; while (1) { // Wait for events r_event = xEventGroupWaitBits(xEventGroup, BIT_0 | BIT_1, pdTRUE, pdFALSE, portMAX_DELAY); if ((r_event & (BIT_0 | BIT_1)) == (BIT_0 | BIT_1)) { // Task code } else { } }} void main(void) { // Create tasks xEventGroup = xEventGroupCreate(); xTaskCreate(vTask1, "Task1", 100, NULL, 1, NULL); xTaskCreate(vTask2, "Task2", 100, NULL, 1, NULL); // Start scheduler vTaskStartScheduler();}
7. Conclusion
Event groups are a powerful and flexible synchronization tool in FreeRTOS, providing an efficient mechanism for task synchronization in a multi-task environment. They allow for complex synchronization conditions and collaborative handling of multiple tasks and events. In practical applications, effectively utilizing event groups can simplify synchronization operations between tasks and enhance system responsiveness.