0
0
FreeRTOSprogramming~5 mins

Producer-consumer pattern in FreeRTOS

Choose your learning style9 modes available
Introduction

The producer-consumer pattern helps two parts of a program work together smoothly. One part makes data (producer), and the other uses it (consumer). This keeps things organized and avoids problems when both work at the same time.

When one task creates data and another task processes it in a FreeRTOS system.
When you want to avoid losing data because the consumer is slower than the producer.
When tasks run at different speeds but need to share information safely.
When you want to use queues to pass messages or data between tasks.
When you want to keep your program responsive by separating work into tasks.
Syntax
FreeRTOS
/* Create a queue */
QueueHandle_t xQueue = xQueueCreate(queue_length, item_size);

/* Producer task */
void vProducerTask(void *pvParameters) {
    DataType data;
    for(;;) {
        // Prepare data
        xQueueSend(xQueue, &data, portMAX_DELAY);
    }
}

/* Consumer task */
void vConsumerTask(void *pvParameters) {
    DataType receivedData;
    for(;;) {
        if(xQueueReceive(xQueue, &receivedData, portMAX_DELAY) == pdPASS) {
            // Process receivedData
        }
    }
}

Use xQueueCreate() to make a queue that holds data between producer and consumer.

xQueueSend() adds data to the queue; xQueueReceive() takes data out safely.

Examples
This example creates a queue for 5 integers. The producer sends increasing numbers every 100 milliseconds.
FreeRTOS
QueueHandle_t xQueue = xQueueCreate(5, sizeof(int));

void vProducerTask(void *pvParameters) {
    int value = 0;
    for(;;) {
        xQueueSend(xQueue, &value, portMAX_DELAY);
        value++;
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}
The consumer waits for data and processes each integer it receives from the queue.
FreeRTOS
void vConsumerTask(void *pvParameters) {
    int receivedValue;
    for(;;) {
        if(xQueueReceive(xQueue, &receivedValue, portMAX_DELAY) == pdPASS) {
            // Use receivedValue here
        }
    }
}
Sample Program

This program creates a queue for 3 integers. The producer task sends numbers every 500 milliseconds. The consumer task receives and prints them. The queue safely passes data between tasks.

FreeRTOS
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include <stdio.h>

QueueHandle_t xQueue;

void vProducerTask(void *pvParameters) {
    int value = 1;
    for(;;) {
        xQueueSend(xQueue, &value, portMAX_DELAY);
        printf("Produced: %d\n", value);
        value++;
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

void vConsumerTask(void *pvParameters) {
    int receivedValue;
    for(;;) {
        if(xQueueReceive(xQueue, &receivedValue, portMAX_DELAY) == pdPASS) {
            printf("Consumed: %d\n", receivedValue);
        }
    }
}

int main(void) {
    xQueue = xQueueCreate(3, sizeof(int));
    if(xQueue == NULL) {
        printf("Queue creation failed!\n");
        return 1;
    }

    xTaskCreate(vProducerTask, "Producer", 1000, NULL, 1, NULL);
    xTaskCreate(vConsumerTask, "Consumer", 1000, NULL, 1, NULL);

    vTaskStartScheduler();

    for(;;);
    return 0;
}
OutputSuccess
Important Notes

Make sure the queue size fits your data flow to avoid blocking tasks too long.

Use portMAX_DELAY to wait indefinitely for queue operations.

Always check if queue creation succeeds before using it.

Summary

The producer-consumer pattern helps tasks share data safely using queues.

Producers send data to the queue; consumers receive and process it.

FreeRTOS queues handle synchronization so tasks don't interfere with each other.