NeuroAgent

Fix ESP32-S3 Core Dump with FreeRTOS Queues

Learn how to fix ESP32-S3 Guru Meditation Error when using FreeRTOS queues for temperature data transfer. Discover solutions for float handling, stack sizing, and queue synchronization.

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:

c
#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:

c
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:

c
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?

NeuroAgent

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

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:

c
// 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:

c
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:

c
// 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:

c
// 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

c
// 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

  1. Use Static Queue Allocation: As mentioned in the ESP32 Forum, static queues can prevent dynamic allocation issues:
c
StaticQueue_t queue_cb;
uint8_t queue_storage[10 * sizeof(sensor_data_t)];
gTempQueue = xQueueCreate(10, sizeof(sensor_data_t), queue_storage, &queue_cb);
  1. Enable Watchdog Timers: Use hardware watchdog timers to recover from hangs.

  2. Implement Task Priorities: Ensure proper priority relationships between tasks.

  3. Use Mutexes for Shared Resources: Protect shared data with mutexes if needed.

Debugging Techniques

When Guru Meditation errors occur, use the following debugging approach:

  1. Analyze the Backtrace: Your backtrace shows 0x40384b9b:0x3fcedfd0, which points to the FreeRTOS kernel. This suggests a kernel-level issue.

  2. Enable Core Dump Analysis: As mentioned in the Espressif documentation, use core dump features to identify the exact location of the error.

  3. Use Serial Debugging: Add more debug output to track task execution flow.

  4. 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

  1. ESP32 FreeRTOS Queue Guru Meditation Error Analysis - Stack Overflow
  2. ESP32 Guru Meditation Error Documentation - Espressif
  3. ESP32 Forum: Guru Meditation Error at uxListRemove
  4. Stack Overflow: Float in ESP32 Interrupt Handler
  5. ESP32-C3 Fatal Errors Documentation
  6. ESP-Techpedia: Guru Meditation Error Debugging Guide