CmBacktrace 相当于重写了hard_fault函数,在hard_fault函数里面去分析SCB寄存器的信息和堆栈信息,然后把这些信息打印出来(或者写到flash);通过使用串口输出产生hard_fault的堆栈信息,然后利用addr2line工具反推出具体的代码执行函数,快速定位hard_fault问题;
1:CmBacktrace获取
看两个git的更新记录,github应该是比较新的;作者都是同一个人
github地址
bash
https://github.com/armink/CmBacktrace
gitee地址
bash
https://gitee.com/Armink/CmBacktrace
使用说明介绍这个博主讲的挺详细的
bash
https://blog.csdn.net/weiqifa0/article/details/120499893
然后大家自行搜索一下 addr2line 工具的说明即可
2:CmBackTrace代码修改适配
cmb_cfg.h 修改
c
#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文件名称可能不一致;
c
......
#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修改
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
c
/*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里面定义的是弱函数,重写之后自动覆盖了; 担心没有覆盖的话可以屏蔽掉
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寄存器的出来的
bash
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执行如下;我使用相对路径执行的,没有添加环境变量
bash
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)
最后附一张截图