This article introduces <span>FreeRTOS</span> another synchronization mechanism for multitasking – Event Groups (<span>Event Group</span>). Unlike semaphores, event groups can achieve one-to-many and many-to-many synchronization.
API Introduction
| API | Function |
|---|---|
| xEventGroupCreate( void ) | Dynamically creates an event group and returns the handle of the newly created event group. configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h, or remain undefined (default is 1). The event group is stored in a variable of type <span>EventBits_t</span>. If <span>configUSE_16_BIT_TICKS</span> is set to 1, the number of bits (or flags) implemented in the event group is 8; if <span>configUSE_16_BIT_TICKS</span> is set to 0, the number of bits (or flags) implemented in the event group is 24. The dependency on <span>configUSE_16_BIT_TICKS</span> depends on the data type used for thread-local storage in the task implementation. |
| xEventGroupCreateStatic(StaticEventGroup_t *pxEventGroupBuffer ) | Statically creates an event group and returns the handle of the newly created event group. pxEventGroupBuffer must point to a variable of type StaticEventGroup_t, which will be used to store the event group data structure. |
| EventBits_t xEventGroupWaitBits(const EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,const BaseType_t xClearOnExit,const BaseType_t xWaitForAllBits,TickType_t xTicksToWait ); | Reads bits from the event group, optionally entering a “blocking” state to wait for a single bit or a group of bits to be set. xEventGroup is the event group handle; uxBitsToWaitFor specifies the bitwise value of one or more bits to be flagged in the event group. Note that setting to 0 is not allowed; xClearOnExit is pdTRUE, the corresponding event flag in the event group is cleared after successfully waiting for the event flag; xWaitForAllBits is used to create a logical ‘AND’ (all bits must be set) or logical ‘OR’ test (one or more bits must be set); xTicksToWait is the maximum time to wait for the condition to occur. |
| xEventGroupSetBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet ) | Sets bits (flags) in the event group. |
| xEventGroupSetBitsFromISR(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,BaseType_t *pxHigherPriorityTaskWoken ) | Sets bits (flags) in the event group from an interrupt. pxHigherPriorityTaskWoken is used to indicate whether a task switch is needed after the function exits. |
| xEventGroupClearBits(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToClear ) | Clears bits (flags) in the event group. |
| xEventGroupClearBitsFromISR(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToClear ) | Clears bits (flags) in the event group from an interrupt. |
| xEventGroupGetBits( EventGroupHandle_t xEventGroup ) | Gets the current value of the event flags in the event group. |
| xxEventGroupGetBitsFromISR(EventGroupHandle_t xEventGroup ) | Gets the current value of the event flags in the event group from an interrupt. |
| xEventGroupSync( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,const EventBits_t uxBitsToWaitFor,TickType_t xTicksToWait ) | Used for task synchronization, where each task must wait for other tasks to reach a synchronization point before continuing execution. |
Program Implementation
Objective: Create 3 tasks using an event group, with the relationship being: (Event 1 OR Event 2) AND Event 3. Once the relationship is established, log information will be printed.
- Creating tasks and event groups with STM32CubeMX


- Program Implementation
Create tasks and event groups, as shown in the automatically generated code by STM32CubeMx.
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.priority = (osPriority_t) osPriorityNormal,
.stack_size = 128 * 4
};
/* Definitions for myTask01 */
osThreadId_t myTask01Handle;
const osThreadAttr_t myTask01_attributes = {
.name = "myTask01",
.priority = (osPriority_t) osPriorityLow,
.stack_size = 128 * 4
};
/* Definitions for myTask02 */
osThreadId_t myTask02Handle;
const osThreadAttr_t myTask02_attributes = {
.name = "myTask02",
.priority = (osPriority_t) osPriorityLow,
.stack_size = 128 * 4
};
/* Definitions for myTask03 */
osThreadId_t myTask03Handle;
const osThreadAttr_t myTask03_attributes = {
.name = "myTask03",
.priority = (osPriority_t) osPriorityLow,
.stack_size = 128 * 4
};
/* Definitions for myEvent01 */
osEventFlagsId_t myEvent01Handle;
const osEventFlagsAttr_t myEvent01_attributes = {
.name = "myEvent01"
};
Implement event group related operations.
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN defaultTask */
uint32_t eventflags = EVENT_1_BIT | EVENT_2_BIT | EVENT_3_BIT;
uint32_t eventreceivedflags;
/* Infinite loop */
for(;;)
{
// wait for event
eventreceivedflags = osEventFlagsWait(myEvent01Handle,eventflags,
osFlagsWaitAny | osFlagsNoClear, // not wait for all bits ready, check the flag manually.
osWaitForever
);
// Condition(Event1 Or Event2) And Evnet3
if(((eventreceivedflags & (EVENT_1_BIT | EVENT_2_BIT)) != 0) &&
((eventreceivedflags & EVENT_3_BIT) != 0)) {
osEventFlagsClear (myEvent01Handle, eventflags);
printf("all conditions are ready!!!!!!\r\n");
}
osDelay(200);
}
/* USER CODE END defaultTask */
}
/* USER CODE BEGIN Header_StartTask01 */
/**
* @brief Function implementing the myTask01 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask01 */
void StartTask01(void *argument)
{
/* USER CODE BEGIN myTask01 */
/* Infinite loop */
for(;;)
{
osEventFlagsSet (myEvent01Handle,EVENT_1_BIT);
printf("Task 1 is ready!!!!\r\n");
osDelay(500);
}
/* USER CODE END myTask01 */
}
/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the myTask02 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void *argument)
{
/* USER CODE BEGIN myTask02 */
/* Infinite loop */
for(;;)
{
osEventFlagsSet (myEvent01Handle,EVENT_2_BIT);
printf("Task 2 is ready!!!!\r\n");
osDelay(1000);
}
/* USER CODE END myTask02 */
}
/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the myTask03 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void *argument)
{
/* USER CODE BEGIN myTask03 */
/* Infinite loop */
for(;;)
{
osEventFlagsSet (myEvent01Handle,EVENT_3_BIT);
printf("Task 3 is ready!!!!\r\n");
osDelay(1500);
}
/* USER CODE END myTask03 */
}
/* Private application code --------------------------------------------------*/
Program Execution Results

Thus, the introduction to the event group of the <span>FreeRTOS</span> operating system (<span>Event Group</span>) is complete.