Esphome
Contents
ESPHOME自定义组件崩溃调试方法
LD2460组件过程中遇到运行的崩溃问题,记录调试方法
- 看日志
| |
setup方法中的LOG根本没有,说明在初始化之前就出现了崩溃。 看到消息日志的存储信息,根据PC/MEPC和RA指针定位崩溃位置,参考这里 和这里
esphome下载ELF文件,这个有用。
使用riscv32-esp-elf-objdump -S xxx.elf > a.txt进行反汇编,得到反汇编文件,之后有用。
使用riscv32-esp-elf-addr2line -pfiaC -e path.elf 0x4200a47a 0x4200a4f6,查询PC指针和RA指针是什么,得到崩溃位置的函数,
| |
汇编文件中
| |
是send_command方法中崩溃的,而它是enable_upload调用的。查询哪调用了enable_upload,在yaml文件和全部代码中分析,只能是EnableUploadSwitch调用的。
查看A0,A1等寄存器,MTVAL接近0,可能是读取了一个NULL附近的地址。
比如把nullptr当对象访问了他的成员,此时A0是0,即 this指针是nullptr ,A1是6,
符合enable_upload调用send_command的command参数的值,A3是1,符合data_size参数的值,所以定位崩溃函数enable_upload。
| |
最终原因是对nullptr调用了他的enable_upload方法,导致了崩溃。为什么this指针是nullptr?
| |
| |
看py的codegen文件,原来这个Switch实例是先构造(switch.new_switch),再赋值this->parent_ = parent;,
构造的时候this->parent_为nullptr,但是这时候就开始调用它的方法了(turn_on会调用write_state,后面涉及到对parent_的调用),
这显然是造成崩溃的罪魁祸首。
因此,不要在Switch、Button、Select类的构造方法中调用parent的方法,弄个成员列表初始化即可。
当然你硬要在构造方法调用parent的方法也行,new_xxx的时候parent就应该作为构造方法的参数传入。
这样后面就不需要register_parented了,构造方法中就可以拿到parent对象。
这两种方法都可以,看esphome官方这两种方法都有。
另外idf5.4似乎还整了个活,如果在完全初始化之前调用uart、i2c、spi的write之类的方法。 多半会得到一个freertos底层的新信错误,这个没法修,只能进一步推迟执行时间到loop方法开始执行的时候,这可以用一个队列实现。
2025.12.7更新
官方的好东西,直接查看调用栈
Author
LastMod 2026-04-20