• 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中添加相关文件和路径

    请添加图片描述

    请添加图片描述

    请添加图片描述

    • 修改 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_TYPECPU平台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_ */
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 修改 cmb_def.h ,根据链接脚本添加栈顶地址栈截至地址代码段起始地址,截止地址
      注意压栈方向,因为我们是满降栈,所以 __StackTop 和 __StackLimit 如下填写
      请添加图片描述

    • 修改 cm_backtrace.c 使用C99gnu99

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

    请添加图片描述

    • 修改 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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 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;
    }
    /*-----------------------------------------------------------*/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    typedef struct tskTaskControlBlock添加

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

    static void prvInitialiseNewTask添加

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

    请添加图片描述

    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    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");
    
    • 1
    • 2
    • 3
    6.运行代码,查询异常信息

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

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

    请添加图片描述

  • 相关阅读:
    聊聊推荐系统的评测(上)
    物联网中的常见传感器
    Spring Web MVC入门
    [物联网专题] - 螺钉式接线端子的选择和辨识
    43、Flink 自定义窗口触发器代码示例
    离子液体(1-乙基-3-甲基咪唑六氟磷酸[EMIM][PF6])负载量不同的多孔纳米氧化硅(SiOx)研究结果
    Java基础——Java的输入(Scanner对象的使用)
    2021年IB各科7分率
    RTC-实时音视频通信技术介绍与应用
    C++ 引用本质
  • 原文地址:https://blog.csdn.net/weixin_38426553/article/details/132744835