LoadProhibited, StoreProhibited
当应⽤程序尝试读取或写⼊⽆效的内存位置时,会发⽣此类 CPU 异常。此类⽆效内存地址可以在寄存器转储的EXCVADDR 中到。如果该地址为零,通常意味着应⽤程序正尝试解引⽤⼀个 NULL指针。如果该地址接近于零,则通常意味着应⽤程序尝试访问某个结构体的成员,但是该结构体的指针为 NULL。如果该地址是其它⾮法值(不在 0x3fxxxxxx - 0x6xxxxxxx 的范围内),则可能意味着⽤于访问数据的指针未初始化或者已经损坏。
IntegerDivideByZero
应⽤程序尝试将整数除以零。
LoadStoreAlignment
应⽤程序尝试读取/写⼊的内存位置不符合加载/存储指令对字节对齐⼤⼩的要求,例如,32 位加载指令只能访问 4 字节对齐的内存地址,⽽ 16 位加载指令只能访问 2 字节对齐的内存地址。
LoadStoreError
应⽤程序尝试从仅⽀持 32 位加载/存储的内存区域执⾏ 8 位或 16 位加载/存储操作,例如,解引⽤⼀个指向指令内存区域的 char* 指针就会导致这样的错误。
Unhandled debug exception
这后⾯通常会再跟⼀条消息:
Debug exception reason: Stack canary watchpoint triggered (task_name)
此错误表⽰应⽤程序写⼊的位置越过了 task_name 任务堆栈的末尾,请注意,并⾮每次堆栈溢出都会触发此错误。任务有可能会绕过堆栈⾦丝雀(stack canary)的位置访问堆栈,在这种情况下,监视点就不会被触发。
Interrupt wdt timeout on CPU0 / CPU1
这表⽰发⽣了中断看门狗超时.
Cache disabled but cached memory region accessed
@ 此问题很多⼈遇到过,特别在这总结⼀下, 该部分内容感谢不⽅便透露姓名的张同学提供帮助
该问题原因在于:在 cache 被禁⽤期间(例如在使⽤ spi_flash API 读取/写⼊/擦除/映射 SPI Flash 的时候),发⽣了 IRAM-Safe 中断并且中断程序访问了 flash 的资源。通常发⽣在中断处理程序调⽤了
在 flash 中的程序,引⽤了 flash 中的常量。值得注意的是,当在中断处理程序⾥使⽤ double 型变量时,由于 double 型变量操作的实现是软件实现的,所以该实现部分也被存放在了 flash 中(例如强制类型转换操作)。
解决办法就是:
1. 给在中断中访问的函数加上IRAM_ATTR修饰符
2. 给在中断中访问的常量加 DRAM_ATTR 修饰符
3. 不在中断处理程序中使⽤ double 类型操作
需要注意的是:
1.该异常只发⽣在 IRAM-Safe 中断,即使⽤ ESP_INTR_FLAG_IRAM注册的中断处理程序。
2.该异常只有在 cache 被禁期间会出现,所以当 cache 未被禁⽤期间不会出现,换句话说该异常具有随机性。
3.编译器可能会将⼀些不会被改变的变量放⼊ .rodata 段中,哪怕程序员没有加 const 修饰符。对于 ESP32 的应⽤程序来
说,.rodata 意味着该部分位于 flash 中。对于字符串变量,这种情况很容易被察觉,但是对于某些常量,就不是那么好察觉了。例如下⾯的情况
static timg_dev_t *TG[2]={&TIMERG0,&TIMERG1};
这⾥定义了指针数组 TG,该数组元素是两个硬件定时器0,1的寄存器⾸地址,该指针数组的元素不会被改变,所以会被编译器放⼊ .rodata 中。此时在定时器中断⾥操作了 TG,⼜恰好这个中断发⽣在 cache 被禁期间,那么 CPU 就会抛出该异常。
出现该问题的调试技巧
1. CPU 抛出该类型异常时,通常异常位置就是出错位置,需要细看
Guru Meditation Error: Core  1 panic'ed (Cache disabled but cached memory region accessed)
Core 1 register dump:
PC      : 0x4011b808  PS      : 0x00060034  A0      : 0x8008c664  A1      : 0x3ffbeca0
0x4011b808: __fixunsdfdi at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libgcc/config/xtensa/ieee754-df.S:2041
A2      : 0x0099fd28  A3      : 0x00000000  A4      : 0x3ffbf6a0  A5      : 0x3f7909f1
A6      : 0x00000000  A7      : 0x00013ffc  A8      : 0x80086136  A9      : 0x3ffbec80
A10    : 0xfffffffc  A11    : 0x40ddd57f  A12    : 0x000007fe  A13    : 0x00000000
A14    : 0x65580000  A15    : 0x00000000  SAR    : 0x00000014  EXCCAUSE: 0x00000007
EXCVADDR: 0x00000000  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0x00000000
Core 1 was running in ISR context:
EPC1    : 0x40086914  EPC2    : 0x00000000  EPC3    : 0x00000000  EPC4    : 0x4011b808
0x40086914: spi_flash_enable_interrupts_caches_and_other_cpu at /home/chenzhengwei/esp/esp-idf/components/spi_flash/cache_utils.c:147
0x4011b808: __fixunsdfdi at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libgcc/config/xtensa/ieee754-df.S:2041
Backtrace: 0x4011b808:0x3ffbeca0 0x4008c661:0x3ffbecd0 0x4008c69d:0x3ffbecf0 0x400857e5:0x
timeout on t2 timer
3ffbed10 0x40086911:0x3ffd0970 0x40086cc9:0x3ffd0 990 0x40117789:0x3ffd09e0 0x4011785e:0x3ffd0a10 0x401179ea:0x3ffd0a30 0x40116c51:0x3ffd0aa0 0x40117109:0x3ffd0b20 0x40116729:0x3ffd0b90 0x40105c36:0x3ffd0bd0 0x401057d7:0x3ffd0c10 0x401058ce:0x3ffd0c40 0x4008dfb5:0x3ffd0c90
0x4011b808: __fixunsdfdi at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libgcc/config/xtensa/ieee754-df.S:2041
0x4008c661: gpio_isr_loop at /home/chenzhengwei/esp/esp-idf/components/driver/gpio.c:433
0x4008c69d: gpio_intr_service at /home/chenzhengwei/esp/esp-idf/components/driver/gpio.c:433
0x400857e5: _xt_lowint1 at /home/chenzhengwei/esp/esp-idf/components/freertos/xtensa_vectors.S:1154
0x40086911: spi_flash_enable_interrupts_caches_and_other_cpu at /home/chenzhengwei/esp/esp-idf/components/spi_flash/cache_utils.c:147
...
在这个例⼦中,发⽣异常的位置在 0x4011b808, 这⾥是__fixunssfdi 函数的存放位置,且该位置位于⽚外存储器(见
esp32_technical_reference_manual 的 1.3.3 节),这个函数是⽤来对浮点数转 64 位⽆符号整数的操作,意味着中断处理程序⾥使⽤了double 型数据的强制类型转换操作。这在 cache 被关闭时操作是不被允许的。
2. 如果不知道变量是在 .data/.bss 段还是 .rodata 段,那么可以使⽤ readelf 命令查看 .elf 中的符号详细信息
# 将 build/empty-project.elf 中的符号表覆盖写到 empty-project.out ⽂件中
readelf -a build/empty-project.elf > empty-project.out
使⽤ readelf 命令提取 elf ⽂件中的符号表,如何查看符号表可参考 C语⾔变量的存储布局,通过符号表,可以准确的看到每⼀个变量、函数的存储位置,⼤⼩等信息。有了这些信息,就可以检查 IRAM-Safe 中断处理程序⾥使⽤变量和函数是否在 flash 中。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。