You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32Cam运行FreeRTOS生产者消费者代码触发Double exception内存损坏

ESP32Cam上FreeRTOS生产者消费者队列触发Double Exception崩溃问题

环境与配置

  • 开发环境:Windows10虚拟机 + VSCode + PlatformIO
  • 开发板:ESP32Cam(未启用PSRAM)
  • platformio.ini配置:
[env:esp32cam]
platform = espressif32
board = esp32cam
framework = espidf
monitor_speed=115200
monitor_rts= 0
monitor_dtr= 0
monitor_filters=colorize
  • 代码来源:《Developing IoT Projects with ESP32》书中的FreeRTOS生产者消费者示例

问题现象

运行代码时触发Guru Meditation Error: Core 0 panic'ed (Double exception),尝试以下排查手段均无效:

  • 修改任务优先级
  • 调整任务栈大小
  • 变更生产者/消费者函数的声明位置
  • 更换开发板
    仅移除消费者任务时,生产者任务可正常运行,期望队列能正常输出数据。

错误日志

mI (307) app: application started
I (307) S�: 
consumer-1      R       5       1       3744    10
main            X       1       0       2036    4
IDLE1           R       0       1       1036    6
IDLE0           R       0       0       1232    5
producer        B       5       2147483647      3536    8
esp_timer       S       22      0       3576    3
ipc1            S       24      1       480     2
Tmr Svc         B       1       0       1476    7
consumer-0      B       5       0       3512    9
ipc0            S       24      0       488     1
m
Guru Meditation Error: Core  0 panic'ed (Double exception). 

Core  0 register dump:
PC      : 0x4008d36e  PS      : 0x00040136  A0      : 0x8008634c  A1      : 0x3ffb4e00
A2      : 0x00000003  A3      : 0x3f400fe4  A4      : 0x2d72656d  A5      : 0x20202030
A6      : 0x42092020  A7      : 0x30093509  A8      : 0x800d0e70  A9      : 0x3ffb4db0  
A10     : 0x00000003  A11     : 0x42092020  A12     : 0x3f4001b4  A13     : 0x00000133
A14     : 0x42092020  A15     : 0x3ffb4e10  SAR     : 0x00000004  EXCCAUSE: 0x00000002
EXCVADDR: 0x00000123  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffb1  


Backtrace: 0x4008d36b:0x3ffb4e00 0x40086349:0x3ffb4f30 0x40086349:0x0d390932 |<-CORRUPTED

测试代码

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_log.h>

#define TERMINATE_CONSUMER -1

namespace AppResources {
    QueueHandle_t m_number_queue;
    const constexpr int MAX_COUNT{10};
    const constexpr char *TAG{"app"};

void producer(void *p){
        int cnt{0};
        vTaskDelay(pdMS_TO_TICKS(500));
        while (++cnt <= MAX_COUNT){
            if(xQueueSendToBack(m_number_queue, &cnt, portMAX_DELAY) == pdPASS){
                ESP_LOGI(TAG, "p:%d - Producer inserted successfully", cnt);
                // Notify the consumer task (if using notifications)
                // vTaskNotifyGive(consumer_handle);
            }else{
                ESP_LOGE(TAG, "Send to Queue failed at Count %d", cnt);
            }
        }
        int terminate_signal = TERMINATE_CONSUMER;
        xQueueSendToBack(m_number_queue, &terminate_signal, portMAX_DELAY);
        ESP_LOGI(TAG, "Producer finished, deleting task");
        vTaskDelete(nullptr);
    }; // end of producer

    void consumer(void *p){
        int num;

    //  ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

        while (true){
            if (xQueueReceive(m_number_queue, &num, portMAX_DELAY)== pdPASS){
                
                if (num == TERMINATE_CONSUMER) {
                    ESP_LOGI(TAG, "Consumer received termination signal.");
                    break; // Exit the loop and terminate the task
                }
                ESP_LOGI(TAG, "c%d:%d - Item received from the Queue", (int)(uintptr_t)p, num);
                vTaskDelay(pdMS_TO_TICKS(50));
                
            }else{
                ESP_LOGE(TAG, "Failed to receive item from the Queue");
            }
        }
        ESP_LOGI(TAG, "Consumer finished, deleting task");
        vTaskDelete(nullptr);
    }; // end of consumer
} // end of namespace

extern "C" void app_main() {
    //Uncomment this to Log the number of cores
    /*
    int core_count = portNUM_PROCESSORS;
    ESP_LOGI("CoreInfo", "Number of cores: %d", core_count);
    */
    ESP_LOGI(AppResources::TAG, "Application started.");

    AppResources::m_number_queue = xQueueCreate(5, sizeof(int));
    if (AppResources::m_number_queue == nullptr) {
        ESP_LOGE(AppResources::TAG, "Queue creation failed!");
        return;
    }else{
        ESP_LOGI(AppResources::TAG,"Queue Successful created at address %p", AppResources::m_number_queue);
        
        // Error handling for task creation
        if (xTaskCreate(AppResources::producer, "producer", 4096, nullptr, 5, nullptr) != pdPASS) {
            ESP_LOGE(AppResources::TAG, "Failed to create producer task!");
        }
        if (xTaskCreatePinnedToCore(AppResources::consumer, "consumer-0", 4096, (void *)0, 5, nullptr, 0) != pdPASS) {
            ESP_LOGE(AppResources::TAG, "Failed to create consumer task on core 0!");
        }
        if (xTaskCreatePinnedToCore(AppResources::consumer, "consumer-1", 4096, (void *)1, 5, nullptr, 1) != pdPASS) {
            ESP_LOGE(AppResources::TAG, "Failed to create consumer task on core 1!");
        }
    }

    char buffer[256]{0};
    vTaskList(buffer);
    ESP_LOGI(AppResources::TAG, "\n%s", buffer);
} // end of app main

解决方案

1. 修复栈溢出风险

从vTaskList输出可见,consumer-0已使用3512字节栈,接近4096的设置上限,ESP32Cam的默认内存分配较为紧张,容易触发栈溢出导致内存 corruption:

  • 将消费者任务栈大小调整为8192:
    xTaskCreatePinnedToCore(AppResources::consumer, "consumer-0", 8192, (void *)0, 5, nullptr, 0)
    
  • 同时修正代码中receiced的拼写错误为received,避免潜在的字符串处理异常。

2. 移除过早的任务状态查询

app_main执行时,刚创建的任务尚未完成初始化,此时调用vTaskList可能触发非法内存访问,直接移除该调试代码:

// 移除以下代码段
// char buffer[256]{0};
// vTaskList(buffer);
// ESP_LOGI(AppResources::TAG, "\n%s", buffer);

若需查看任务状态,可在生产者任务中添加延迟后调用,或使用ESP-IDF自带的系统监控工具。

3. 确认ESP-IDF版本兼容性

切换PlatformIO的espressif32平台到稳定版(如v5.1.x),避免新版本API变动与示例代码不兼容。


内容的提问来源于stack exchange,提问作者Érico Pinto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:12:33