-
Notifications
You must be signed in to change notification settings - Fork 8k
Description
Answers checklist.
- I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
- I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
- I have searched the issue tracker for a similar issue and not found a similar issue.
IDF version.
v5.5.1
Espressif SoC revision.
ESP32-D0WDR2-V3 (revision v3.1)
Operating System used.
Windows
How did you build your project?
Eclipse IDE
If you are using Windows, please specify command line type.
CMD
Development Kit.
CUSTOM BOARD
Power Supply used.
Battery
What is the expected behavior?
One task pushes parsed UART messages into the queue and another task consumes those messages and processes them. Wi-Fi initialization and operation should run normally without interfering with these two tasks. There should be no crash, because the queue operations and Wi-Fi stack appear to be unrelated subsystems, although both ultimately depend on FreeRTOS scheduling and memory management.
What is the actual behavior?
Unexpected crash when using a FreeRTOS queue located in PSRAM after upgrading to ESP-IDF v5.5.1
Hello Espressif team,
I am migrating a project from ESP-IDF v5.1.4 to v5.5.1 and found a stability problem related to a FreeRTOS queue whose storage buffer is allocated in PSRAM. The project has always worked reliably in v5.1.4, but after upgrading to v5.5.1 the device crashes during Wi-Fi initialization (WPA2 connection stage). The crash occurs before any UART traffic is processed. ESP32 V3.1
The issue seems to appear only when:
- The queue storage buffer is in PSRAM.
- The queue is accessed by tasks running in both internal RAM and external RAM (static task in PSRAM, another task in internal RAM).
- Wi-Fi is initialized after the queue creation.
Steps to reproduce.
Below is the exact relevant code (simplified but complete). This is the queue and stream-buffer setup, plus the two tasks that use them:
// Initialize On Data Rx Queue
uint8_t *RXDataQueueBuffer = (uint8_t *)ps_malloc(sizeof(UART_Message) * 128);
static StaticQueue_t RXStaticQueue;
OnDataRxQueue = xQueueCreateStatic(128, sizeof(UART_Message), RXDataQueueBuffer, &RXStaticQueue);
// Initialize RX Raw Stream
static constexpr size_t RXDataQueueRawSize = 1024 * 50;
uint8_t *RXDataQueueBufferRaw = (uint8_t *)ps_malloc(RXDataQueueRawSize);
static StaticStreamBuffer_t RXStaticStreamRaw;
RXDataQueueRaw = xStreamBufferCreateStatic(
RXDataQueueRawSize,
128,
RXDataQueueBufferRaw,
&RXStaticStreamRaw
);
// RX UART Task (stack in PSRAM)
EXT_RAM_BSS_ATTR static StackType_t rxStack[7 * 1024];
static StaticTask_t rxTaskBuffer;
rxTaskHandle = xTaskCreateStaticPinnedToCore(
rxTask,
"SerialRXTask",
7 * 1024,
nullptr,
2,
rxStack,
&rxTaskBuffer,
1
);
// Task that processes parsed UART messages
xTaskCreatePinnedToCore(
[](void *param) {
while (!OnDataRxQueue) vTaskDelay(pdMS_TO_TICKS(5));
UART_Message msg;
for (;;) {
if (xQueueReceive(OnDataRxQueue, &msg, portMAX_DELAY) == pdPASS) {
UART_DataProcess(msg);
}
}
},
"UART_DATA_PROCCESS_TASK",
7 * 1024,
nullptr,
1,
nullptr,
1
);And here are the two tasks that use the stream buffer and the queue:
static void rxTask(void *parameters) {
constexpr size_t BUFFER_SIZE = 512;
uint8_t receivedBuffer[BUFFER_SIZE];
while (!uart_is_driver_installed(UART_NUM_1)) vTaskDelay(pdMS_TO_TICKS(5));
for (;;) {
int len = uart_read_bytes(UART_NUM_1, receivedBuffer, BUFFER_SIZE, pdMS_TO_TICKS(1));
if (len > 0) {
size_t total = 0;
while (total < (size_t)len) {
size_t sent = xStreamBufferSend(RXDataQueueRaw, receivedBuffer + total, len - total, pdMS_TO_TICKS(1));
total += sent;
if (uxSemaphoreGetCount(RTO::uartStopFlag)) { rxTaskHandle = nullptr; vTaskDelete(NULL); }
taskYIELD();
}
}
if (uxSemaphoreGetCount(RTO::uartStopFlag)) { rxTaskHandle = nullptr; vTaskDelete(NULL); }
taskYIELD();
}
}
static void RXQueueHandler(void *parameters) {
constexpr size_t ACCUM_CAP = 1024 * 2;
constexpr size_t ACCUM_MAX = ACCUM_CAP - 1;
while (!RXDataQueueRaw) vTaskDelay(pdMS_TO_TICKS(5));
uint8_t chunk[512];
PSRAMString accum;
accum.reserve(ACCUM_CAP);
UART_Message receivedData;
UARTDeserializer deserializer(30);
for (;;) {
size_t n = xStreamBufferReceive(RXDataQueueRaw, chunk, sizeof(chunk), pdMS_TO_TICKS(1));
if (n > 0) {
for (size_t i = 0; i < n; ++i) {
uint8_t c = chunk[i];
if (c == '\n') {
if (!accum.empty()) {
String line(accum.c_str());
line.trim();
if (deserializer.makeUARTMessage(line, receivedData) && OnDataRxQueue) {
xQueueSend(OnDataRxQueue, &receivedData, portMAX_DELAY);
}
accum.clear();
}
taskYIELD();
} else {
if (accum.size() < ACCUM_MAX) accum.push_back((char)c);
else accum.clear();
}
}
}
taskYIELD();
}
}
### Debug Logs.
```plain
ESP_ERROR_CHECK failed: esp_err_t 0x101 (ESP_ERR_NO_MEM) at 0x4019db45
--- 0x4019db45: wifi_init_sta() at C:/Firmware/ws5.5.1-ard3.3.3-ide3.6.0/SLYDE-Firmware/main/lib/6sense_kernel/wifi_test.cpp:70
file: "./main/lib/6sense_kernel/wifi_test.cpp" line 70
func: void wifi_init_sta()
expression: esp_wifi_init(&cfg)
abort() was called at PC 0x4008ee8f on core 1
--- 0x4008ee8f: _esp_error_check_failed at C:/Users/Ivan/espidf551/components/esp_system/esp_err.c:49
Backtrace: 0x4008ef31:0x3ffd0380 0x4008eefd:0x3ffd03a0 0x400954d2:0x3ffd03c0 0x4008ee8f:0x3ffd0430 0x4019db45:0x3ffd0460 0x400e8f00:0x3ffd05f0 0x400dae32:0x3ffd0640 0x400db080:0x3ffd0950 0x400da1b3:0x3ffd0990 0x401a998a:0x3ffd09b0
--- 0x4008ef31: panic_abort at C:/Users/Ivan/espidf551/components/esp_system/panic.c:469
--- 0x4008eefd: esp_system_abort at C:/Users/Ivan/espidf551/components/esp_system/port/esp_system_chip.c:87
--- 0x400954d2: abort at C:/Users/Ivan/espidf551/components/newlib/src/abort.c:38
--- 0x4008ee8f: _esp_error_check_failed at C:/Users/Ivan/espidf551/components/esp_system/esp_err.c:49
--- 0x4019db45: wifi_init_sta() at C:/Firmware/ws5.5.1-ard3.3.3-ide3.6.0/SLYDE-Firmware/main/lib/6sense_kernel/wifi_test.cpp:70
--- 0x400e8f00: initUartProtocol() at C:/Firmware/ws5.5.1-ard3.3.3-ide3.6.0/SLYDE-Firmware/main/lib/uart_protocol/uart_protocol.cpp:878
--- 0x400dae32: sixsense_iot::startJordan() at C:/Firmware/ws5.5.1-ard3.3.3-ide3.6.0/SLYDE-Firmware/main/lib/6sense_kernel/6sense_kernel.cpp:638
--- 0x400db080: sixsense_iot::system_start() at C:/Firmware/ws5.5.1-ard3.3.3-ide3.6.0/SLYDE-Firmware/main/lib/6sense_kernel/6sense_kernel.cpp:878
--- 0x400da1b3: setup() at C:/Firmware/ws5.5.1-ard3.3.3-ide3.6.0/SLYDE-Firmware/main/main.cpp:19
--- 0x401a998a: loopTask(void*) at C:/Firmware/ws5.5.1-ard3.3.3-ide3.6.0/SLYDE-Firmware/components/arduino/cores/esp32/main.cpp:67Diagnostic report archive.
No response
More Information.
Problem summary
The queue storage buffer (RXDataQueueBuffer) resides in PSRAM using ps_malloc().
The queue is accessed from two tasks located in different memory regions.
Everything works reliably in ESP-IDF v5.1.4.
After migrating to ESP-IDF v5.5.1, the device crashes as soon as Wi-Fi initializes, even before UART traffic.
If the tasks are moved to PSRAM as well, the crash becomes less frequent but still appears at random.
Questions
Is it still supported in ESP-IDF v5.5.1 to place a queue storage buffer in PSRAM when it is accessed by tasks located in internal RAM?
Is there any recommended approach for safely mixing internal RAM tasks and PSRAM-backed FreeRTOS objects?
Should xQueueCreateStatic() be avoided when the storage buffer is in PSRAM?
Is there any documented limitation regarding PSRAM use for queue or stream-buffer storage in IDF versions 5.2+?
Any guidance on the correct or recommended way to handle this scenario in ESP-IDF v5.5.1 would be greatly appreciated.
Thanks!