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
相关产品推荐
相关产品推荐

