Why is my ESP32-S3 experiencing a core dump when using FreeRTOS queues to pass temperature data between tasks?
I’m trying to pass temperature readings from a DHT20 sensor task to an LED blink task using a queue, but the system crashes with a Guru Meditation Error. Here’s my implementation:
DHT20 Sensor Task:
#include "DN_Task_DHT20.h"
DHT20 sensor_dht20(&Wire); // DHT20 sensor object
float temperature_dht20 = 0.0f; // Temperature value
float humidity_dht20 = 0.0f; // Humidity value
void Task_DHT20(void *pvParameters) {
float temp_temperature = 0.0f;
float temp_humidity = 0.0f;
sensor_dht20.begin();
vTaskDelay(1000 / portTICK_PERIOD_MS); // Initial delay for sensor stabilization
while (1){
int error_code = sensor_dht20.read();
if (error_code == DHT20_OK) {
temp_temperature = sensor_dht20.getTemperature();
temp_humidity = sensor_dht20.getHumidity();
Serial.printf("[INFO][DHT20]: Temperature: %.2f C, Humidity: %.2f %%\n", temp_temperature, temp_humidity);
temperature_dht20 = temp_temperature;
humidity_dht20 = temp_humidity;
if(gTempQueue) {
if(xQueueSend(gTempQueue, &temperature_dht20, (TickType_t)0) == pdTRUE) {
// Successfully sent temperature to queue
Serial.println("[INFO][DHT20]: Temperature sent to queue");
} else {
Serial.println("[ERROR][DHT20]: Failed to send temperature to queue");
}
vTaskDelay(10 / portTICK_PERIOD_MS);
} else {
Serial.printf("[ERROR][DHT20]: ERROR ON READING SENSOR: %d\n", error_code);
}
vTaskDelay(500 / portTICK_PERIOD_MS); // Delay for 500 milliseconds
}
}
}
LED Blink Task:
void Task_LEDBlink(void *pvParameters) {
pinMode(LED_BUILTIN_PIN, OUTPUT);
vTaskDelay(2000); // Wait for system to stabilize
// Default before first reading
float currentTemperature = 25.0f;
float receivedTemperature = 25.0f;
uint16_t blinkMs = tempToFreqByRange(currentTemperature); // full period in ms
while(1){
Serial.println("[DEBUG][LED BLINK] Waiting for temperature data...");
if(xQueueReceive(gTempQueue, &receivedTemperature, portMAX_DELAY) == pdTRUE) {
Serial.printf("[DEBUG][LED BLINK] Received Temperature: %.2f C\n", receivedTemperature);
currentTemperature = receivedTemperature;
blinkMs = tempToFreqByRange(currentTemperature);
}
Serial.printf("[INFO][LED BLINK] Current Temperature: %.2f C, Blink Frequency: %d ms\n", currentTemperature, blinkMs);
digitalWrite(LED_BUILTIN_PIN, HIGH);
vTaskDelay(blinkMs);
digitalWrite(LED_BUILTIN_PIN, LOW);
vTaskDelay(blinkMs);
}
}
Setup Function:
void setup() {
Serial.begin(115200); // UART @ 115200 bps
initQueues();
Wire.begin(11, 12);
delay(500);
// Delay to allow Serial Monitor to initialize
xTaskCreate(
Task_DHT20, // Task function
"DHT20 Task", // Name of the task
4096, // Stack size (in words)
NULL, // Task input parameter
2, // Priority of the task
NULL // Task handle
);
xTaskCreate(
Task_LEDBlink, // Task function
"LED Blink Task", // Name of the task
2048, // Stack size (in words)
NULL, // Task input parameter
1, // Priority of the task
NULL // Task handle
);
}
Error Log:
Rebooting...
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0x29 (SPI_FAST_FLASH_BOOT)
Saved PC:0x4037b4dd
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce2820,len:0x116c
load:0x403c8700,len:0xc2c
load:0x403cb700,len:0x3108
entry 0x403c88b8
[INFO][Queue] gTempQueue created successfully
[ 20][I][esp32-hal-i2c-ng.c:112] i2cInit(): Initializing I2C Master: num=0 sda=11 scl=12 freq=100000
[ 530][W][Wire.cpp:300] begin(): Bus already started in Master Mode.
[INFO][DHT20]: Temperature: 25.37 C, Humidity: 65.91 %
[INFO][DHT20]: Temperature sent to queue
[DEBUG][LED BLINK] Waiting for temperature data...
Guru Meditation Error: Core 0 panic'ed (Double exception).
Core 0 register dump:
PC : 0x40384b9e PS : 0x00040b36 A0 : 0x803821c4 A1 : 0x3fcedfd0
A2 : 0x00040b36 A3 : 0x00040026 A4 : 0x00000004 A5 : 0x00001800
A6 : 0x3fc984bc A7 : 0x3fce9710 A8 : 0x3fcee090 A9 : 0x00001800
A10 : 0x00000084 A11 : 0x00001800 A12 : 0x3fcee070 A13 : 0x00000084
A14 : 0x00000002 A15 : 0x3fc9ad00 SAR : 0x0000001d EXCCAUSE: 0x00000002
EXCVADDR: 0x00001800 LBEG : 0x400556d5 LEND : 0x400556e5 LCOUNT : 0xffffffff
Backtrace: 0x40384b9b:0x3fcedfd0 0x403821c1:0x3fcee000 0x40380df9:0x3fcee020 0x403765af:0x3fcee040 0x403765c9:0x3fcee070 0x403762d5:0x3fcee090
What could be causing this core dump when using FreeRTOS queues on ESP32-S3, and how can I fix it?
The Guru Meditation Error with “Double exception” in your ESP32-S3 when using FreeRTOS queues is typically caused by one or more of the following issues: improper float data handling, insufficient stack sizes, queue overflow, or memory corruption. Based on your code and error analysis, here are the specific causes and solutions:
Contents
- Common Causes of Guru Meditation Errors with FreeRTOS Queues
- Float Data Handling Issues
- Stack Size Configuration Problems
- Queue Overflow and Synchronization Issues
- Memory Management and Corruption
- Step-by-Step Solutions
- Preventive Measures
- Debugging Techniques
- Conclusion
Common Causes of Guru Meditation Errors with FreeRTOS Queues
The “Double exception” error indicates that the ESP32-S3 encountered a critical issue, recovered briefly, but then encountered another exception. This pattern typically points to fundamental problems in your task implementation or data handling. According to Espressif’s documentation, Guru Meditation errors occur when “the instruction which was executed was not a valid instruction,” often due to stack overflow, memory corruption, or improper use of hardware features.
Float Data Handling Issues
The primary issue in your code is the use of float data in FreeRTOS queues. As mentioned in the Stack Overflow answer, “in ESP32 we can’t use float in the interrupt, because it will use the FPU, which is not allowed inside an interrupt handler.” The DHT20 sensor reading likely triggers an I2C interrupt context, causing the FPU to be accessed inappropriately.
Solution:
Convert float data to integer representation for queue transmission:
// Convert temperature to integer representation
typedef struct {
int16_t temp_celsius; // Temperature in Celsius * 100
int16_t humidity_percent; // Humidity in percent * 100
} sensor_data_t;
// In DHT20 task:
int16_t temp_int = (int16_t)(temp_temperature * 100);
int16_t hum_int = (int16_t)(temp_humidity * 100);
sensor_data_t data = {temp_int, hum_int};
xQueueSend(gTempQueue, &data, (TickType_t)0);
// In LED task:
sensor_data_t received_data;
if(xQueueReceive(gTempQueue, &received_data, portMAX_DELAY) == pdTRUE) {
float temp = (float)received_data.temp_celsius / 100.0f;
float hum = (float)received_data.humidity_percent / 100.0f;
}
Stack Size Configuration Problems
Your current stack sizes (4096 and 2048 words) might be insufficient. On ESP32, FreeRTOS stack sizes are specified in bytes, not words as in standard FreeRTOS implementations. The ESP32 Forum thread confirms this common misconception.
Recommended Stack Sizes:
xTaskCreate(
Task_DHT20, // Task function
"DHT20 Task", // Name of the task
8192, // Stack size in bytes (was 4096 words)
NULL, // Task input parameter
2, // Priority of the task
NULL // Task handle
);
xTaskCreate(
Task_LEDBlink, // Task function
"LED Blink Task", // Name of the task
4096, // Stack size in bytes (was 2048 words)
NULL, // Task input parameter
1, // Priority of the task
NULL // Task handle
);
Queue Overflow and Synchronization Issues
Your DHT20 task sends data every 500ms, but the LED task might not process it fast enough. The short 10ms delay after sending doesn’t prevent potential queue overflow. The ESP32 Forum discussion shows similar issues at uxListRemove, indicating queue management problems.
Solution:
Implement proper queue flow control:
// In DHT20 task - check queue availability before sending
if(gTempQueue) {
// Remove any old data to prevent overflow
xQueueReset(gTempQueue);
if(xQueueSend(gTempQueue, &data, (TickType_t)10) == pdTRUE) {
Serial.println("[INFO][DHT20]: Temperature sent to queue");
} else {
Serial.println("[WARNING][DHT20]: Queue full, data dropped");
}
vTaskDelay(500 / portTICK_PERIOD_MS); // Longer delay
}
Memory Management and Corruption
The “Double exception” often indicates memory corruption from stack overflow or heap issues. The ESP32 Forum thread mentions similar problems with assert failures in queue operations.
Solution:
Enable stack overflow detection and heap monitoring:
// In setup():
// Enable stack overflow detection
vTaskSetApplicationTaskTag(NULL, (TaskFunction_t)1);
// Enable heap monitoring
heap_caps_check_integrity_all(true);
// Monitor stack usage
void Task_DHT20(void *pvParameters) {
// ... existing code ...
while(1) {
// Add stack monitoring
UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL);
if(stackHighWaterMark < 100) { // Warning threshold
Serial.printf("[WARNING][DHT20]: Stack low: %u words\n", stackHighWaterMark);
}
// ... rest of the code ...
}
}
Step-by-Step Solutions
1. Fix Float Data Handling
Replace float queues with structured integer data as shown above. This eliminates FPU usage in interrupt contexts.
2. Adjust Stack Sizes
Convert your stack sizes from words to bytes and increase them for safety:
- DHT20 Task: 8192 bytes
- LED Task: 4096 bytes
3. Implement Queue Flow Control
Use xQueueReset() or implement a more sophisticated queue management system to prevent overflow.
4. Add Error Handling
// In setup():
if(xTaskCreate(Task_DHT20, "DHT20 Task", 8192, NULL, 2, NULL) != pdPASS) {
Serial.println("[FATAL][Setup]: Failed to create DHT20 task");
while(1);
}
5. Use Proper Task Delays
Remove the 10ms delay after queue send and rely on the main 500ms loop delay.
Preventive Measures
- Use Static Queue Allocation: As mentioned in the ESP32 Forum, static queues can prevent dynamic allocation issues:
StaticQueue_t queue_cb;
uint8_t queue_storage[10 * sizeof(sensor_data_t)];
gTempQueue = xQueueCreate(10, sizeof(sensor_data_t), queue_storage, &queue_cb);
-
Enable Watchdog Timers: Use hardware watchdog timers to recover from hangs.
-
Implement Task Priorities: Ensure proper priority relationships between tasks.
-
Use Mutexes for Shared Resources: Protect shared data with mutexes if needed.
Debugging Techniques
When Guru Meditation errors occur, use the following debugging approach:
-
Analyze the Backtrace: Your backtrace shows
0x40384b9b:0x3fcedfd0, which points to the FreeRTOS kernel. This suggests a kernel-level issue. -
Enable Core Dump Analysis: As mentioned in the Espressif documentation, use core dump features to identify the exact location of the error.
-
Use Serial Debugging: Add more debug output to track task execution flow.
-
Monitor System Resources: Track stack usage, heap fragmentation, and CPU utilization.
Conclusion
The Guru Meditation Error in your ESP32-S3 FreeRTOS implementation is primarily caused by improper float data handling in queues and insufficient stack sizes. By converting float data to integer representation, adjusting stack sizes from words to bytes, implementing proper queue flow control, and adding comprehensive error handling, you can eliminate these crashes. Always remember that ESP32-S3 has specific requirements for FreeRTOS implementation that differ from standard FreeRTOS, particularly regarding FPU usage and stack size specifications. Implement the suggested changes methodically and test each component thoroughly to ensure stable operation.
Sources
- ESP32 FreeRTOS Queue Guru Meditation Error Analysis - Stack Overflow
- ESP32 Guru Meditation Error Documentation - Espressif
- ESP32 Forum: Guru Meditation Error at uxListRemove
- Stack Overflow: Float in ESP32 Interrupt Handler
- ESP32-C3 Fatal Errors Documentation
- ESP-Techpedia: Guru Meditation Error Debugging Guide