完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
芯片:ESP32-D0WDQ6
IDF版本:v4.2.1 开发环境:tools for windows,cmake。 这几天在写一个项目,同时用到uart和ota功能。当uart发送数据时,同时进行ota升级,就会产生panic。 经过长时间的追踪和分析,已经确认了bug原因,并采取了临时补救措施。 下面是错误分析过程: espesp-idfcomponentsdriveruart.c这个文件里有uart_rx_intr_handler_default函数,它是布局在IRAM里的代码,这是为了在cache禁用期间能处理uart中断请求。 它有一个分支,执行了uart_hal_is_tx_idle宏(其实这个宏是uart_ll_is_tx_idle的别名),请看下面: espesp-idfcomponentssocincludehaluart_hal.hCode: Select all #define uart_hal_is_tx_idle(hal) uart_ll_is_tx_idle((hal)->dev) 而uart_ll_is_tx_idle定义在如下文件: espesp-idfcomponentssocsrcesp32includehaluart_ll.hCode: Select all static inline bool uart_ll_is_tx_idle(uart_dev_t *hw){ typeof(hw->status) status = hw->status; return ((status.txfifo_cnt == 0) && (status.st_utx_out == 0));} 它是一个inline函数。我们都认为inline关键字,会告诉编译器内联此函数,于是它的代码会被展开到调用方函数体内, 比如uart_rx_intr_handler_default函数在IRAM内,那么uart_ll_is_tx_idle的逻辑也就在IRAM里,事实上这是理想状态而已。 就是这个假设引起了bug! 我观察的现象为:uart.c里有三处代码调用了uart_ll_is_tx_idle内联函数,但是在编译器配置为-Os的情况下,它自作聪明地把uart_ll_is_tx_idle函数编译成非内联函数!估计3处调用,编译为非内联可以节省空间吧?于是uart_ll_is_tx_idle函数实体就被默认安排在flash地址空间了,不再是安全的IRAM里!这就导致uart中断里执行了flash代码,而同时ota禁用cache的话就发生panic了。 bug复现方式就是把sdkconfig文件里优化配置为CONFIG_COMPILER_OPTIMIZATION_SIZE=y,然后观察uart_ll_is_tx_idle是否内联;在readelf -s导出的标号里,也能看到uart_ll_is_tx_idle,并且是在flash地址段。 我的临时解决方法是:在uart.c文件里加一行声明,强制uart_ll_is_tx_idle内联(它比关键字inline靠谱!)Code: Select all static inline bool uart_ll_is_tx_idle(uart_dev_t *hw) __attribute((always_inline)); 或者把CONFIG_COMPILER_OPTIMIZATION_SIZE取消,设置为CONFIG_COMPILER_OPTIMIZATION_PERF=y也行。 但是通过改编译优化等级来解决问题并不科学,这说明代码经不起优化,而且指不定引入其它隐秘的bug呢? |
|
相关推荐
1个回答
|
|
1. **更新ESP-IDF版本**:首先,建议您尝试更新ESP-IDF到最新版本(例如v4.4或更高版本),因为新版本可能已经修复了这个问题。您可以访问ESP-IDF的GitHub仓库(https://github.com/espressif/esp-idf)以获取最新版本。
2. **禁用优化**:如果更新ESP-IDF版本后问题仍然存在,您可以尝试在编译时禁用优化。在CMakeLists.txt文件中,添加以下行: ``` set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") ``` 这将禁用编译器优化,可能会解决panic问题。 3. **修改uart.c文件**:如果问题仍然存在,您可以尝试修改`espesp-idfcomponentsdriveruart.c`文件中的`uart_rx_intr_handler_default`函数。在执行`uart_hal_is_tx_idle`宏之前,添加以下代码: ``` portENTER_CRITICAL_ISR(&spinlock); // 执行uart_hal_is_tx_idle宏 portEXIT_CRITICAL_ISR(&spinlock); ``` 这样可以确保在执行宏时,中断被临时禁用,从而避免panic。 4. **报告问题**:如果您认为这是一个编译器优化bug,建议您在ESP-IDF的GitHub仓库(https://github.com/espressif/esp-idf/issues)上报告这个问题。提供详细的错误分析过程和您的开发环境信息,以便开发者能够更好地了解问题并提供解决方案。 |
|
|
|
只有小组成员才能发言,加入小组>>
142 浏览 1 评论
545浏览 6评论
457浏览 5评论
有没有办法在不使用混杂模式的情况下实现Wifi驱动程序接收缓冲区访问中断呢?
438浏览 5评论
441浏览 4评论
411浏览 4评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 16:34 , Processed in 0.850372 second(s), Total 78, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号