Esp32 reset when I call a procedure, raspberry NOT

Hi, I have a very simple question

I have a stupid question

What happen if i call recursivley a method like that:

// Calls a function x times, this functions allocates 1k in the stack
// then i call the function again

void callProc(int x){
  // I allocate around 1kb as local variables then it should go in the stack 
  size_8t vector[1000];
  Serial.print("I have allocated 1kb in the stack");

  // I repeat the allocation, calling recoursivley callProc(x-1) times
  if (x>=2){
    callProc(x - 1);
    // I just add this code to prevent the code optimization on the allocation of my array
    for (int i=0; i<999;i++){
      vector[i+1] = vector[i];
    }
  } else {
    return;
  } 
}

The code is not well written but it is very simple, I have the right version on my pc but I'm not at home

Well on the esp32 -an az-delivery board- (i should have 500k of ram) it happen that the microcontroller call tha procedure about 5 or 6 times and after it reset. It should not be a memory issue since for 6 times the memory used is around 6K.

I've tried to run it on an raspberry pi pico and it works as I expected.

Do you have any suggestions? How I can solve the problem?

All the issue was born when i tried to compile a library and flash it on a arduino iot 33 nano. It did not worked, then I tried again on the esp32 but it did not worked, then I tried again with an raspberry pi pico and it worked.

The section you posted in is not for your project is when you are having problems installing the IDE on your system.
I have moved it here which is a better place to ask about recursion.

Posting all your code is much more useful than just posting a bit, we can't see the overall structure or try it ourselves.

Thanks a lot for the explanation. I apologize, next time ill'write the question here

The ESP32 uses a version of FreeRTOS and supports multiple tasks/threads. Each task has its own stack, and stacks are actually allocated on the heap. The default stack size for the setup and loop is defined in

I'm not familiar with the specific memory layout for the Pi Pico, but I suspect it has a single stack that can grow much larger, probably until hitting the top of the heap.

Moral of the story: don't allocate large arrays on the stack.

Here is the callRec.ino file. That's the correct code

If you try to execute on your board please let me know


uint8_t callRec1000(int times){
  uint8_t vector[1000];
  if (times>=2){
    Serial.print("Allocated 1kb :");
    Serial.print(times);
    Serial.print("\n");
    callRec1000(times-1);
    for(int i=1; i<1000; i++){
      vector[i-1] = vector[i-1]*vector[i];
    }
  }
  return vector[0];
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.print("delay(5000);\n");
  delay(5000);
  Serial.print("Call callfun() in 2000ms\n");
  delay(2000); 
//  callfun();

  callRec1000(50);
}

void loop() {
  // put your main code here, to run repeatedly:
}

RASPBERRY PI PICO works perfectly but i would like to run it on mu esp32 because the size of the memory is the same.

This is the error of my esp32 board

delay(5000);
Call callfun() in 2000ms
Allocated 1kb :50
Allocated 1kb :49
Allocated 1kb :48
Allocated 1kb :47
Allocated 1kb :46
Allocated 1kb :45
Allocated 1kb :44
Allocat
***ERROR*** A stack overflow in task loopTask has been detected.


Backtrace:0x40082e2d:0x3ffb04600x40087a85:0x3ffb0480 0x4008a609:0x3ffb04a0 0x40089357:0x3ffb0520 0x40087b98:0x3ffb0550 0x40087b48:0x3ffb0014  |<-CORRUPTED




ELF file SHA256: 0000000000000000

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13516
load:0x40080400,len:3604
entry 0x400805f0
[

My arduino nano 33 IOT just say from the serial:

Call callfun() in 2000ms
Allocated 1kb :50
Allocated 1kb :49
Allocated 1kb :48
Allocated 1kb :47
Allocated 1kb :46
Allocated 1kb :45
Allocated 1kb :44
Allocated 1kb :43
Allocated 1kb :42
Allocated 1kb :41
Allocated 1kb :40
Allocated 1kb :39
Allocated 1kb :38
Allocated 1kb :37
Allocated 1kb :36
Allocated 1kb :35
Allocated 1kb :34

That's what i expect because there are limited memory on the NANO IOT

Thanks peter

I think you got the point. An observation that could make me think you are right is because the board works until around 8k and is the same amount of memory consumed during my test.

I need to understand how I can modify this value.

Any suggestion?

Define the getArduinoLoopTaskStackSize() function in your sketch:

size_t getArduinoLoopTaskStackSize() {
    return 16 * 1024; // bytes
}

Why do you need so much stack space, though?

  • Allocate large data structures/arrays on the heap
  • Make sure all (deep) recursive calls are tail-recursive or replace them by loops

I have a library (encryption library) that uses some space to work.

Ive tried to define the function getArduinoLoopTaskStackSize() and something was changed.

I put 16*1024 and the result was more or less the same I had before.

I tried to put 128*1024 and the error was

Allocated 1kb :26
Allocated 1kb :25
Allocated 1kb :24
Allocated 1kb :23
Allocated 1kb :22
Allocated 1kb :21
Guru Meditation Error: Core  1 panic'ed (Unhandled debug exception). 
Debug exception reason: Stack canary watchpoint triggered (loopTask) 
Core  1 register dump:
PC      : 0x400887bf  PS      : 0x00060236  A0      : 0x800d2ff2  A1      : 0x3ffc2660  
A2      : 0x3ffb8eb4  A3      : 0xffffffff  A4      : 0x00060220  A5      : 0x00060223  
A6      : 0x00060223  A7      : 0x00000001  A8      : 0x00000001  A9      : 0x00000004  
A10     : 0x00060223  A11     : 0x3ffc1340  A12     : 0x3ffc1148  A13     : 0x00000000  
A14     : 0x007bee88  A15     : 0x003fffff  SAR     : 0x00000003  EXCCAUSE: 0x00000001  
EXCVADDR: 0x00000000  LBEG    : 0x40085fe1  LEND    : 0x40085ff1  LCOUNT  : 0xfffffffb  


Backtrace:0x400887bc:0x3ffc26600x400d2fef:0x3ffc26a0 0x400d384d:0x3ffc26f0 0x400d1d50:0x3ffc2720 0x400d111d:0x3ffc2740 0x400d1507:0x3ffc2760 0x400d1519:0x3ffc2780 0x400d0f5c:0x3ffc27a0 0x400d0f72:0x3ffc2bb0 0x400d0f72:0x3ffc2fc0 0x400d0f72:0x3ffc33d0 0x400d0f72:0x3ffc37e0 0x400d0f72:0x3ffc3bf0 0x400d0f72:0x3ffc4000 0x400d0f72:0x3ffc4410 0x400d0f72:0x3ffc4820 0x400d0f72:0x3ffc4c30 0x400d0f72:0x3ffc5040 0x400d0f72:0x3ffc5450 0x400d0f72:0x3ffc5860 0x400d0f72:0x3ffc5c70 0x400d0f72:0x3ffc6080 0x400d0f72:0x3ffc6490 0x400d0f72:0x3ffc68a0 0x400d0f72:0x3ffc6cb0 0x400d0f72:0x3ffc70c0 0x400d0f72:0x3ffc74d0 0x400d0f72:0x3ffc78e0 0x400d0f72:0x3ffc7cf0 0x400d0f72:0x3ffc8100 0x400d0f72:0x3ffc8510 0x400d0f72:0x3ffc8920 0x400d0f72:0x3ffc8d30 0x400d0f72:0x3ffc9140 0x400d0f72:0x3ffc9550 0x400d0f72:0x3ffc9960 0x400d0f72:0x3ffc9d70 0x400d0f72:0x3ffca180 0x400d0fe6:0x3ffca590 0x400d18b6:0x3ffca5c0 




ELF file SHA256: 0000000000000000

Rebooting...
ets Jun  8 2016 00:22:57 

Is it possible to configure the esp32 or freeRTOS to support a larger stack.

Do I need to keep FreeRTOS or is it possible drop freeRTOS and use straight the code on the microcontroller?

I've found this document
FreeRTOS - stacks and stack overflow checking

But i don't understand how to modify the values.

Decode the back trace using the ESP Exception Decoder.

Also try to print the high water mark in your function.

What do you want to modify?

Here there is the ESP Exception decoder output

Decoding stack results
0x400887bc: xQueueSemaphoreTake at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/queue.c line 1535
0x400d2fef: uart_tx_all at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/driver/uart.c line 1186
0x400d384d: uart_write_bytes at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/driver/uart.c line 1246
0x400d1d50: uartWriteBuf at C:\Users\giana\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.3\cores\esp32\esp32-hal-uart.c line 310
0x400d111d: HardwareSerial::write(unsigned char const*, unsigned int) at C:\Users\giana\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.3\cores\esp32\HardwareSerial.cpp line 461
0x400d1507: Print::write(char const*) at C:\Users\giana\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.3\cores\esp32/Print.h line 67
0x400d1519: Print::print(char const*) at C:\Users\giana\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.3\cores\esp32\Print.cpp line 89
0x400d0f5c: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 8
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0f72: callRec1000(int) at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 11
0x400d0fe6: setup() at C:\Users\giana\OneDrive\Code\Arduino\callRec\callRec/callRec.ino line 28
0x400d18b6: loopTask(void*) at C:\Users\giana\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.3\cores\esp32\main.cpp line 42

Here you can see the high water mark function
As you can see the stack size become smaller and smaller, as expected.
I don't think is a matter of numbers of call but is a problem of stack size

delay(5000);
Call callfun() in 2000ms
Allocated 1kb: 50 Stack size: 31012
Allocated 1kb: 49 Stack size: 29972
Allocated 1kb: 48 Stack size: 28932
Allocated 1kb: 47 Stack size: 27892
Allocated 1kb: 46 Stack size: 26852
Allocated 1kb: 45 Stack size: 25812
Allocated 1kb: 44 Stack size: 24676
Allocated 1kb: 43 Stack size: 23732
Allocated 1kb: 42 Stack size: 22692
Allocated 1kb: 41 Stack size: 21652
Allocated 1kb: 40 Stack size: 20612
Allocated 1kb: 39 Stack size: 19572
Allocated 1kb: 38 Stack size: 18436
Allocated 1kb: 37 Stack size: 17492
Allocated 1kb: 36 Stack size: 16452
Allocated 1kb: 35 Stack size: 15412
Allocated 1kb: 34 Stack size: 14372
Allocated 1kb: 33 Stack size: 13236
Allocated 1kb: 32 Stack size: 12292
Allocated 1kb: 31 Stack size: 11252
Allocated 1kb: 30 Stack size: 10212
Allocated 1kb: 29 Stack size: 9076
Allocated 1kb: 28 Stack size: 8132
Allocated 1kb: 27 Stack size: 7092
Allocated 1kb: 26 Stack size: 5828
Allocated 1kb: 25 Stack size: 4916
Allocated 1kb: 24 Stack size: 3972
Allocated 1kb: 23 Stack size: 2932
Allocated 1kb: 22 Stack size: 1892
Allocated 1kb: 21 Stack size: 756
Guru Meditation Error: Core  1 panic'ed (Unhandled debug exception). 
Debug exception reason: Stack canary watchpoint triggered (loopTask) 
Core  1 register dump:
PC      : 0x400887bf  PS      : 0x00060236  A0      : 0x800d300e  A1      : 0x3ffc2660  
A2      : 0x3ffb8eb4  A3      : 0xffffffff  A4      : 0x00060220  A5      : 0x00060223  
A6      : 0x00060223  A7      : 0x00000001  A8      : 0x00000001  A9      : 0x00000004  
A10     : 0x00060223  A11     : 0x3ffc1148  A12     : 0x3ffc1340  A13     : 0x00000000  
A14     : 0x007bee88  A15     : 0x003fffff  SAR     : 0x00000003  EXCCAUSE: 0x00000001  
EXCVADDR: 0x00000000  LBEG    : 0x40085fe1  LEND    : 0x40085ff1  LCOUNT  : 0xfffffffb  


Backtrace:0x400887bc:0x3ffc26600x400d300b:0x3ffc26a0 0x400d3869:0x3ffc26f0 0x400d1d6c:0x3ffc2720 0x400d1139:0x3ffc2740 0x400d1523:0x3ffc2760 0x400d1535:0x3ffc2780 0x400d0f60:0x3ffc27a0 0x400d0f8e:0x3ffc2bb0 0x400d0f8e:0x3ffc2fc0 0x400d0f8e:0x3ffc33d0 0x400d0f8e:0x3ffc37e0 0x400d0f8e:0x3ffc3bf0 0x400d0f8e:0x3ffc4000 0x400d0f8e:0x3ffc4410 0x400d0f8e:0x3ffc4820 0x400d0f8e:0x3ffc4c30 0x400d0f8e:0x3ffc5040 0x400d0f8e:0x3ffc5450 0x400d0f8e:0x3ffc5860 0x400d0f8e:0x3ffc5c70 0x400d0f8e:0x3ffc6080 0x400d0f8e:0x3ffc6490 0x400d0f8e:0x3ffc68a0 0x400d0f8e:0x3ffc6cb0 0x400d0f8e:0x3ffc70c0 0x400d0f8e:0x3ffc74d0 0x400d0f8e:0x3ffc78e0 0x400d0f8e:0x3ffc7cf0 0x400d0f8e:0x3ffc8100 0x400d0f8e:0x3ffc8510 0x400d0f8e:0x3ffc8920 0x400d0f8e:0x3ffc8d30 0x400d0f8e:0x3ffc9140 0x400d0f8e:0x3ffc9550 0x400d0f8e:0x3ffc9960 0x400d0f8e:0x3ffc9d70 0x400d0f8e:0x3ffca180 0x400d1002:0x3ffca590 0x400d18d2:0x3ffca5c0 




ELF file SHA256: 0000000000000000

Rebooting...

But the error in the application I want run is different
Is the same that I have here if i allocate 10000 bytes per call instead of 1000bytes per call


rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13516
load:0x40080400,len:3604
entry 0x400805f0
delay(5000);
Call callfun() in 2000ms
Allocated 1kb: 50 Stack size: 22004
Allocated 1kb: 49 Stack size: 11956
Allocated 1kb: 48 Stack size: 1908
Allocated 1kb: 47 Stack size: 1908
Allocated 1kb: ets Jun  8 2016 00:22:57

I think really is a problem of stack size. There is any possibility to increase the stack size for a single task in freeRTOS?

It seems to me you were already given the correct solution:

Why not just set the task's stack size when it's created?

I have a library and i need to modify the library making malloc() and (unfortunatley) free() when i return()

It's a great idea modify the stack prior to the creation of the task. I think i should increase the ARDUINO task.

I've seen the link but where i can put the call to the function? If i call them in the start(){} i'm allredy in the task then i cannot use the functions? Or i can and modify the task's stack?

Thanks

Hi, I’ve tried the function that you have told me. In particular i’ve tried this code:

void newloop(void* param) {
  while(1) {
    delay(10000);
    Serial.printf("memtask: %d\n", uxTaskGetStackHighWaterMark(NULL));
  }
}

void setup() {
  Serial.begin(115200);
  xTaskCreateUniversal(newloop,"newloop", 64*1024, NULL, 1, NULL, ARDUINO_RUNNING_CORE);
  vTaskDelete(NULL);
}
void loop() {}

The output is 64200, that is correct. But i need MORE than 64k of stack. I need around 350k,

Do you know why when i use the xTaskCreateUniversal(newloop,“newloop”, x*1024, NULL, 1, NULL, ARDUINO_RUNNING_CORE); with x>64 the output is <64k?

Many thanks

Yes i've tried to change the last parameter both to change the size to 300000 the board do not respond

Because configSTACK_DEPTH_TYPE is uint16_t:

In other words, the maximum stack size is 64KiB-1byte = 65535 bytes.

You should never use malloc in C++. And if you need dynamic allocation, you should probably be using containers or smart pointers like std::unique_ptr so you never have to worry about manually deallocating them.

i don't want introduce errors in my library.

The library you're using should include a comprehensive testing suite so you can be confident that it still works after changes like this.

The line you quoted doesn't mean anything in isolation, AFAIK, it is only meaningful for Load/StoreProhibited exceptions.

The error here is the stack canary being triggered.

Please read the posts earlier in the thread before cluttering it with unrelated code snippets, OP is already logging uxTaskGetStackHighWaterMark.

I've modified the configSTACK_DEPTH_TYPE to uint32_t in the FreeRTOS.h

I've tried definiton as adviced but the microcontroller does not respond in this case

xTaskCreateUniversal(newloop,"newloop", X*1024, NULL, 1, NULL, ARDUINO_RUNNING_CORE);

where X>150.

I need 300k of memory not only 150

Seems strange for me that anyone hadn't seen this kind of error

You cannot do this without recompiling the entire ESP-IDF core.

Most likely because hundreds of kilobytes of stack memory are highly unusual in embedded systems.

@gchini, it looks like the path you stubbornly keep trying to go down does not and will not work. It seems to me your 2 best choices are:

  1. Dynamically allocate the required storage, preferably using a memory leak-safe technique as suggested by @PieterP.

  2. Spin up a new task with the required stack space as I suggested in one of your other numerous threads on this topic.

A variation on #1 would be to use psram. But, it looks like the API for that is of the 'C' malloc() flavor. So be really careful about memory leaks.