I.MX RT1176笔记(9)-- 程序异常追踪(CmBacktrace 和 segger rtt)

前言

在使用 ARM Cortex-M 系列 MCU时候,有时候会遇到各种异常(Hard Fault, Memory Management Fault, Bus Fault, Usage Fault, Debug Fault),这时候我们根据经验查询PC指针,LR寄存器,堆栈数据定位地址然后再通过反汇编确定异常位置,但往往会花很多时间,那么有没有一种工具可以很快定位出错位置呢?这里推荐使用 CmBacktrace

开发前期准备

  • 硬件平台 rt1176开发板
  • IDE: GNU(vscode)
  • CmBacktrace + segger rtt
1.Segger RTT 获取

J-Link RTT – Real Time Transfer (segger.com)

segger rtt 可以简单理解 Jlink的组件吧,我们不需要多余外设(如串口等),只需要调试口,将需要的数据打印到窗口。组件获取很简单,如果安装了Jlink驱动,直接到安装路径会找到组件压缩文件,将文件解压到工程就行了。

请添加图片描述

2.CmBacktrace 获取

CmBacktrace: ARM Cortex-M 系列 MCU 错误追踪库 (gitee.com)

GitHub - armink/CmBacktrace: Advanced fault backtrace library for ARM Cortex-M series MCU | ARM Cortex-M 系列 MCU 错误追踪库

3.移植 CmBacktrace 和 Segger RTT
  • cmake中添加相关文件和路径

I.MX RT1176笔记(9)-- 程序异常追踪(CmBacktrace 和 segger rtt)_第1张图片

I.MX RT1176笔记(9)-- 程序异常追踪(CmBacktrace 和 segger rtt)_第2张图片

I.MX RT1176笔记(9)-- 程序异常追踪(CmBacktrace 和 segger rtt)_第3张图片

  • 修改 cmb_cfg.h

用户需要自行手动配置,常用配置如下:

配置名称 功能 备注
cmb_println(…) 错误及诊断信息输出 必须配置
CMB_USING_BARE_METAL_PLATFORM 是否使用在裸机平台 使用则定义该宏
CMB_USING_OS_PLATFORM 是否使用在操作系统平台 操作系统与裸机必须二选一
CMB_OS_PLATFORM_TYPE 操作系统平台 RTT/UCOSII/UCOSIII/FREERTOS
CMB_CPU_PLATFORM_TYPE CPU平台 M0/M3/M4/M7
CMB_USING_DUMP_STACK_INFO 是否使用 Dump 堆栈的功能 使用则定义该宏
CMB_PRINT_LANGUAGE 输出信息时的语言 CHINESE/ENGLISH
#ifndef _CMB_CFG_H_
#define _CMB_CFG_H_

#include "SEGGER_RTT.h"


/* print line, must config by user */
#define cmb_println(...)               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 */
/* 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 */
/* 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_ */

  • 修改 cmb_def.h ,根据链接脚本添加栈顶地址栈截至地址代码段起始地址,截止地址
    注意压栈方向,因为我们是满降栈,所以 __StackTop 和 __StackLimit 如下填写
    I.MX RT1176笔记(9)-- 程序异常追踪(CmBacktrace 和 segger rtt)_第4张图片

  • 修改 cm_backtrace.c 使用C99gnu99

笔者工程默认用的gnu99标准,所以屏蔽了如下信息(如果是C99可保留)

I.MX RT1176笔记(9)-- 程序异常追踪(CmBacktrace 和 segger rtt)_第5张图片

  • 修改 HardFault_Handler MemManage_Handler 中断函数(笔者没添加cm_fault.S
void HardFault_Handler(void)
{
  __asm volatile
  (
    "	mov r0, lr							\n"
    "	mov r1, sp							\n"
    "	bl cm_backtrace_fault		\n"
  );

  while(1);
}

void MemManage_Handler(void)
{
  __asm volatile
  (
    "	mov r0, lr							\n"
    "	mov r1, sp							\n"
    "	bl cm_backtrace_fault		\n"
  );

  while(1);
}
  • FreeRtos修改内容(没有使用不用关心)

task.c 末尾添加

/*-----------------------------------------------------------*/
/*< Support For CmBacktrace >*/
uint32_t * vTaskStackAddr()
{
    return pxCurrentTCB->pxStack;
}
 
uint32_t vTaskStackSize()
{
    #if ( portSTACK_GROWTH > 0 )
    
    return (pxNewTCB->pxEndOfStack - pxNewTCB->pxStack + 1);
    
    #else /* ( portSTACK_GROWTH > 0 )*/
    
    return pxCurrentTCB->uxSizeOfStack;
    
    #endif /* ( portSTACK_GROWTH > 0 )*/
}
 
char * vTaskName()
{
    return pxCurrentTCB->pcTaskName;
}
/*-----------------------------------------------------------*/

typedef struct tskTaskControlBlock添加

#if( portSTACK_GROWTH <= 0)
	UBaseType_t     uxSizeOfStack;      /*< Support For CmBacktrace >*/
#endif

static void prvInitialiseNewTask添加

pxNewTCB->uxSizeOfStack = ulStackDepth;   /*< Support For CmBacktrace >*/

I.MX RT1176笔记(9)-- 程序异常追踪(CmBacktrace 和 segger rtt)_第6张图片

4.写一个能进异常中断的代码
uint32_t *ptr32=0xFFFFFFF1;
uint32_t tmp;

//笔者放到一个线程中
static void xAPP_KeyScanTask(void* pvParameters)
{
	while(1)
	{
		/*按键扫描*/
		xSYS_LEDKEY_KeyScan();
#if CONFIG_EN_CMBACKTRACE
        tmp = *ptr32; //这句话放到任一地方,将会引起异常
#endif        
        vTaskDelay(10);
    }
}
5.添加 CmBacktrace 和 Segger RTT 初始化代码
	SEGGER_RTT_Init();
    cm_backtrace_init("rt1176_rtos_app", "B1.0.0", "B1.0.0");
	SEGGER_RTT_printf(0, "Enable Cmbacktrace\r\n");
6.运行代码,查询异常信息

打开 J-Link RTT Viewer将监听到异常打印信息,甚至知道错误代码在函数:xAPP_KeyScanTask 中,除此之外我们可以通过终端控制台,输入如下命令(addr2line.exeCmBacktrace 提供工具):

.\addr2line.exe -e .\rt1176_rtos_app.elf -a -f 00001fc0 00003c26

I.MX RT1176笔记(9)-- 程序异常追踪(CmBacktrace 和 segger rtt)_第7张图片

你可能感兴趣的:(RT1176,VS,Code,RTOS,笔记,gnu,vscode,arm)