一、CmBacktrace简介
一款针对 ARM Cortex-M 系列 MCU 的错误代码自动追踪、定位,错误原因自动分析的开源库。主要特性如下:
- 支持的错误包括:
- 断言(assert)
- 故障(Hard Fault, Memory Management Fault, Bus Fault, Usage Fault, Debug Fault)
- 故障原因 自动诊断 :可在故障发生时,自动分析出故障的原因,定位发生故障的代码位置,而无需再手动分析繁杂的故障寄存器;
- 输出错误现场的 函数调用栈(需配合 addr2line 工具进行精确定位),还原发生错误时的现场信息,定位问题代码位置、逻辑更加快捷、精准。也可以在正常状态下使用该库,获取当前的函数调用栈;
- 支持 裸机 及以下操作系统平台:
- RT-Thread
- UCOS
- FreeRTOS(需修改源码)
- 根据错误现场状态,输出对应的 线程栈 或 C 主栈;
- 故障诊断信息支持多国语言(目前:简体中文、英文);
- 适配 Cortex-M0/M3/M4/M7 MCU;
- 支持 IAR、KEIL、GCC 编译器;
更多详情大家可以到GITHUB开源的这个网址查看:CmBacktrace开源代码
二、移植环境
系统:WIN7
MDK:keil v5.26
开发板:GD32F303C-EVAL
固件库:V1.0.2
FreeRTOS版本:V10.4.0
CmBacktrace Release 1.4.0
三、开始移植
1> 下载源码,解压,如下图:
cm_backtrace这个文件夹下就是核心文件,就是我们移植需要用到的。
2>将核心文件添加到工程中,将1中cm_backtrace整个文件夹复制到工程,添加文件和头文件路径到工程。
3> 将gd32f30x_it.c文件中断硬件中断入口函数屏蔽掉,因为cmb_fault.S中重构了这个函数,重复了。当然了也可以有另外的一种方式,详情可以参考源代码中移植说明。
4>写断言函数
因为GD的库中很少用到指针形参,与ST的标准库有很大区别,所以不像ST库里面用到了断言函数。所以只能自己写一个。参考如下:
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
cm_backtrace_assert(cmb_get_sp());
SEGGER_RTT_printf(0,"assert failed at %s:%d \n", file, line);
// printf("assert failed at %s:%d \n", file, line);
while (1) {
}
}
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval : None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__,(uint32_t) __LINE__))
这里还需要将cmb_cfg.h中进行如下修改,为了方便打印信息
代码开发完成后,可以将断言函数和打印信息关掉,节省代码空间。
5>配置说明,配置文件是cmb_cfg.h
#ifndef _CMB_CFG_H_
#define _CMB_CFG_H_
/* print line, must config by user */
//#define cmb_println(...) printf(__VA_ARGS__);printf("\r\n");
#define cmb_println(...) SEGGER_RTT_printf(0,__VA_ARGS__);SEGGER_RTT_printf(0,"\r\n");/* e.g., printf(__VA_ARGS__);printf("\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_RTT or CMB_OS_PLATFORM_UCOSII or CMB_OS_PLATFORM_UCOSIII or CMB_OS_PLATFORM_FREERTOS */
/* cpu platform type, must config by user */
#define CMB_CPU_PLATFORM_TYPE CMB_CPU_ARM_CORTEX_M4/* CMB_CPU_ARM_CORTEX_M0 or CMB_CPU_ARM_CORTEX_M3 or CMB_CPU_ARM_CORTEX_M4 or CMB_CPU_ARM_CORTEX_M7 */
/* 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
#endif /* _CMB_CFG_H_ */
6> 添加头文件和初始化函数
#include "cm_backtrace.h"
/* CmBacktrace initialize */
cm_backtrace_init("CmBacktrace", HARDWARE_VERSION, SOFTWARE_VERSION);
至此移植完成。
四、测试
这里使用开源代码中提供一个demo进行测试
#include "SEGGER_RTT.h"
#include "cm_backtrace.h"
#define HARDWARE_VERSION "V1.0.0"
#define SOFTWARE_VERSION "V0.1.0"
void fault_test_by_div0(void);
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
cm_backtrace_assert(cmb_get_sp());
SEGGER_RTT_printf(0,"assert failed at %s:%d \n", file, line);
// printf("assert failed at %s:%d \n", file, line);
while (1) {
}
}
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval : None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__,(uint32_t) __LINE__))
int main(void)
{
delay_init();
usart0_shell();
GW_LedInit(LED1);
/* CmBacktrace initialize */
cm_backtrace_init("CmBacktrace", HARDWARE_VERSION, SOFTWARE_VERSION);
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
SEGGER_RTT_printf(0,"test start\r\n");
fault_test_by_div0();
while(1)
{
GW_LedToggle(LED1);
delay_xms(100);
}
}
void fault_test_by_div0(void)
{
volatile int * SCB_CCR = (volatile int *) 0xE000ED14; // SCB->CCR
int x, y, z;
*SCB_CCR |= (1 << 4); /* bit4: DIV_0_TRP. */
x = 10;
y = 0;
z = x / y;
printf("z:%d\n", z);
}
五、测试结果
从结果的最后打印信息看出;提示是除0错误导致的,更加详细的就需要打开MAP文件和错误寄存器查看了。