Understanding Queues in FreeRTOS

FreeRTOS Learning Part 9 – Introduction to Queues

Objective of this article: FreeRTOS Learning Part 9 – Introduction to Queues

Understand the concept of queues in operating systems as described in this article.

Experimental conditions of this article: Theoretical learning.

1. Methods of Data Transmission

1.1 How Tasks Transmit Data

Comparison of multiple methods:

Number of Data Mutual Exclusion Measures Blocking-Waking Usage Scenario
Global Variables 1 None None One reader, one writer
Circular Buffer Multiple None None One reader, one writer
Queue Multiple Yes Yes Multiple readers, multiple writers

As a beginner, one might feel that using message queues is cumbersome and that using a global array is simpler. However, this is not the case. In bare-metal programming, using a global array is indeed more convenient, but when using an RTOS, the situation changes. Compared to message queues, using global arrays has the following four issues:

1. Using message queues allows the RTOS kernel to effectively manage tasks, while global arrays cannot achieve this. Mechanisms such as task timeouts need to be implemented by the user.

2. Using global arrays requires preventing access conflicts in multitasking, whereas message queues handle this issue well, relieving users of concern.

3. Message queues effectively solve the problem of message passing between interrupt service routines and tasks.

4. The FIFO mechanism is more conducive to data processing.

1.2 The Essence of Queues

In a queue, the essence of reading and writing data is a circular buffer, with added mutual exclusion measures and blocking-waking mechanisms.

If this queue does not transmit data but only adjusts the “number of data”, it acts as a semaphore.

If the semaphore limits the “number of data” to a maximum of 1, it acts as a mutex.

Next, we will continue to explore the working principles, implementation methods of queues, and how to use queues for task synchronization and communication in FreeRTOS.

2. Working Principles and Implementation of Queues

A queue is a first-in, first-out (FIFO) data structure that allows data to be added at one end (rear) and removed from the other end (front). In FreeRTOS, queues are used not only for data transmission but also as task synchronization mechanisms. The actual data is passed through FreeRTOS queues, not data addresses.

2.1 Creating a Queue

In FreeRTOS, a queue is created by calling the xQueueCreate() function. This function requires two parameters: the maximum number of elements that the queue can store and the size of each element.

QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize );

Upon successful creation, the function returns a queue handle (QueueHandle_t), which can be used to access the queue. If creation fails, it returns NULL.

2.2 Sending Data to the Queue

Data can be sent to the queue using the xQueueSend(), xQueueSendToFront(), xQueueSendToBack(), and xQueueSendOverwrite() functions. These functions allow data to be sent in different scenarios, such as adding to the front or back of the queue, or overwriting existing data in the queue.

BaseType_t xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );

2.3 Receiving Data from the Queue

Data can be received from the queue using the xQueueReceive() function. When calling this function, if the queue is empty, the task can choose to block and wait until data is available.

BaseType_t xQueueReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait );

3. Using Queues for Inter-Task Communication

Queues are a powerful tool for implementing inter-task communication. They allow tasks to exchange information in a thread-safe manner without worrying about data corruption or race conditions.

3.1 Communication Example

Consider a producer-consumer scenario where the producer task creates data and the consumer task processes it. Here, the queue acts as a bridge between the producer and consumer.

  1. The producer task sends data to the queue.
  2. The consumer task waits for data in the queue and processes it upon receipt.

3.2 Synchronization Example

Queues can also be used for task synchronization. For example, one task may need to wait for another task to complete specific work before continuing. This can be achieved by sending and receiving specific synchronization messages (or signals).

Conclusion

Understanding and using queues is key to mastering inter-task communication and synchronization in FreeRTOS. Through this article, you should be able to grasp the basic concepts of queues, how to create and use them, and how to utilize queues for passing data and signals between tasks. In practice, flexibly using queues can not only solve complex synchronization issues but also enhance system stability and responsiveness.

Leave a Comment

×