Why this stack overflow occurs?

After running for a while this error message appears:

localTextOne: 1111111111111111111111111111111111111
ERROR A stack overflow in task Task-1 has been detected.
abort() was called at PC 0x4008512c on core 1

This is unexpected because the variable localTextOne is local to the task and I expect it to be only placed on the stack once; or am I missing something.

Code is here:

When you change

the 1024 (bytes of stack) to something larger, say double that, does it take twice as long to crash or does it never crash?

The task code is so simple that there shouldn’t be any leaks in that function.

When the stack size is 1024 words, stack overflow occurs every time after printing 64 lines.

When I increase stack size to 2048, it works flawlessly endlessly, at least for three minutes.

More interestingly; why does this behavior occurs? Theoretically a stack size of 768 + (40 / 4) = 778 words should be sufficient, so: I’m surprised (unpleasantly).

I’m looking at this in FreeRTOSConfig.h
#define configMINIMAL_STACK_SIZE 768
/* apptrace module requires at least 2KB of stack per task */
#define configMINIMAL_STACK_SIZE 2048
But… I don’t have APPTRACE enabled; or do I unknowingly?

When I changed to xTaskCreate() there is a watchdog timer reset after 1108 lines.
“localTextOne: 1111111111111111E (11183) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:”
The new code is in GitHub.

Hm pretty sure that’s the minimum size when not calling any functions, calling into Serial.printf() will introduce the load on the stack, the question is how big. printf() and friends are known to be heavy, and functions can even have variable stack usage (variable-sized-stack-array…)

Thank you; Serial is the culprit.
what triggered the watchdog timer, repeatedly after exactly 1108 printed lines, in the now updated code?
It only occurred on core 0

I might be wrong, but if Serial in your framework works similarly to Serial in the Arduino framework, writing data to Serial when the buffer is full, blocks until space becomes available when the interrupt handler that sends the data to the USART clears out a few characters.

If this takes too long due to the amount of data, then the watchdog timer will, most likely, expire and you will get a reset. You could, possibly, make the Serial TX and/or RX buffers bigger with a bit of jiggery pokery in the source code – but that’s something I found in the Arduino code as opposed to RTOS etc.

When receiving data, if there’s no room in the RX buffer, then the data that has been received is simply lost without blocking to wait for space. (Again, that’s on the Arduino framework, RTOS may be different.)

Just a thought, I may be wrong.


Thank you. Then why does it only happen on core 0?

Maybe people at ESP-IDF, Arduino-ESP32 or at the ESP32 forum (ESP32 Arduino - ESP32 Forum) have more technical knowledge about this.

Is core 0 the one used by the system?

I’ve got little experience in this microcontroller, so I might just be talking rubbish. I’ve read that one core is used for stuff like Bluetooth or WiFi (if the Board has it of course) and possibly, the RTOS kernel. It needs the watchdog to help prevent this Ultra important, timing wise, functions from being hindered by user code.

HTH (a little)


I suspect you have a point here, thank you.

1 Like

In case you dont alread have it, the ESP32 Getting Started Guide looks very useful.

I’m having a read myself now!