FreeRTOS Queue

API

Introduction

The objective of this post is to give an introduction to FreeRTOS queues, using the ESP32 and the Arduino core.

Queues are very useful for inter-task communication, allowing to send messages from one task to another safely in terms of concurrency [1]. They are typically used as FIFOs (First In First Out) [1], meaning that new data is inserted at the back of the queue and consumed from the front.

Nonetheless, FreeRTOS has a very rich queue API, which offers a lot more functionality. You can check the queue API here.

One very important aspect to keep in mind is that the data that is inserted in the queue is copied rather that only a reference to it being stored [1]. This means that if we send an integer to the queue, its value will be actually copied and if we change the original value after that no problem should occur.

Nonetheless, we can still insert pointers to data as elements of our queue, which is useful specially if the messages to exchange are big. In this case, the pointer will be copied to the queue, not the message itself, and thus we need to guarantee that it is not changed. But this is a more advanced situation which we are not going to cover here.

Other important behavior to keep in mind is that the insertion in a full queue or the consumption of an empty queue can be made blocking calls for a specified amount of time [1] (this amount of time is a parameter of the API).

QueueHandle_t queue;
 
void setup() {
 
  Serial.begin(115200);
 
  queue = xQueueCreate( 10, sizeof( int ) );
 
  if(queue == NULL){
    Serial.println("Error creating the queue");
  }
 
}
 
void loop() {
 
  if(queue == NULL)return;
 
  for(int i = 0; i<10; i++){
    xQueueSend(queue, &i, portMAX_DELAY);
  }
 
  int element;
 
  for(int i = 0; i<10; i++){
    xQueueReceive(queue, &element, portMAX_DELAY);
    Serial.print(element);
    Serial.print("|");
  }
 
  Serial.println();
  delay(1000);
}

xQueueCreate
Return
If the queue is successfully create then a handle to the newly created queue is returned. If the queue cannot be created then 0 is returned.
Parameters
uxQueueLength: The maximum number of items that the queue can contain.
uxItemSize: The number of bytes each item in the queue will require. Items are queued by copy, not by reference, so this is the number of bytes that will be copied for each posted item. Each item on the queue must be the same size.


xQueueSendToFront,xQueueSendToBack,xQueueSend
Return
pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
Parameters
xQueue: The handle to the queue on which the item is to be posted.
pvItemToQueue: A pointer to the item that is to be placed on the queue. The size of the items the queue will hold was defined when the queue was created, so this many bytes will be copied from pvItemToQueue into the queue storage area.
xTicksToWait: The maximum amount of time the task should block waiting for space to become available on the queue, should it already be full. The call will return immediately if this is set to 0 and the queue is full. The time is defined in tick periods so the constant portTICK_PERIOD_MS should be used to convert to real time if this is required.

xQueueReceive
Return
pdTRUE if an item was successfully received from the queue, otherwise pdFALSE.
Parameters
xQueue: The handle to the queue from which the item is to be received.
pvBuffer: Pointer to the buffer into which the received item will be copied.
xTicksToWait: The maximum amount of time the task should block waiting for an item to receive should the queue be empty at the time of the call. xQueueReceive() will return immediately if xTicksToWait is zero and the queue is empty. The time is defined in tick periods so the constant portTICK_PERIOD_MS should be used to convert to real time if this is required.

xQueuePeek
similar to xQueueReceive without remove element from queue

xTaskHandle task;
xQueueHandle queue;
byte tpin=13;

void taskFunction(void* parameter){
  for(;;){
    int val1=0;
    int* val=&val1;
    xQueueReceive(queue,&val,100);//wait the queue for 100 ms if not queue recived it will print 0
    Serial.println(*((int*)val));
  }
  vTaskDelete(task);
}

void setup(){
  Serial.begin(9600);
  //pinMode(tpin,INPUT_PULLUP);
  if(xTaskCreate(taskFunction,"task1",2048,nullptr,tskIDLE_PRIORITY,&task))
    Serial.println("task created");
  queue=xQueueCreate(5,sizeof(void*));//queue contain 5 integer items
}

void loop(){
  delay(1000);
  int val1=touchRead(tpin);
  int* val=&val1;
  xQueueSend(queue,&val,portMAX_DELAY);// if queue is full it will wait for portMAX_DELAY to available space
}
Tagged :