Queue[Specific usage in FreeRTOS]
Table of contents
What is a cue?
Queue is a computer term, often used in FreeRTOS to transfer data between tasks. The etymology of the word is a sequence of items waiting for their turn.
A queue is a buffer (temporary data storage) with a First In First Out data structure.
A buffer with a Last In First Out data structure, which is the opposite of this, is called a stack.
Transfer data between tasks using queues
As an example of an application of data transfer between tasks using a queue, we will explain saving by writing parameters to EEPROM.
In an application in which TaskA, which performs processing A, and TaskB, which performs processing B, are executing in parallel, the data that exists in each task is written and stored in external memory EEPROM.
Data is transferred to TaskC, a task dedicated to EEPROM writing, and then written in queue order. EEPROM writing is a relatively time-consuming process among microcontroller processes. Therefore, if writing is performed in TaskA or TaskB, where normal processing is performed, the crucial process will be interrupted.
Therefore, it is more efficient to create TaskC as a task that only writes EEPROMs and perform processing according to the order of the queue.
Queue buffer creation:
To use a queue, first declare a variable xQueue for the handle of the queue. Please understand that a handle variable is a variable used in operations. This variable is used to pass data between tasks.
Next, create the queue buffer with xQueueCreate().
Execution example of xQueueCreate(): xQueue=xQueueCreate(10,(sizeof(int8_t));
The first argument of the function specifies the number of data to be stored in the queue, and the second argument specifies the number of bytes per data to be stored in the queue. In this example, the number of data to be stored is 10, and the data length is 1 byte because the data to be passed is a number up to 255. This allocates memory for the queue buffer and the queue is ready for use.
In this example, the queue buffer does not pass the data value itself that you want to store in the EEPROM, but the ID of the data value. Therefore, the data length of the queue is 1 (1 byte), but strings and other data can also be passed. In that case, specify the number of characters to be used (1 byte per character).
However, since creating a queue means allocating memory, the xQueue variable for the return value handle of xQueueCreate() will be NULL if allocation fails due to insufficient memory. When creating a queue, confirm that the queue has been allocated as in the example above before proceeding.
Send to queue:
Passing data to the queue (sending to the queue) is done within each task that performs the processing.
Use xQueueSendToBack() to send data to a queue. The first argument of the function is the xQueue variable for the queue handle, and the second argument is the pointer (address) of the data to be sent. The third argument of the function specifies the maximum waiting time of the queue. The unit of the specified time is Tick. If the macro portMAX_DELAY is specified, the waiting time is unlimited. Conversely, if 0 is specified, there is no waiting time.
Receive to queue:
Receiving data stored in a queue (receiving from a queue) is done in a task. The data is processed in the task that wants to process the data. In this example, TaskC, the task dedicated to writing EEPROM, does this.
Use xQueueReceive() to receive data from a queue. Prepare a variable to store the data from the queue. In this example, it is set to 1 byte queue_buffer. The first argument of the function is the xQueue variable for the queue handle, and the second argument is a pointer (address) to the queue_buffer data storage variable. The third argument of the function specifies the maximum waiting time of the queue.
The flow of data is the reverse of that for transmission, with data received from the queue via the queue handle variable xQueue, received in the data storage variable queue_buffer, and processed sequentially according to its data value.
This means that when TaskC's execution cycle comes around, it will execute EEPROM writes until the queue buffer is empty. This allows TaskA and TaskB to concentrate only on their own processing.
In the sample example, data generated by normal processing TaskA or TaskB is stored in a queue buffer and passed to TaskC, an EEPROM write-only task with a relatively long execution cycle and high priority (priority depends on the processing).