Note: This article is excerpted from Wei Dongshan's "FreeRTOS Complete Development Manual", if there is any infringement, please inform
The concept of synchronization and mutual exclusion:
-
Synchronization: A waits for B to do something
-
Mutual exclusion: a resource can only be accessed by one user at a time
-
Ways of RTOS synchronization and mutual exclusion: task notification, queue, event group, semaphore, mutex, etc.
The event group
4.1 Event Group Concept
An event group can simply be thought of as an integer:
- Each bit represents an event, and the meaning of the event is determined by the programmer
- Can wait for any one of a certain bit, certain bits, or wait for multiple bits
- The upper 8 bits of the integer are reserved for the kernel, and only other bits can be used to represent events
4.2 Comparison of event groups with queues and semaphores
- wake
- Queue, semaphore: When an event occurs, only one task will be awakened
- Event group: When an event occurs, it will wake up the tasks of all symbol conditions, simply put, it has the function of "broadcasting"
- clear event
- Queue, semaphore: It is a consuming resource, the data of the queue is read away and gone; the semaphore is reduced after it is acquired
- Event group: The awakened task has two options, you can leave the event unchanged, or you can clear the event
4.3 Event Group Functions
Before using an event group, it must be created first. Tasks A and B generate events, and tasks C and D wait for events.
4.3.1 Create an event group
/* Create an event group * Return value: return handle, non-NULL means success */ EventGroupHandle_t xEventGroupCreate( void ); /* Create an event group * Return value: return handle, non-NULL means success */ EventGroupHandle_t xEventGroupCreateStatic(StaticEventGroup_t *pxEventGroupBuffer);
4.3.2 Delete an event group
/* xEventGroup: Event group handle, which event group do you want to delete */ void vEventGroupDelete(EventGroupHandle_t xEventGroup)
4.3.3 Setting up event groups
/* set bit in event group * xEventGroup: which event group * uxBitsToSet: Which bits are set? * Return value: Returns the original event value (meaningless, because it may have been modified by other tasks) */ EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet); /* set bit in event group * xEventGroup: which event group * uxBitsToSet: Which bits are set? * pxHigherPriorityTaskWoken: Did it cause a higher priority task to enter the ready state? pdTRUE - yes, pdFALSE - no * Return value: pdPASS-success, pdFALSE-failure */ BaseType_t xEventGroupSetBitsFromISR(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t * pxHigherPriorityTaskWoken);
Note: The functions in the ISR, such as the queue function xQueueSendToBackFromISR and the semaphore function xSemaphoreGiveFromISR, will wake up a task, and only one task at most.
But when setting up an event group, it is possible to cause multiple tasks to wake up, which brings a lot of uncertainty. Therefore, the xEventGroupSetBitsFromISR function does not directly set the event group, but sends queue data to a FreeRTOS background task (daemontask), which sets the event group.
4.3.4 Waiting for events
/* wait for bit in event group * xEventGroup: which event group * uxBitsToWaitFor: Which bits are waiting? * xWaitForAllBits: pdTRUE: Waiting bits, all are 1;pdFALSE: Waiting bits, one of them can be 1 * xClearOnExit: Do you want to clear the event before the function exits? pdTRUE: clear the bit specified by uxBitsToWaitFor; pdFALSE: do not clear * xTicksToWait: If the expected event does not occur, how long to block; it can be set to portMAX_DELAY: it must wait until it is successful before returning * Return value: pdPASS-success, pdFALSE-failure */ EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait);
4.3.4 Synchronization point
Multiple tasks can be synchronized using the xEventGroupSync() function:
- You can set a certain bit, certain bits, to indicate what you have done
- You can wait for a certain bit, certain bits, indicating that you want to wait for other tasks
- xEventGroupSync() will not return successfully until the expected time has occurred
- After xEventGroupSync returns successfully, the event will be cleared
/* event group * xEventGroup: which event group * uxBitsToSet: Which bits are set? * uxBitsToWaitFor: Which bits are waiting? * xTicksToWait: If the expected event does not occur, how long to block; it can be set to portMAX_DELAY: it must wait until it is successful before returning * Return value: Returns the event value */ EventBits_t xEventGroupSync(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait);