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

Return Value

Description

Event Group Handle

Event group creation successful.

NULL

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 );
Parameter Explanation

Input Parameter

Parameter Function

Parameter Description

xEventGroup

Handle of the event group to be deleted

For example, a valid handle returned by xEventGroupCreate().

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 );
Parameter Explanation

Input Parameter

Parameter Function

Parameter Description

xEventGroup

Handle of the event group to be set

For example, a valid handle returned by xEventGroupCreate().

uxBitsToSet

Specifies the event bits to be set

Indicates which bits will be set to 1, multiple event bits can be combined by bitwise OR | operation.

Return Value Description

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 EventBits_t, can be used to determine whether the setting is effective, or to view the overall status of the event group.

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 calling xEventGroupSetBits(), 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 );
Parameter Explanation

Input Parameter

Parameter Function

Parameter Description

xEventGroup

Handle of the event group to wait for

For example, a valid handle returned by xEventGroupCreate().

uxBitsToWaitFor

Event bits to wait for

The bits that the task hopes to wait for, which can be a combination of one or more bits.

xClearOnExit

Whether to clear the event bits before exiting

If set to pdTRUE, the event bits that meet the conditions are automatically cleared before the task unblocks; otherwise, the event bit status is retained.

xWaitForAllBits

Wait for all bits or any bit

If set to pdTRUE, wait for all specified bits to be set; if pdFALSE, any bit that meets the condition is sufficient.

xTicksToWait

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 to portMAX_DELAY, it means that the task waits indefinitely until the event conditions are met.

Return Value Explanation

Return Value

Explanation

The entire bit status of the event group when the waiting conditions are met.

The type is EventBits_t, and you can determine which waiting event bits have been set and whether the wake-up conditions are met by bitwise AND & operation.

Note

  • The return value is the current status bitmap of the event group.

  • Even if the automatic clear bit xClearOnExit is set to pdTRUE, 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, and BIT2 is not set.

  • Wait for BIT0 and BIT2: The execution result shows that when the task is awakened, both BIT0 and BIT2 are successfully set.

  • Wait for BIT0 and BIT2: The execution result shows that when the task is awakened, BIT0 is not set, and BIT2 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 );
Parameter Explanation

Input Parameter

Parameter Function

Parameter Description

xEventGroup

Handle of the event group to be cleared

For example, a valid handle returned by xEventGroupCreate().

uxBitsToClear

Specifies the event bits to be cleared

Indicates which bits will be set to 0, multiple event bits can be combined by bitwise OR | operation.

Return Value Explanation

Return Value

Explanation

The status of all bits in the event group before calling this API.

Type is EventBits_t, can be used to record the state of the event group before clearing, convenient for subsequent analysis or debugging.

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 parameter xClearOnExit, 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 );
Parameter Explanation

Input Parameter

Parameter Function

Parameter Description

xEventGroup

The handle of the event group to be cleared

For example, a valid handle returned by xEventGroupCreate().

Return Value Explanation

Return Value

Explanation

The status of all event bits in the event group at the time of the call.

The type is EventBits_t, which represents the overall status of all event bits in the event group, not a specific bit.

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:

Behavior Characteristics and Applicable Scenarios of Each API

API

Whether to Modify Event Group

Main Purpose

Usage Scenario

xEventGroupGetBits()

Unmodified

Read-only query

Status judgment, conditional query

xEventGroupSetBits()

Set the specified bit to 1

Notify event occurrence

Trigger event in task

xEventGroupWaitBits()

Optional whether to clear the flag bit

Wait for event synchronization

Task blocked waiting for an event

xEventGroupClearBits()

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.