乐鑫技术交流
直播中

京五环以外

10年用户 3209经验值
擅长:EMC/EMI设计
私信 关注
[问答]

inline关键字被优化导致此类函数被布局在flash内,怎么处理?

在编写同时使用uart和ota的程序中,发现进入串口中断后导致panic,提示如下:
Guru Meditation Error: Core  0 panic'ed (Cache disabled but cached memory region accessed).

Core  0 register dump:
PC      : 0x4010b324  PS      : 0x00060034  A0      : 0x40082611  A1      : 0x3ffb0660  
A2      : 0x3ffc6904  A3      : 0x3ffb18a8  A4      : 0x3ffb18a4  A5      : 0x00000001  
A6      : 0x00000001  A7      : 0x00004000  A8      : 0x80085b19  A9      : 0x00000008  
A10     : 0x3ff50000  A11     : 0x00000000  A12     : 0x00000000  A13     : 0x3ffb0650  
A14     : 0x3ffb2358  A15     : 0x00000008  SAR     : 0x00000020  EXCCAUSE: 0x00000007  
EXCVADDR: 0x00000000  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff  

Backtrace:0x4010b321:0x3ffb0660 0x4008260e:0x3ffb06c0 0x0004001e:0x00000000 |<-CORRUPTED
经过一顿凶猛的排错分析,是因为uart的中断函数uart_rx_intr_handler_default内调用uart_hal_is_tx_idle宏导致的。
uart_hal_is_tx_idle宏是uart_ll_is_tx_idle的别名,而uart_ll_is_tx_idle定义如下:Code: 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));}
由于uart.c多处调用这个函数,所以编译器自作聪明地把它编译成了非内联函数(意图是减少代码占用?),且elf能找到uart_ll_is_tx_idle标号。uart_ll_is_tx_idle函数被安排在默认的flash地址,最终导致了运行时panic。
我的临时解决方法是,在uart.c文件里加入如下声明:Code: Select all
static inline bool uart_ll_is_tx_idle(uart_dev_t *hw) __attribute((always_inline));
如此以来uart_ll_is_tx_idle不会被编译为非内联函数,经测试问题解决。
但是,希望乐鑫官方把idf内源码中的inline关键词都替换为__attribute((always_inline)),因为inline关键字不可靠!
期待下次idf版本更新能解决此bug,自己修改idf源码真的是权宜之计、临时之策。                                                                                                                                                                                                                    
                                                                                                                        
                                                                                                                        

回帖(1)

王飞云

2024-6-22 15:24:26
在这种情况下,我们需要采取以下步骤来解决问题:

1. **检查代码中的inline函数**:首先,检查您的代码中是否有使用`inline`关键字的函数。这些函数可能会被编译器优化,导致它们被放置在Flash存储器中。如果这些函数在中断服务例程(ISR)中被调用,可能会导致访问未被缓存的内存区域。

2. **将inline函数移动到RAM中**:如果发现有inline函数在ISR中被调用,您可以尝试将这些函数的实现从Flash移动到RAM中。这可以通过使用` IRAM_ATTR`宏来实现,例如:

   ```c
   __attribute__((section(".iram1"))) void inline_function() {
       // 函数实现
   }
   ```

   这将确保该函数的代码被放置在RAM中,而不是Flash。

3. **检查中断服务例程中的其他问题**:除了检查inline函数外,还需要检查ISR中的其他潜在问题。例如,确保在ISR中没有使用可能导致堆栈溢出的大型数据结构,或者确保ISR中的代码没有执行时间过长。

4. **优化代码结构**:如果可能的话,尝试优化代码结构,以减少在ISR中执行的代码量。这可以通过将一些操作移出ISR,或者使用任务调度器来实现。

5. **使用调试工具**:如果问题仍然存在,您可以使用调试工具(如ESP-IDF的gdb)来进一步分析问题。这可以帮助您找到导致错误的具体代码行。

6. **更新固件和工具链**:确保您使用的ESP-IDF和工具链是最新版本的,因为新版本可能修复了一些已知的问题。


举报

更多回帖

发帖
×
20
完善资料,
赚取积分