yahboom
HomeLearn
Solution
Blog
Online Store
About Us
EN/中文
ESP32 Core Board📖
1. ESP32 Introduction
  • 1. ESP32S3 Overview
  • 2. Environment Setup Introduction
  • 3. Dev Board Introduction
2. ESP-IDF Development Tutorial
1. Before Development
  • 1. Environment Setup (Windows)
  • 2. Environment Setup (Linux)
  • 3. Build and Flash
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. ESP_TIMER
  • 5. GPTIMER
  • 6. Watchdog Timer
  • 7. DMA
  • 8. ADC
  • 9. PWM Breathing LED
  • 10. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication Experiment
  • 2. I2C_OLED Display Experiment
  • 3. SPI Bus Communication Experiment
  • 4. PSRAM External Memory Experiment
  • 5. Flash Read and Write Experiment
  • 6. USB Emulated Mass Storage Experiment
4. FreeRTOS operating system
  • 1.FreeRTOS Core Concepts Theory
  • 2.Task Creation and Management
  • 3.Queue
  • 4.Binary Semaphore
  • 5.Mutex
  • 6.Event Groups
  • 7.Software Timer
  • 8.Task Scheduler
  • 9.Low Power Mode
  • 10.Deadlock
  • 11.Priority Inversion
5. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Client Experiment
  • 5. UDP Server Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. Socket Programming Basics
  • 9. HTTP Client Experiment
  • 10. HTTP Server Experiment
  • 11. MQTT IoT Communication Protocol
  • 12. WIFI OTA Upgrade
  • 13. Bluetooth Fundamentals
  • 14. Bluetooth Slave Mode
  • 15. Bluetooth Master Mode
6. Audio Applications
  • 1.I2S Microphone Recording and U-Disk Playback
  • 2.I2S Audio Playback Experiment
  • 3.Repeater Experiment
7. Xiaozhi AI Voice
  • 1. Burn Xiaozhi Firmware
  • 2. Network and Configuration
  • 3. AI Agent Settings
  • 4. Program Analysis
  • 5. Free Chat
3. Arduino Development Course
1. Before Development
  • 1. Environment Setup
  • 2. Build and Flash
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. ESP_TIMER
  • 5. GPTIMER
  • 6. Watchdog Timer
  • 7. ADC
  • 8. PWM Breathing LED
  • 9. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication
  • 2. I2C OLED Display
  • 3. SPI Bus Communication
  • 4. Flash Read and Write
  • 5. USB Emulated Mass Storage
4. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Server Experiment
  • 5. UDP Client Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. HTTP Client Experiment
  • 9. HTTP Server Experiment
  • 10. MQTT IoT Communication Protocol
  • 11. WIFI OTA Upgrade
  • 12. Bluetooth Fundamentals
  • 13. Bluetooth Slave Mode
  • 14. Bluetooth Master Mode
5. Audio Applications
  • 1.I2S Microphone Recording and U-Disk Playback
  • 2.I2S Audio Playback Experiment
  • 3.Repeater Experiment
4. MicroPython Development Course
1. Before Development
  • 1. Environment Setup
  • 2. Build and Flash
  • 3. Thonny IDE
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. TIMER_IT
  • 5. Watchdog Timer
  • 6. ADC
  • 7. PWM Breathing LED
  • 8. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication Experiment
  • 2. I2C_OLED Display Experiment
  • 3. SPI Bus Communication Experiment
  • 4. Flash Read and Write Experiment
  • 5. Print Storage
4. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Client Experiment
  • 5. UDP Server Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. HTTP Client Experiment
  • 9. HTTP Server Experiment
  • 10. MQTT
  • 11. Bluetooth Fundamentals
  • 12. Bluetooth Slave Mode
  • 13. Bluetooth Master Mode
5. Audio Applications
  • 1. I2S Audio Playback Experiment
  • 2. Repeater Experiment
Download
  • Code
  • Hardware_Info
  • 3D_Model_File
  • Software_Tools
  • VMware
  • VM_File
Download ZIP

Welcome to ESP32 Core Board repository

3.Queue

Queue


Queue1. Queue OverviewWhy Do We Need Queues?Typical Application Scenarios2. Core Concepts2.1 How Queues Work2.2 Queue Creation API2.3 Send API2.4 Receive API2.5 Blocking vs Non-Blocking Comparison3. Project Architecture and Flow4. Hardware Dependencies5. Source Code Analysis5.1 Header Files and Macro Configuration5.2 prv_button_level_stable() — Debounce Detection5.3 vSendTask() — Send Task5.4 vRecvTask() — Receive Task5.5 prv_running_horse() — Marquee Effect5.6 app_main() — Main Entry6. Operation Flow6.1 Compilation and Flashing Flow6.2 Normal Operation7. FAQ


1. Queue Overview

Queue is FreeRTOS's most fundamental inter-task communication mechanism. It is a FIFO (First In First Out) data buffer where one task writes data to the queue and another task reads data from it, achieving data transfer and flow control between tasks.

Why Do We Need Queues?

In a multi-tasking system, tasks often need to exchange data. If two tasks directly operate on the same global variable, they face race conditions (one task gets interrupted halfway through writing, causing data corruption). Queues use built-in internal mutex protection to ensure atomicity of data writes and reads, fundamentally avoiding these problems.

Typical Application Scenarios

ScenarioSenderReceiverQueue Function
Button event deliveryGPIO interrupt/polling taskUI processing taskBuffer button events, no loss, no blocking
Sensor data acquisitionADC sampling taskData processing/display taskDecouple sampling rate from computation rate
UART command parsingUART receive taskCommand execution taskBuffer command frames, process frame by frame
Network data forwardingWiFi receive taskBusiness logic taskIsolate network stack from business logic
Log outputVarious business tasksLog writing taskCentralized log management, avoid multi-task contention for peripherals

Core Value: Queues decouple "producers" and "consumers" — both can run at different frequencies, on different CPU cores, without interfering with each other. Producers just stuff data into the queue, consumers take data at their own pace, backpressure naturally occurs when the queue is full, and consumers block and wait when the queue is empty.

This project demonstrates queue creation, sending, and receiving: each button press sends one data item to the queue (green LED lights for 300ms), the receiving task takes one data item every 1 second, and after receiving 30 items, it enters an infinite rainbow marquee loop.


2. Core Concepts

2.1 How Queues Work

  Sender Task (Producer)                    Receiver Task (Consumer)
       │                                      │
       │ xQueueSend(xQueue, &data, 0)        │ xQueueReceive(xQueue, &data, portMAX_DELAY)
       ▼                                      ▼
  ┌──────────────────────────────────────────────────┐
  │               Queue (FIFO)                       │
  │  ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐     │
  │  │ D0  │ D1  │ D2  │ D3  │ ... │     │     │     │
  │  └─────┴─────┴─────┴─────┴─────┴─────┴─────┘     │
  │    Head                                     Tail │
  └──────────────────────────────────────────────────┘

2.2 Queue Creation API

xxxxxxxxxx
QueueHandle_t xQueueCreate(
    UBaseType_t uxQueueLength,   // Queue length (max items)
    UBaseType_t uxItemSize       // Item size (bytes)
);

Returns NULL on failure (insufficient memory).

2.3 Send API

xxxxxxxxxx
BaseType_t xQueueSend(
    QueueHandle_t xQueue,        // Queue handle
    const void *pvItemToQueue,   // Data pointer
    TickType_t xTicksToWait      // Timeout (ticks)
);
xTicksToWaitBehavior
0Non-blocking — returns errQUEUE_FULL immediately if queue is full
portMAX_DELAYPermanent block — waits until queue has space
pdMS_TO_TICKS(100)100ms timeout — returns error after timeout

Must use xQueueSendFromISR() in ISR.

2.4 Receive API

xxxxxxxxxx
BaseType_t xQueueReceive(
    QueueHandle_t xQueue,        // Queue handle
    void *pvBuffer,              // Receive buffer
    TickType_t xTicksToWait      // Timeout (ticks)
);

2.5 Blocking vs Non-Blocking Comparison

ModexTicksToWaitQueue Full/Empty BehaviorApplicable Scenario
Non-blocking send0Return error immediatelyCannot wait scenarios
Blocking sendportMAX_DELAYWait until space availableData must not be lost
Non-blocking receive0Return error immediatelyPolling
Blocking receiveportMAX_DELAYWait until data availableEvent-driven

3. Project Architecture and Flow

​x
app_main()
  ├─ gpio_config()          ← Button GPIO0 (pull-up input)
  ├─ led_strip_init()       ← WS2812 (GPIO48, RMT 10MHz)
  ├─ xQueueCreate(30, sizeof(uint32_t))  ← Queue capacity 30
  ├─ xTaskCreate(vSendTask) → Core 1, Prio 2  (Send task)
  └─ xTaskCreate(vRecvTask) → Core 0, Prio 2  (Receive task)

  GPIO0 pressed ─► vSendTask ──(uint32_t)──► xQueue ──► vRecvTask
                     │                               │
                     ▼                               ▼
            Green LED 300ms (send success)    Take 1 data every 1s
                                               After 30 received → infinite marquee

Queue Parameters:

ParameterValueMeaning
Queue length30Max 30 uint32_t data items buffered
Item size4 bytessizeof(uint32_t)
Send modeNon-blocking (timeout=0)Drop and print warning when queue full
Receive modeBlocking (portMAX_DELAY)Task stays Blocked until data arrives

4. Hardware Dependencies

PinFunctionDescription
GPIO 0BOOT buttonInternal pull-up, active low
GPIO 48WS2812 RGB LEDRMT peripheral driver

Required Components: freertos/FreeRTOS, freertos/task, freertos/queue, driver/gpio, led_strip, esp_log

This project uses a third-party library again: For details, review (Third-party library installation process: 2.Basic Peripherals → 10.RGB LED Effects)

Note: led_strip is a third-party component provided by ESP-IDF Component Registry, not built into IDF. Before use, declare the dependency in main/idf_component.yml, otherwise compilation will fail to find the header file:

xxxxxxxxxx
## IDF Component Manager Manifest File
dependencies:
idf:
 version: '>=4.1.0'
espressif/led_strip: ^3.0.3

After declaration, execute idf.py build, and the component manager will automatically download the component to the managed_components/ directory.


5. Source Code Analysis

Full source code: Source Code → ESP-IDF → 4.FreeRTOS → 2. RTOS_Inter-task_communication → RTOS-QUE

5.1 Header Files and Macro Configuration

This section defines all adjustable parameters such as task priority, stack size, queue capacity, button debounce parameters, and WS2812 LED pins, and declares global handle variables. All macros are concentrated at the file header for easy unified adjustment without modifying deep code.

xxxxxxxxxx
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "led_strip.h"

// Log tag
static const char *TAG = "queue_demo";

/* ==================== Task Config ==================== */

#define SEND_TASK_PRIORITY      2
#define RECV_TASK_PRIORITY      2
#define SEND_TASK_STACK_SIZE    2048
#define RECV_TASK_STACK_SIZE    2048

/* ==================== Queue Config ==================== */

#define QUEUE_LENGTH            30
#define MAX_SEND_COUNT          30
#define MAX_RECV_COUNT          30

/* ==================== Button Config ==================== */
#define BUTTON_GPIO             0
#define DEBOUNCE_MS             30
#define DEBOUNCE_SAMPLES        3

/* ==================== LED Config ==================== */
#define LED_GPIO                48
#define LED_NUM                 1
#define LED_BRIGHTNESS          80

/* ==================== Global Handles ==================== */

static QueueHandle_t xQueue = NULL;
static led_strip_handle_t led_strip;
static uint32_t send_count = 0;
static uint32_t recv_count = 0;

5.2 prv_button_level_stable() — Debounce Detection

Continuously samples GPIO level multiple times, only returns true if all samples are consistent. More reliable than single-delay debouncing (2.KEY example).

xxxxxxxxxx
static bool prv_button_level_stable(uint32_t ulLevel)
{
    for (int i = 0; i < DEBOUNCE_SAMPLES; i++)
    {
        if (gpio_get_level(BUTTON_GPIO) != ulLevel)
        {
            return false;
        }
        vTaskDelay(pdMS_TO_TICKS(DEBOUNCE_MS / DEBOUNCE_SAMPLES));
    }
    return true;
}

5.3 vSendTask() — Send Task

Polls BOOT button, sends incremental data to queue after debouncing (non-blocking), WS2812 green LED lights for 300ms on successful send.

xxxxxxxxxx
static void vSendTask(void *pvParameters)
{
    uint32_t send_data = 0;
    (void)pvParameters;

    while (send_count < MAX_SEND_COUNT)
    {
        while (gpio_get_level(BUTTON_GPIO) == 1)
        {
            vTaskDelay(pdMS_TO_TICKS(10));
        }

        if (!prv_button_level_stable(0))
        {
            continue;
        }

        if (xQueueSend(xQueue, &send_data, 0) == pdPASS)
        {
            send_count++;
            send_data++;
            ESP_LOGI(TAG, "Send OK: %lu | sent: %lu/%d",
                     send_data - 1, send_count, MAX_SEND_COUNT);

            led_strip_set_pixel(led_strip, 0, 0, LED_BRIGHTNESS, 0);
            led_strip_refresh(led_strip);
            vTaskDelay(pdMS_TO_TICKS(300));
            led_strip_clear(led_strip);
            led_strip_refresh(led_strip);
        }
        else
        {
            ESP_LOGW(TAG, "Queue FULL, send failed");
        }

        while (gpio_get_level(BUTTON_GPIO) == 0)
        {
            vTaskDelay(pdMS_TO_TICKS(10));
        }
        prv_button_level_stable(1);
    }

    ESP_LOGI(TAG, "Send task STOP. Total sent: %lu", send_count);
    vTaskDelete(NULL);
}

Why use non-blocking for send (timeout=0)? Button events should not block waiting for space. When queue is full, simply drop and print warning, don't block button handling.

5.4 vRecvTask() — Receive Task

Blocks waiting for queue data, delays 1s after taking each item. After receiving 30, enters infinite rainbow marquee loop.

xxxxxxxxxx
static void vRecvTask(void *pvParameters)
{
    uint32_t recv_data;
    (void)pvParameters;

    while (recv_count < MAX_RECV_COUNT)
    {
        if (xQueueReceive(xQueue, &recv_data, portMAX_DELAY) == pdPASS)
        {
            recv_count++;
            ESP_LOGI(TAG, "Receive: %lu | recv: %lu/%d",
                     recv_data, recv_count, MAX_RECV_COUNT);
        }

        vTaskDelay(pdMS_TO_TICKS(1000));
    }

    ESP_LOGI(TAG, "Receive task STOP. Total received: %lu", recv_count);

    ESP_LOGI(TAG, "Running horse light show start...");
    while (1)
    {
        prv_running_horse(5);
    }
}

Why use blocking for receive (portMAX_DELAY)? When queue is empty, receive task enters Blocked state, not consuming CPU. Once data arrives in queue, scheduler immediately wakes it up. This is the most energy-efficient waiting method in FreeRTOS.

5.5 prv_running_horse() — Marquee Effect

Cycles through 7 rainbow colors on WS2812, parameter cycles controls the number of complete rainbow cycles, LED automatically turns off after completion.

xxxxxxxxxx
static void prv_running_horse(uint32_t cycles)
{
    static const struct { uint8_t r, g, b; } colors[] = {
        {150,   0,   0},    // Red
        {150,  60,   0},    // Orange
        {150, 150,   0},    // Yellow
        {  0, 150,   0},    // Green
        {  0, 150, 150},    // Cyan
        {  0,   0, 150},    // Blue
        {150,   0, 150},    // Purple
    };
    static const int color_count = sizeof(colors) / sizeof(colors[0]);

    for (uint32_t n = 0; n < cycles; n++)
    {
        for (int i = 0; i < color_count; i++)
        {
            led_strip_set_pixel(led_strip, 0,
                                colors[i].r, colors[i].g, colors[i].b);
            led_strip_refresh(led_strip);
            vTaskDelay(pdMS_TO_TICKS(200));
        }
    }
    led_strip_clear(led_strip);
    led_strip_refresh(led_strip);
}

5.6 app_main() — Main Entry

Initializes GPIO button (pull-up input), WS2812 LED (via RMT peripheral driver), creates uint32_t queue of length 30, then creates send task (bound to CPU1) and receive task (bound to CPU0). If queue creation fails, tasks are not started.

xxxxxxxxxx
void app_main(void)
{
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << BUTTON_GPIO),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE,
    };
    gpio_config(&io_conf);

    led_strip_config_t strip_config = {
        .strip_gpio_num          = LED_GPIO,
        .max_leds                = LED_NUM,
        .led_model               = LED_MODEL_WS2812,
        .color_component_format  = LED_STRIP_COLOR_COMPONENT_FMT_GRB,
        .flags.invert_out        = false,
    };
    led_strip_rmt_config_t rmt_config = {
        .resolution_hz  = 10 * 1000 * 1000,
        .flags.with_dma = false,
    };
    ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
    led_strip_clear(led_strip);
    led_strip_refresh(led_strip);

    xQueue = xQueueCreate(QUEUE_LENGTH, sizeof(uint32_t));

    if (xQueue != NULL)
    {
        ESP_LOGI(TAG, "Queue created, press BOOT button to send.");

        xTaskCreatePinnedToCore(vSendTask, "Send", SEND_TASK_STACK_SIZE, NULL,
                                SEND_TASK_PRIORITY, NULL, 1);

        xTaskCreatePinnedToCore(vRecvTask, "Recv", RECV_TASK_STACK_SIZE, NULL,
                                RECV_TASK_PRIORITY, NULL, 0);
    }
}

6. Operation Flow

6.1 Compilation and Flashing Flow

For detailed flashing process: 1. Before Development → 3. Build and Flash

6.2 Normal Operation

  1. After flashing, power on, wait for button input

  2. Press BOOT button → Send success → Green LED lights for 300ms → Serial prints Send OK

  3. Press 30 times consecutively → Send task prints Send task STOP and exits

  4. Receive task takes one data from queue every 1 second

  5. After receiving 30 → Receive task prints Receive task STOP → Infinite rainbow marquee

Log field meanings:

xxxxxxxxxx
I (1263) queue_demo: Queue created, press BOOT button to send.
I (2000) queue_demo: Send OK: 0 | sent: 1/30          ← 1st press send
I (2300) queue_demo: Send OK: 1 | sent: 2/30          ← 2nd press send
I (3263) queue_demo: Receive: 0 | recv: 1/30           ← Received 1st data
I (4263) queue_demo: Receive: 1 | recv: 2/30           ← Received 2nd data
...
I (30000) queue_demo: Send task STOP. Total sent: 30
I (32000) queue_demo: Receive task STOP. Total received: 30
I (32000) queue_demo: Running horse light show start...

0 pressure — Rapidly press 30 times, sends to queue (buffered), receiver takes at its own pace (1/sec) = Queue asynchronous decoupling.


7. FAQ

SymptomCauseSolution
Send failed Queue FULLPressed too fast, queue already has 30Normal — queue capacity is limited, just wait for receiver to take data
Send success but green LED not litLED refresh timing issueConfirm led_strip_refresh is called
Receive task not workingQueue creation failed (NULL)Check xQueueCreate return value
Button insensitiveDebounce time inappropriateAdjust DEBOUNCE_MS (recommended 30ms)
Fast consecutive presses lose dataQueue capacity insufficientIncrease QUEUE_LENGTH
Marquee colors abnormalGRB byte order errorConfirm led_strip_set_pixel parameter order is (R, G, B)
Task Creation and Management
Binary Semaphore

COMPANY

  • About us
  • Team Style
  • Blog

LEARNING & EXPLORATION

  • Tutorials
  • Edge AI hardware
  • Educational robots
  • Embedded intelligent hardware

WHERE TO BUY

  • Yahboom Online Store
  • Amazon
  • Alibaba
  • AliExpress
  • Mercado

TECHNOLOGY SUPPORT

  • Email: support@yahboom.com

BE A DISTRIBUTOR

  • Email: sales@yahboom.com
QR Code
QR Code

Copyright © 2017-2026 Yahboom. All Rights Reserved.

EN/中文