Event Groups
Event groups are a synchronization mechanism provided by FreeRTOS for implementing event flag communication between tasks or between tasks and interrupts. Essentially, it is a variable, usually 32 bits, with each bit representing an independent event. Tasks can achieve synchronization control over multiple events by waiting for certain bits to be set. Event groups are commonly used in scenarios such as task collaboration and peripheral synchronization, with the advantages of high efficiency and simple implementation.
Note
The total number of bits in the event group depends on the configuration item
configUSE_16_BIT_TICKS
:When
configUSE_16_BIT_TICKS
is 1, the event group is 16 bits.When
configUSE_16_BIT_TICKS
is 0, the event group is 32 bits.
The top 8 bits are reserved by the system and cannot be used for user event flags, so the available bits are 8 or 24 bits.
This document only covers some commonly used APIs in queue management. For more information, please refer to the FreeRTOS official documentation.
When calling event group related APIs in ESP-IDF, you need to include the following header file in the file:
#include "freertos/event_groups.h"
Event Group Creation API
xEventGroupCreate()
is used to create an event group. It returns the handle of the event group when successful, which can be used for subsequent setting, clearing, or waiting for event bits. This function is usually called during system initialization, and returns NULL
if creation fails.
API Prototype
EventGroupHandle_t xEventGroupCreate( void );
Return Value |
Description |
---|---|
Event Group Handle |
Event group creation successful. |
|
Event group creation failed, not enough FreeRTOS heap to create the event group. |
Example 1: Creating an Event Group
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
// Define handle to receive return value
EventGroupHandle_t xHandle = NULL;
void app_main(void)
{
// Create event group
xHandle = xEventGroupCreate();
if (xHandle != NULL) {
printf("Create SUCCESS\n");
}
else {
printf("Create FALSE\n");
}
}
The execution result of the above code is as follows:
Create SUCCESS
This example demonstrates how to use xEventGroupCreate()
to create an event group: define a handle to receive the return value after creating the event group, and judge whether the creation is successful based on the return value.
Event Group Deletion API
vEventGroupDelete()
is used to delete an event group and free up its memory resources. After calling this function, the event group handle will become invalid and cannot be used for event operations.
Note
This API is typically called when the event group is no longer in use to prevent memory leaks.
API Prototype
void vEventGroupDelete( EventGroupHandle_t xEventGroup );
Input Parameter |
Parameter Function |
Parameter Description |
---|---|---|
|
Handle of the event group to be deleted |
For example, a valid handle returned by |
After deleting the event group, the value of the event group handle itself will not automatically become NULL
or other special values, it still maintains the original numerical value. But this handle is invalid and cannot be used for any event group operations, otherwise it will cause undefined behavior.
Therefore, after calling vEventGroupDelete()
, it is recommended to manually set the handle to NULL
to prevent misuse.
Set Event Flag Bit API
xEventGroupSetBits()
is used to set one or more flag bits in the event group, indicating that the corresponding event has occurred. After successful setting, all tasks waiting for these event bits will be awakened according to the waiting conditions.
API Prototype
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet );
Input Parameter |
Parameter Function |
Parameter Description |
---|---|---|
|
Handle of the event group to be set |
For example, a valid handle returned by |
|
Specifies the event bits to be set |
Indicates which bits will be set to 1, multiple event bits can be combined by bitwise OR |
Return Value |
Description |
---|---|
Returns the status of all event bits in the event group after setting, not just the event bits set this time. |
Type is |
Example 2: Set Event Flag Bit
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
// Define flag bit
#define BIT0 (1<<0)
#define BIT2 (1<<2)
// Define handle, used to receive return value
EventGroupHandle_t xHandle = NULL;
EventBits_t uxBits; // Used to receive flag bit return value
void app_main(void)
{
int cnt = 0;
// Create semaphore
xHandle = xEventGroupCreate();
if (xHandle != NULL) {
printf("Create SUCCESS\n");
}
else {
printf("Create FALSE\n");
}
while (1) {
if (cnt == 0) {
printf("Set BIT0\n");
uxBits = xEventGroupSetBits(xHandle, BIT0);
}
else {
printf("Set BIT0 and BIT2\n");
uxBits = xEventGroupSetBits(xHandle, BIT0|BIT2);
}
if ((uxBits & BIT0) != 0)
{
printf("BIT0 set SUCCESS\n");
xEventGroupClearBits(xHandle, BIT0);
}
else {
printf("BIT0 set FALSE\n");
}
if ((uxBits & BIT2) != 0)
{
printf("BIT2 set SUCCESS\n");
xEventGroupClearBits(xHandle, BIT2);
}
else {
printf("BIT2 set FALSE\n");
}
cnt++;
vTaskDelay(10);
}
}
The execution result of the above code is as follows:
Create SUCCESS
Set BIT0
BIT0 set SUCCESS
BIT2 set FALSE
Set BIT0 and BIT2
BIT0 set SUCCESS
BIT2 set SUCCESS
This example demonstrates how to use xEventGroupSetBits()
to set event flag bits and determine which bits have been successfully set through the return value. It also combines xEventGroupClearBits()
to manually clear the set event bits.
The program sets BIT0
in a loop, and sets BIT0
and BIT2
at the same time, showing how to set multiple event bits individually or in combination, and determine whether the setting is successful bit by bit according to the return value.
This example demonstrates the complete process of setting, judging, and clearing event bits, which helps to understand the basic usage of event groups and bit operation mechanism.
Note
Tasks can determine which bits are set by performing bitwise AND
&
operation on the return value and the expected bits.When using bitwise AND
&
to determine the bit status, you cannot use== 1
for judgment, because the position of the event bit may not be at the lowest bit, you should use!= 0
to determine whether it is set.Repeatedly setting the same event bit will not change its status, nor will it trigger additional events.
The return value
uxBits
represents all bits set in the event group after callingxEventGroupSetBits()
, including the content set this time and previously. If the event bits are not cleared in time, these bits will remain set in subsequent judgments, which may lead to logical misjudgment.
Waiting for Event Flag Bits API
xEventGroupWaitBits()
is used to block the current task and wait for the specified event bits to be set. It can be configured to wait for all bits or any one bit, and supports options for timeout and whether to automatically clear event bits. It is commonly used for task synchronization or waiting for external events to complete.
API Prototype
EventBits_t xEventGroupWaitBits(const EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
Input Parameter |
Parameter Function |
Parameter Description |
---|---|---|
|
Handle of the event group to wait for |
For example, a valid handle returned by |
|
Event bits to wait for |
The bits that the task hopes to wait for, which can be a combination of one or more bits. |
|
Whether to clear the event bits before exiting |
If set to |
|
Wait for all bits or any bit |
If set to |
|
Maximum waiting time |
When the event flag bit does not meet the requirements, the maximum time the caller blocks and waits, defined in tick cycles; returns immediately when set to 0. |
Note
You can use the bitwise OR operator
|
to combine multiple event bits, allowing the task to wait for any or all of multiple events to occur at the same time.When
xTicksToWait
is set toportMAX_DELAY
, it means that the task waits indefinitely until the event conditions are met.
Return Value |
Explanation |
---|---|
The entire bit status of the event group when the waiting conditions are met. |
The type is |
Note
The return value is the current status bitmap of the event group.
Even if the automatic clear bit
xClearOnExit
is set topdTRUE
, the return value still contains the complete event bit information before triggering.
Example 3: Waiting for Event Flag Bits
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
// Define flag bits
#define BIT0 (1<<0)
#define BIT2 (1<<2)
// Define handle for receiving return value
EventGroupHandle_t xHandle = NULL;
EventBits_t uxBits; // Used to receive the return value of the flag bit
static void vSetBitTask (void *pvParameters)
{
int cnt = 0;
while (1)
{
// Simulate a task
vTaskDelay(pdTICKS_TO_MS(10));
if (cnt == 0) {
// Set BIT0
printf("Set BIT0\n");
xEventGroupSetBits(xHandle, BIT0); // The return value of this API is not needed here, so no need to receive
}
else if (cnt == 1) {
// Set BIT0 and BIT2
printf("Set BIT0 and BIT2\n");
xEventGroupSetBits(xHandle, BIT0|BIT2);
}
else if (cnt == 3) {
// Set BIT2
printf("Set BIT2\n");
xEventGroupSetBits(xHandle, BIT2);
}
cnt++;
}
}
void app_main(void)
{
// Create semaphore
xHandle = xEventGroupCreate();
if (xHandle != NULL) {
printf("Create SUCCESS\n");
xTaskCreate(vSetBitTask, "Set Bits", 2048, NULL, 1, NULL);
}
else {
printf("Create FALSE\n");
}
// Set a wait bit
uxBits = xEventGroupWaitBits(xHandle, BIT0, pdTRUE, pdFALSE, portMAX_DELAY);
if ((uxBits & BIT0) != 0)
{
printf("BIT0 set SUCCESS\n");
}
else {
printf("BIT0 set FALSE\n");
}
if ((uxBits & BIT2) != 0)
{
printf("BIT2 set SUCCESS\n");
}
else {
printf("BIT2 set FALSE\n\n");
}
// Set two wait bits, wait until all specified bits are set
uxBits = xEventGroupWaitBits(xHandle, (BIT0 | BIT2), pdTRUE, pdTRUE, portMAX_DELAY);
if ((uxBits & ( BIT0 | BIT2)) != 0)
{
printf("BIT0 and BIT2 set SUCCESS\n\n");
}
else {
printf("BIT0 and BIT2 set FALSE\n");
}
// Set two wait bits, any bit is sufficient
uxBits = xEventGroupWaitBits(xHandle, (BIT0 | BIT2), pdTRUE, pdFALSE, portMAX_DELAY);
if ((uxBits & BIT0) != 0)
{
printf("BIT0 set SUCCESS\n");
}
else {
printf("BIT0 set FALSE\n");
}
if ((uxBits & BIT2) != 0)
{
printf("BIT2 set SUCCESS\n\n");
}
else {
printf("BIT2 set FALSE\n");
}
}
The above code execution result is as follows:
Create SUCCESS
Set BIT0
BIT0 set SUCCESS
BIT2 set FALSE
Set BIT0 and BIT2
BIT0 and BIT2 set SUCCESS
Set BIT2
BIT0 set FALSE
BIT2 set SUCCESS
This example demonstrates how to use xEventGroupWaitBits()
to wait for the setting of one or more event flags, and combines with xEventGroupSetBits()
to simulate the occurrence of events in real time, thereby helping to understand the basic principles of task synchronization.
The program creates an event group and starts the task vSetBitTask()
. This task sets the specified flags in the event group in sequence with a certain delay, simulating the triggering of different events.
The main task implements three typical waiting scenarios through xEventGroupWaitBits()
:
Wait for a single bit
BIT0
: The execution result shows that when the task is awakened,BIT0
is successfully set, andBIT2
is not set.Wait for
BIT0
andBIT2
: The execution result shows that when the task is awakened, bothBIT0
andBIT2
are successfully set.Wait for
BIT0
andBIT2
: The execution result shows that when the task is awakened,BIT0
is not set, andBIT2
is successfully set.
This example clearly demonstrates the waiting mechanism of the event group, including the combined use of event bits, configuration of waiting conditions, judgment of return values, and automatic clearing of key operations, which helps to understand the synchronization logic based on event flags between tasks.
Clear Event Flag Bit API
xEventGroupClearBits()
is used to manually clear one or more event bits in the event group, that is, to change the specified bits from 1 to 0. This function is suitable for tasks to actively clear event flags to control the logic of subsequent event judgments, often used to avoid misjudgment or repeated responses.
API Prototype
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear );
Input Parameter |
Parameter Function |
Parameter Description |
---|---|---|
|
Handle of the event group to be cleared |
For example, a valid handle returned by |
|
Specifies the event bits to be cleared |
Indicates which bits will be set to 0, multiple event bits can be combined by bitwise OR |
Return Value |
Explanation |
---|---|
The status of all bits in the event group before calling this API. |
Type is |
xEventGroupWaitBits()
and xEventGroupClearBits()
can both be used to clear event flag bits, but their uses and clearing methods are different.
xEventGroupWaitBits()
can automatically clear the event bits that meet the conditions after the task successfully waits for the event by setting the parameterxClearOnExit
, suitable for scenarios where clearing is done while waiting.
xEventGroupClearBits()
is used to actively manually clear specified event bits at any position without waiting, suitable for situations where precise control of event status is required.The former depends on task waiting, and the clearing range is limited to the waiting event bits, while the latter is more flexible, suitable for explicit calls in tasks or interrupts to maintain the status of event bits.
For examples of using this API, refer to Example 2, where the set event bits are manually cleared through xEventGroupClearBits()
, demonstrating the basic usage of event status management.
Get Event Flag Bit API
xEventGroupGetBits()
is used to get the current event bit status of a specified event group. It is only used for reading and does not modify the content of the event group. It is commonly used in tasks or interrupts to check the current status of the event group, so as to handle accordingly based on the set event bits.
API Prototype
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
Input Parameter |
Parameter Function |
Parameter Description |
---|---|---|
|
The handle of the event group to be cleared |
For example, a valid handle returned by |
Return Value |
Explanation |
---|---|
The status of all event bits in the event group at the time of the call. |
The type is |
Example 4: Get Event Flag Bit
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
// Define flag bit
#define BIT0 (1<<0)
#define BIT2 (1<<2)
// Define handle for receiving return value
EventGroupHandle_t xHandle = NULL;
EventBits_t uxSetBits;
EventBits_t uxGetBits;
void app_main(void)
{
// Create semaphore
xHandle = xEventGroupCreate();
if (xHandle != NULL) {
printf("Create SUCCESS\n");
printf("Set BIT0\n");
uxSetBits = xEventGroupSetBits(xHandle, BIT0);
}
else {
printf("Create FALSE\n");
}
uxGetBits = xEventGroupGetBits(xHandle);
if (uxSetBits == uxGetBits) {
printf("BIT0 Set SUCCESS\n");
}
}
The execution result of the above code is as follows:
Create SUCCESS
Set BIT0
BIT0 Set SUCCESS
This example demonstrates how to use xEventGroupGetBits()
to get the current flag bit status of the event group, and compare it with the return value set by xEventGroupSetBits()
, to verify whether the event bit is successfully set.
In theory, xEventGroupGetBits()
, xEventGroupSetBits()
, xEventGroupWaitBits()
and xEventGroupClearBits()
can all get the status of the event flag bits set in the event group, but their design purposes and usage scenarios are significantly different. As shown in the table below:
API |
Whether to Modify Event Group |
Main Purpose |
Usage Scenario |
---|---|---|---|
|
Unmodified |
Read-only query |
Status judgment, conditional query |
|
Set the specified bit to 1 |
Notify event occurrence |
Trigger event in task |
|
Optional whether to clear the flag bit |
Wait for event synchronization |
Task blocked waiting for an event |
|
Clear the specified bit to 0 |
Manually clear event bit |
Status reset, event cleared |
Therefore, when only the event bit status needs to be obtained without affecting the event group, xEventGroupGetBits()
should be used preferentially, and the return values of other APIs are mainly used to judge the status results after related operations.