为什么会出现调试异常原因:堆栈金丝雀观察点已触发(主要)?

Why do I get the Debug exception reason: Stack canary watchpoint triggered (main)?

我正在使用 esp-idf-v3.0esp32-wroom-32 编写程序。
我正在尝试添加日志,这些日志将保存在 fatfs.
在一些日志之后我得到:

21:54:21.306 -> Debug exception reason: Stack canary watchpoint triggered (main) 
21:54:21.306 -> Register dump:
21:54:21.306 -> PC      : 0x40089827  PS      : 0x00060b36  A0      : 0x40082179  A1      : 0x3ffd3860  
21:54:21.340 -> A2      : 0x3ff40000  A3      : 0x00000033  A4      : 0x00000033  A5      : 0x00000000  
21:54:21.340 -> A6      : 0x00000024  A7      : 0xff000000  A8      : 0xe37fc000  A9      : 0x0000007e  
21:54:21.340 -> A10     : 0x00000000  A11     : 0xffffffff  A12     : 0x00000004  A13     : 0x00000001  
21:54:21.340 -> A14     : 0x00000005  A15     : 0x00000000  SAR     : 0x00000004  EXCCAUSE: 0x00000001  
21:54:21.340 -> EXCVADDR: 0x00000000  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xfffffff6  

为什么会发生在 main 上?

FreeRTOS 任务堆栈深度

这很可能是由您的 FreeRTOS 任务中的堆栈溢出引起的。

增加堆栈深度

我要做的第一件事是 增加 FreeRTOS 任务的堆栈深度。例如,如果您创建的任务的堆栈大小为 configMINIMAL_STACK_SIZE,这可能低至 768 字节 - 这不足以满足许多常见要求。

堆栈深度增加多少?

回答这个问题并不容易,但是 - 在这种情况下 - 简单地增加它可能就足够了,直到你不再有堆栈溢出。如果您担心不会不必要地浪费内存,FreeRTOS includes a mechanism 可以让您知道任务即将溢出其堆栈的程度。

缓冲区和金丝雀

A canary 只是缓冲区末尾的标记 - 会定期检查。如果它从默认值更改,则意味着程序已尝试写入超出缓冲区的末尾 - 即存在缓冲区 溢出.

通过更改配置中的两个选项(在 Component Config -> FreeRTOS 部分下),在 ESP IDF 中启用使用金丝雀检测堆栈溢出:

  • 'Check for stack overflow' -> 'using canary bytes'
  • 'Set a debug watchpoint as a stack overflow check' -> 启用

如果您禁用第二个选项,您将收到 Guru Meditation 错误 - LoadProhibited 异常 - 在堆栈溢出的情况下。

xTaskCreate() 和堆栈深度

请记住,ESP IDF 中 xTaskCreate() 的版本与原始 FreeRTOS 中的不同。在原始的 FreeRTOS 中,堆栈深度为 specified in words. In the ESP IDF, it's specified in bytes非常 重要的区别!