CmBacktrace 相當于重寫了hard_fault函數,在hard_fault函數里面去分析SCB寄存器的信息和堆棧信息,然后把這些信息打印出來(或者寫到flash);通過使用串口輸出產生hard_fault的堆棧信息,然后利用addr2line工具反推出具體的代碼執行函數,快速定位hard_fault問題;
1:CmBacktrace獲取
看兩個git的更新記錄,github應該是比較新的;作者都是同一個人
github地址
https://github.com/armink/CmBacktrace
gitee地址
https://gitee.com/Armink/CmBacktrace
使用說明介紹這個博主講的挺詳細的
https://blog.csdn.net/weiqifa0/article/details/120499893
然后大家自行搜索一下 addr2line 工具的說明即可
2:CmBackTrace代碼修改適配
cmb_cfg.h 修改
#ifndef _CMB_CFG_H_
#define _CMB_CFG_H_
#include "mocar_log.h"#ifdef CMB_USER_CFG
#include "cmb_user_cfg.h"
#else
/* print line, must config by user */
#define cmb_println(...) log_print(SLOG_INFO, __VA_ARGS__); /* e.g., printf(__VA_ARGS__);printf("\r\n") or SEGGER_RTT_printf(0, __VA_ARGS__);SEGGER_RTT_WriteString(0, "\r\n") */
/* enable bare metal(no OS) platform */
/* #define CMB_USING_BARE_METAL_PLATFORM */
/* enable OS platform */
#define CMB_USING_OS_PLATFORM
/* OS platform type, must config when CMB_USING_OS_PLATFORM is enable */
#define CMB_OS_PLATFORM_TYPE CMB_OS_PLATFORM_FREERTOS /* CMB_OS_PLATFORM_RTT or CMB_OS_PLATFORM_UCOSII or CMB_OS_PLATFORM_UCOSIII or CMB_OS_PLATFORM_FREERTOS or CMB_OS_PLATFORM_RTX5 or CMB_OS_PLATFORM_THREADX */
/* cpu platform type, must config by user */
#define CMB_CPU_PLATFORM_TYPE CMB_CPU_ARM_CORTEX_M7 /* CMB_CPU_ARM_CORTEX_M0 or CMB_CPU_ARM_CORTEX_M3 or CMB_CPU_ARM_CORTEX_M4 or CMB_CPU_ARM_CORTEX_M7 or CMB_CPU_ARM_CORTEX_M33 */
/* enable dump stack information */
#define CMB_USING_DUMP_STACK_INFO
/* language of print information */
#define CMB_PRINT_LANGUAGE CMB_PRINT_LANGUAGE_ENGLISH /* CMB_PRINT_LANGUAGE_ENGLISH(default) or CMB_PRINT_LANGUAGE_CHINESE or CMB_PRINT_LANGUAGE_CHINESE_UTF8 */
#endif#endif /* _CMB_CFG_H_ */
cmb_def.h 修改
S32DS默認使用gcc編譯器;
注意這里要結合.ld文件去里面的 SECTIONS{…}適配, 不同的.ld文件名稱可能不一致;
......
#elif defined(__GNUC__)/* C stack block start address, defined on linker script file, default is _sstack */#ifndef CMB_CSTACK_BLOCK_START#define CMB_CSTACK_BLOCK_START __Stack_dtcm_start#endif/* C stack block end address, defined on linker script file, default is _estack */#ifndef CMB_CSTACK_BLOCK_END#define CMB_CSTACK_BLOCK_END __Stack_dtcm_end#endif/* code section start address, defined on linker script file, default is _stext */#ifndef CMB_CODE_SECTION_START#define CMB_CODE_SECTION_START __text_start#endif/* code section end address, defined on linker script file, default is _etext */#ifndef CMB_CODE_SECTION_END#define CMB_CODE_SECTION_END __text_end#endif
#else#error "not supported compiler"
#endif
task.c修改
......
/*適配CmBacktrace插件*/
uint32_t *vTaskStackAddr(void)
{return (uint32_t)pxCurrentTCB->pxStack;
}uint32_t vTaskStackSize(void)
{return (uint32_t)pxCurrentTCB - (uint32_t)pxCurrentTCB->pxStack - 4;
}char * vTaskName()
{return pxCurrentTCB->pcTaskName;
}
在現場里面自己寫了個觸發hard_fault的代碼;參考例程里面的代碼,測試不會產生 HardFault_Handler
/*cm_backtrace 臨時測試產生hardfault的函數 */
#include "C40_Ip.h"
static void tmp_test_create_hardfault(void)
{C40_Ip_StatusType c40_erase_status=C40_IP_STATUS_ERROR;if (C40_IP_STATUS_SECTOR_PROTECTED == C40_Ip_GetLock(C40_CODE_ARRAY_0_BLOCK_0_S000)){C40_Ip_ClearLock(C40_CODE_ARRAY_0_BLOCK_0_S000, 0);}c40_erase_status = C40_Ip_MainInterfaceSectorErase(C40_CODE_ARRAY_0_BLOCK_0_S000, 0);if (c40_erase_status == C40_IP_STATUS_SUCCESS){ // 擦除之后必須調用該接口,不然會報 EHV 錯誤; 很容易就busy了...c40_erase_status = C40_Ip_MainInterfaceSectorEraseStatus();}
}
S32DS代碼里面的 exceptions.c里面定義的是弱函數,重寫之后自動覆蓋了; 擔心沒有覆蓋的話可以屏蔽掉
//void HardFault_Handler(void) __attribute__ ((weak)); /* Hard Fault Handler */
......
//void HardFault_Handler(void)
//{
// while(TRUE){};
//}
其它的再沒修改什么通用的代碼了,根據自己的工程初始化"cm_backtrace_init"之后,調用 "tmp_test_create_hardfault"函數即可
3:實測驗證
代碼燒寫運行之后串口日志如下
Bus fault is caused by … 這里的故障原因就是分析 SCB寄存器的出來的
1969.12.31-23:59:59]info cm_backtrace_fault lr=0xfffffffd sp=0x2000ffe0
[1969.12.31-23:59:59]info Firmware name: FreeRTOS_S32K328, hardware version: hv_v1.0.0, software version: sv_v1.0.1
[1969.12.31-23:59:59]info Fault on thread TaskManager
[1969.12.31-23:59:59]info ===== Thread stack information =====
[1969.12.31-23:59:59]info stack_info pointer=0x20400ff8 addr=0x20400458 size=12272
[1969.12.31-23:59:59]info addr: 20400ff8 data: 00000000
[1969.12.31-23:59:59]info addr: 20400ffc data: 00000000
[1969.12.31-23:59:59]info addr: 20401000 data: 20401008
[1969.12.31-23:59:59]info addr: 20401004 data: 0041ebf1
[1969.12.31-23:59:59]info addr: 20401008 data: 00a5a5a5
[1969.12.31-23:59:59]info addr: 2040100c data: 00000010
[1969.12.31-23:59:59]info addr: 20401010 data: 00400000
[1969.12.31-23:59:59]info addr: 20401014 data: 00000000
[1969.12.31-23:59:59]info addr: 20401018 data: 20401020
[1969.12.31-23:59:59]info addr: 2040101c data: 004110e1
[1969.12.31-23:59:59]info addr: 20401020 data: 20400398
[1969.12.31-23:59:59]info addr: 20401024 data: 00000002
[1969.12.31-23:59:59]info addr: 20401028 data: 20401030
[1969.12.31-23:59:59]info addr: 2040102c data: 00411141
[1969.12.31-23:59:59]info addr: 20401030 data: 00000000
[1969.12.31-23:59:59]info addr: 20401034 data: 00000000
[1969.12.31-23:59:59]info ====================================
[1969.12.31-23:59:59]info =================== Registers information ====================
[1969.12.31-23:59:59]info R0 : 00000000 R1 : 00000000 R2 : 402ec000 R3 : 00000000
[1969.12.31-23:59:59]info R12: 0000000a LR : 004407d3 PC : 004407d6 PSR: 61000000
[1969.12.31-23:59:59]info ==============================================================
[1969.12.31-23:59:59]info Bus fault is caused by instruction access violation
[1969.12.31-23:59:59]info Bus fault is caused by precise data access violation
[1969.12.31-23:59:59]info The bus fault occurred address is 00440810
[1969.12.31-23:59:59]info Show more call stack info by run: addr2line -e FreeRTOS_S32K328.elf -afpiC 004407d6 004407d2 0041ebf0 004110e0 00411140 004066f4 0040936e
addr2line執行如下;我使用相對路徑執行的,沒有添加環境變量
PS D:\2_gitlab\S32K328\s32k328\FreeRTOS_S32K328\FreeRTOS_S32K328\src\mid\cm_backtrace\exe> .\addr2line.exe -e ..\..\..\..\Debug_FLASH\FreeRTOS_S32K328.elf -afpiC 004407d6 004407d2 0041ebf0 004110e0 00411140 004066f4 0040936e
0x004407d6: SchM_Exit_Mem_43_INFLS_MEM_EXCLUSIVE_AREA_10 at D:\2_gitlab\S32K328\s32k328\FreeRTOS_S32K328\FreeRTOS_S32K328\Debug_FLASH/../RTD/src/SchM_Mem_43_INFLS.c:797
0x004407d2: SchM_Exit_Mem_43_INFLS_MEM_EXCLUSIVE_AREA_10 at D:\2_gitlab\S32K328\s32k328\FreeRTOS_S32K328\FreeRTOS_S32K328\Debug_FLASH/../RTD/src/SchM_Mem_43_INFLS.c:795
0x0041ebf0: C40_Ip_MainInterfaceSectorErase at D:\2_gitlab\S32K328\s32k328\FreeRTOS_S32K328\FreeRTOS_S32K328\Debug_FLASH/../RTD/src/C40_Ip.c:2569
0x004110e0: tmp_test_create_hardfault at D:\2_gitlab\S32K328\s32k328\FreeRTOS_S32K328\FreeRTOS_S32K328\Debug_FLASH/../src/task/manager/manager.c:243
0x00411140: task_manage_thread at D:\2_gitlab\S32K328\s32k328\FreeRTOS_S32K328\FreeRTOS_S32K328\Debug_FLASH/../src/task/manager/manager.c:270
0x004066f4: xTaskResumeAll at D:\2_gitlab\S32K328\s32k328\FreeRTOS_S32K328\FreeRTOS_S32K328\Debug_FLASH/../FreeRTOS/Source/tasks.c:4102
0x0040936e: prvTimerTask at D:\2_gitlab\S32K328\s32k328\FreeRTOS_S32K328\FreeRTOS_S32K328\Debug_FLASH/../FreeRTOS/Source/timers.c:777 (discriminator 1)
最后附一張截圖