Index
In FreeRTOS, a queue is a data structure that allows for communication between tasks or between tasks and interrupts. Queues provide a safe way to send and receive messages or data in a multi-threaded environment, ensuring that tasks can synchronize and communicate without stepping on each other’s toes.
Key Features of Queues
- Data Storage: Queues can store multiple items of data (e.g., integers, structures) until they are processed by a receiving task.
- Synchronization: Queues help synchronize tasks by ensuring that data is only accessed when available.
- Blocking and Non-blocking Operations: FreeRTOS provides both blocking and non-blocking APIs for sending and receiving items from queues.
- Task Communication: Queues are commonly used for inter-task communication, allowing tasks to send messages or share data.
Example: Using Queues in FreeRTOS
In this example, we’ll create two tasks: one that produces data (a producer) and another that consumes data (a consumer). The producer will send integer values to the queue, and the consumer will read and print those values.
Step 1: Set Up the Environment
Make sure you have ESP-IDF installed and your environment set up:
. $HOME/esp/esp-idf/export.sh
Step 2: Create a New Project
Create a new folder for your project and initialize it.
Step 3: Write the Code
Here’s a simple FreeRTOS application using a queue:
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#define QUEUE_SIZE 5 // Define the size of the queue
#define ITEM_SIZE sizeof(int) // Define the size of each item in the queue
// Create a queue handle
QueueHandle_t queue;
// Producer task
void producer_task(void *pvParameter) {
int item;
while (1) {
item = rand() % 100; // Generate a random integer (0-99)
if (xQueueSend(queue, &item, portMAX_DELAY) == pdPASS) {
printf("Produced: %d\n", item);
} else {
printf("Failed to send to queue.\n");
}
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay for 1 second
}
}
// Consumer task
void consumer_task(void *pvParameter) {
int item;
while (1) {
if (xQueueReceive(queue, &item, portMAX_DELAY) == pdPASS) {
printf("Consumed: %d\n", item);
} else {
printf("Failed to receive from queue.\n");
}
vTaskDelay(2000 / portTICK_PERIOD_MS); // Delay for 2 seconds
}
}
// Main application entry point
void app_main(void) {
// Create a queue capable of holding 5 integers
queue = xQueueCreate(QUEUE_SIZE, ITEM_SIZE);
// Create the producer and consumer tasks
xTaskCreate(producer_task, "Producer Task", 2048, NULL, 1, NULL);
xTaskCreate(consumer_task, "Consumer Task", 2048, NULL, 1, NULL);
}
Explanation of the Code
- Queue Definition:
- A queue handle
queue
is declared. - The queue size is defined as 5, meaning it can hold up to 5 items at a time.
- Each item in the queue is an integer.
- A queue handle
- Producer Task (
producer_task
):- This task generates a random integer (0-99) every second.
- It attempts to send the generated integer to the queue using
xQueueSend()
. - If the queue is full, it prints a message indicating failure; otherwise, it prints the produced item.
- The
portMAX_DELAY
parameter makes the function wait indefinitely until space is available in the queue.
- Consumer Task (
consumer_task
):- This task attempts to receive an integer from the queue every two seconds using
xQueueReceive()
. - If successful, it prints the consumed item; if it fails, it prints a failure message.
- The
portMAX_DELAY
parameter makes the function wait indefinitely until an item is available in the queue.
- This task attempts to receive an integer from the queue every two seconds using
- Main Function (
app_main
):- The queue is created using
xQueueCreate()
, specifying the size and item size. - The producer and consumer tasks are created using
xTaskCreate()
.
- The queue is created using
Step 4: Build and Flash the Project
- Build the project:
idf.py build
2. Flash the project to the ESP32:
idf.py -p /dev/ttyUSB0 flash
Output Explanation
When you run the project, you will see output similar to this:
Produced: 42
Consumed: 42
Produced: 27
Consumed: 27
Produced: 88
Consumed: 88
...
The producer will produce random numbers, and the consumer will consume them in the order they were sent. The producer adds items to the queue, and the consumer retrieves items from the queue, demonstrating inter-task communication using FreeRTOS queues.
Summary
In this example, we demonstrated how to create and use queues for communication between tasks in FreeRTOS. Queues are a powerful tool for synchronizing tasks and facilitating data transfer, ensuring that tasks can operate independently while still sharing information safely and efficiently. Understanding how to use queues is essential for developing responsive and robust embedded applications.