Thread synchronization is typically done using semaphores and message queues. Developers often overlook a very efficient method for synchronizing task which is the event flag. In this post, we will examine the event flag object in detail and learn when and where we should use event flags over more traditional RTOS objects such as semaphores.
An event flag group is essentially thirty-two individual bits that exist within a single memory location where every bit represents an event flag. Event flags are very efficient from a memory stand-point and even from a performance stand point. Setting and clearing an event is nothing more than an AND/OR logical operation performed on the event flag group. An event flag uses much less memory than a semaphore control block. The AND/OR operation is also very fast and efficient on the Renesas Synergy™ Microcontrollers.
Event flags can be a great way to notify and synchronize threads. For example, each flag within an event group can represent a different event that a thread can act on. One flag might represent a camera being started. Another flag might represent an over temperature condition in the system or even an overspeed detection in a BLDC motor application. Developers can have their threads suspend on an event flag which means the thread won’t run until an event occurs in the system. Developers can even specify a combination of events that are required before the thread will resume execution.
Creating an event flag group in the Renesas Synergy™ development environment is similar to creating a semaphore or a mutex. A developer opens the Synergy Configurator, navigates to the threads tab and then within the selected thread, adds an event flag group. An example event flag group that is added into the camera thread in the S7_DK_Web_Cam example can be seen below:
Once the event group has been created, a developer can select the group and navigate to the Synergy properties window to create the initial settings. The event flag group properties can be seen below:
Developers can provide the event group a string name and a symbol name that will be used in the code. Beyond these initial settings, a developer interacts with the events flags through the RTOS API. When a developer creates an event flag group, it is up to the developer to decide which bits will represent an event. The event representation is done at the code level by the developer. A best practice would be to create an enum that specifies all the event flag names and the bit they represent so that they can be OR’d and passed into the flags_to_set parameter and still be human readable.
There are several API’s that a developer can use to interact with the event flags group. These are detailed in the ThreadX user manual which can be downloaded from the Synergy Gallery. The primary API’s that we will discuss are the following:
UINT tx_event_flags_set(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG flags_to_set,UINT set_option)
UINT tx_event_flags_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG requested_flags, UINT get_option, ULONG *actual_flags_ptr, ULONG wait_option)
The tx_event_flags_set API can be used to clear flags by passing TX_AND into the set_option. If a flag should be set, indicating that an event has occurred, the TX_OR option can be used. For example, if a developer wanted to set bit 4 in g_camera_flags, which they have assigned to mean CAMERA_START, the following would be used:
status = tx_event_flags_set(g_camera_flags, CAMERA_START, TX_OR);
Developers will typically use the tx_event_flags_set API call to set when an event occurs.
The tx_event_flags_get API can be used to retrieve any or all the event flags in a specified group. A developer can specify the flags they want set in order to continue execution by using TX_AND to tell the get call that all events must have occurred or TX_OR which tells the call that any event will work. When the specified events do occur, they can also be immediately cleared by using TX_AND_CLEAR and TX_OR_CLEAR. A developer also needs to realize that when using tx_event_flags_get, they must supply their own ULONG variable to store the flags that they requested. Let’s look at a quick example.
If a developer has specified that bit 4 is the camera start event, CAMERA_START and a thread should continue executing when the event occurs, they would write a line of code that looks like the following:
tx_event_flags_get(g_camera_flags, CAMERA_START, TX_AND_CLEAR, &actual_events, TX_WAIT_FOREVER);
The thread will suspend and stop executing until bit 4 is set in g_camera_flags. Once this occurs, the bit state will be stored in the variable actual_events. Using TX_AND_CLEAR means that bit 4 must be set and that by getting the flag it will be cleared.
Event flags can be a great way for developers who are concerned with their memory footprint and their performance to optimize their RTOS object usage while still effectively synchronizing their threads. Semaphores tend to be overused in applications where a simple event flag group could have been used instead.
In the next post, we will examine how to pass data around an application from one thread to the next using ThreadX message queues. Until next time,
Live long and profit!
Hot Tip of the Week
Check out the new Renesas Synergy™ Promotion Kit, the PK-S5D9. This kit is an extremely low-cost way to access the entire Synergy Platform, enabling full development using the vast majority of all Synergy Software Package (SSP) functions. The kit supports high speed connectivity over Ethernet, USB-HS host and USB-FS device, CAN, plus wireless connectivity to mobile Internet devices via BLE 4.0. Color graphics, audio, and capacitive touch user interface features support complex HMI applications. Arduino™ and Pmod™ expansion ports allow for further customization. Additional kit details and ordering links to distribution are available here.