FreeRTOS – Event Groups Explained

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
FreeRTOS - Event Groups Explained
FreeRTOS - Event Groups Explained
  • 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 &amp; (EVENT_1_BIT | EVENT_2_BIT)) != 0) &amp;&amp;  
       ((eventreceivedflags &amp; 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

FreeRTOS - Event Groups Explained

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

Leave a Comment