Embedded Software Programming

Follow+Star Public Account Number, don’t miss out on exciting content

Source | Awesome Engineer Community

Today, I will discuss a commonly used event group programming method in embedded software programming, along with source code.

Event Group

The embedded event group is a widely used synchronization mechanism in embedded systems, primarily used for synchronization and communication between multiple tasks.

An event group is a collection of event flags, where each flag represents whether an event has occurred. It allows tasks to wait for specific events to happen, and when an event occurs, the relevant tasks are awakened to perform the corresponding actions.

Features

  • Flexibility: Users can customize the meaning of each bit event as needed, such as bit0 indicating whether a button is pressed. It supports one-to-many and many-to-many synchronization modes, meaning one task can wait for multiple events, or multiple tasks can synchronize multiple events.
  • Efficiency: Using bit operations, it is highly efficient and occupies minimal resources.
  • Scalability: Although commonly used with 16-bit or 32-bit unsigned data types to store event flags, the high 8 bits may be used for control information, while the low 24 bits are used to store event flags, allowing for multiple event flags to be stored.

Working Principle

  • Waiting for Events: Tasks wait for one or more event flags to occur by calling the appropriate API function (e.g., xEventGroupWaitBits in FreeRTOS). Conditions can be set for waiting, such as waiting for all specified event flags to be 1, or waiting for any one of the event flags to be 1.
  • Triggering Events: When an event occurs, the corresponding event flag is set to 1 by calling the appropriate API function (e.g., xEventGroupSetBits in FreeRTOS), thereby triggering the tasks waiting for that event. This wakes up all tasks that meet the conditions, similar to a “broadcast” effect.
  • Executing Tasks: The awakened tasks perform the corresponding actions based on the state of the event flags and can choose whether to clear the event flags.

Application Scenarios

  • Multi-task Synchronization: In scenarios where multiple tasks need to work together, event groups can be used to synchronize these tasks without data transfer.
  • Interrupt Handling: Set event flags in interrupt service routines to notify the main task or other tasks to perform corresponding processing.
  • Status Monitoring: Used to monitor various system statuses, such as whether a device is ready or whether data has arrived.

Example:

In embedded systems, synchronizing the sending of USB data typically involves multi-threaded programming and using appropriate synchronization mechanisms to ensure data consistency and integrity. In this case, event flags and message queues can be used to coordinate a producer thread (generating USB data) and a consumer thread (sending USB data).

Design Approach:

  • Message Queue: Used to store data from the producer thread to the consumer thread. Each data item may be a pointer to a USB data packet buffer or a structure containing packet information.

  • Event Flags: Used to notify the consumer thread that new data is available for processing, or to notify the producer thread to pause production when the queue is empty.

  • Mutex: Protects access to the message queue and event flags to prevent race conditions.

Implementation Steps:

1. Define Message Queue and Event Flags

  • Use the API provided by the RTOS to create the message queue and event flags.
  • The message queue should be able to store pointers to USB data packets or related structures.

2. Producer Thread

The producer thread is responsible for generating USB data and placing it into the message queue.

void producer_thread(void *arg) {  while (1) {  // Generate USB data packet  usb_packet_t *packet = generate_usb_packet();  // Lock mutex  rtos_mutex_lock(&mutex);  // Place packet into queue  if (rtos_queue_send(&usb_queue, &packet, portMAX_DELAY) == pdPASS) {  // Notify consumer thread of new data  rtos_event_group_set_bits(&event_group, EVENT_BIT_DATA_READY);  }  // Unlock mutex  rtos_mutex_unlock(&mutex);  // Wait for a while or continue generating data based on other conditions  vTaskDelay(pdMS_TO_TICKS(100));  } } 

3. Consumer Thread

The consumer thread retrieves data from the message queue and sends USB data packets.

void consumer_thread(void *arg) {  usb_packet_t *packet;  while (1) {  // Wait for data ready event  EventBits_t uxBits = xEventGroupWaitBits(  &event_group,   EVENT_BIT_DATA_READY,   pdTRUE,   pdFALSE,   portMAX_DELAY  );  if (uxBits & EVENT_BIT_DATA_READY) {  // Lock mutex  rtos_mutex_lock(&mutex);  // Receive packet from queue  if (rtos_queue_receive(&usb_queue, &packet, portMAX_DELAY) == pdPASS) {  // Send USB data packet  send_usb_packet(packet);  // Free packet (if needed)  free_usb_packet(packet);  }  // Unlock mutex  rtos_mutex_unlock(&mutex);  }  } } 

4. Initialization and Startup

Create the message queue, event flags, and mutex, and start the producer and consumer threads.

void app_main(void) {  // Initialize message queue, event flags, and mutex  rtos_queue_create(&usb_queue, ...);  rtos_event_group_create(&event_group);  rtos_mutex_create(&mutex);  // Create and start producer and consumer threads  xTaskCreate(producer_thread, "Producer", STACK_SIZE, NULL, PRIORITY, NULL);  xTaskCreate(consumer_thread, "Consumer", STACK_SIZE, NULL, PRIORITY, NULL);  // Other initialization... } 

Precautions

  • When using event groups, it is important to avoid race conditions and ensure the correctness of synchronization and communication between tasks.
  • Reasonably arrange the number and usage of event flags to avoid resource waste and inefficiency.
  • When designing the system, fully consider the dependencies and synchronization needs between tasks to choose appropriate synchronization mechanisms.

———— END ————

Embedded Software Programming

● Column “Embedded Tools”

● Column “Embedded Development”

● Column “Keil Tutorials”

● Selected Tutorials from the Embedded Column

Follow the public accountReply “Add Group” to join the technical exchange group according to the rules, reply “1024” to see more content.

Click “Read Original” to see more shares.

Leave a Comment