• 亲测可用的RT1052+FreeRTOS10.3移植CmBacktrace方法——2022.11.12


    搜遍全网都找不到一个靠谱的RT1052可用的移植方法,自己弄了一个分享出来,禁止一切形式未经许可的转载复制。

    CmBacktrace

    CmBacktrace(Cortex Microcontroller Backtrace)是一款针对 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 编译器;

    源码仓库地址https://github.com/armink/CmBacktrace

    移植CmBacktrace

    前期准备

    1. CmBacktrace源码
    2. 任意RT1052+FreeRTOS V10的keil工程(所有i.MX RT系列都可以)

    移植过程

    添加CmBacktrace到工程

    把下载到的cm_backtrace文件夹复制到工程目录下,我这里为了方便,直接用官方sdk里的demo工程做演示了😆。实际情况以实际工程为准,步骤是一样的。
    在这里插入图片描述


    打开工程,在工程里添加源文件和包含路径
    在这里插入图片描述
    在这里插入图片描述


    右键点击工程界面左边添加好的cmb_fault.S,点击Options for File ‘cmb_fault.S’,在Asm选项卡按照图中选择
    在这里插入图片描述

    配置CmBacktrace

    需要配置的有cmb_cfg.h和cmb_def.h两个文件。
    先打开工程目录下的cmb_cfg.h,这个文件用来配置CmBacktrace,每个配置项的具体含义如下:

    配置项功能说明
    cmb_println(…)输出诊断信息必须配置
    CMB_USING_BARE_METAL_PLATFORM使能裸机平台配置在裸机上用就开这个宏
    CMB_USING_OS_PLATFORM使能RTOS平台配置在rtos上用就开这个宏
    CMB_OS_PLATFORM_TYPE选择RTOS类型在rtos上用必须配置
    CMB_CPU_PLATFORM_TYPE选择MCU内核类型必须配置
    CMB_USING_DUMP_STACK_INFO使能Dump堆栈信息功能需要时配置
    CMB_PRINT_LANGUAGE选择输出语言需要时配置,默认英文

    表格的第1、3、4、5、7行是我们需要配置的项,具体配置如下:

    #ifndef _CMB_CFG_H_
    #define _CMB_CFG_H_
    
    #include "fsl_debug_console.h"
    
    /* print line, must config by user */
    #define cmb_println(...)               PRINTF(__VA_ARGS__);PRINTF("\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_FREERTOS/* 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_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

    然后是cmb_def.h,需要把栈节区和代码节区的名字改一下,这里不受具体工程配置的影响,也就是说不管代码和堆栈实际放在哪里,只要名字和分散加载里的定义的一样就能用,代码节区名字一定要和分散加载文件保持一致,具体改成下面这样:

    #if defined(__ARMCC_VERSION)
        /* C stack block name, default is STACK */
        #ifndef CMB_CSTACK_BLOCK_NAME
        #define CMB_CSTACK_BLOCK_NAME          Image$$ARM_LIB_STACK$$ZI
        #endif
        /* code section name, default is ER_IROM1 */
        #ifndef CMB_CODE_SECTION_NAME
        #define CMB_CODE_SECTION_NAME          ER_m_text
        #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    接着到cm_backtrace.c,找到587行的cmb_println,在下图位置加一个空格。
    在这里插入图片描述

    适配FreeRTOS

    配置好CmBacktrace以后,还需要改一下FreeRTOS的源码,不用担心不用怕,只是加几行获取任务栈信息的函数而已😊,并不会影响原本FreeRTOS的功能。

    首先打开FreeRTOSConfig.h把下图这个宏关掉,不然会影响到实际使用效果,这个是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

    找到下图中的两处地方加入代码:在这里插入图片描述

    	#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
    		StackType_t		*pxEndOfStack;		/*< Points to the highest valid address for the stack. */
    	#else
            UBaseType_t     uxSizeOfStack;      /*< Support For CmBacktrace >*/
      #endif /* ( portSTACK_GROWTH > 0 )*/
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

        #else
        pxNewTCB->uxSizeOfStack = ulStackDepth;   /*< Support For CmBacktrace >*/
        #endif /* configRECORD_STACK_HIGH_ADDRESS */
    
    • 1
    • 2
    • 3

    这个时候编译就没有错了。

    使用CmBacktrace追踪错误

    初始化CmBacktrace

    在自己喜欢的地方添加宏定义:

    #define APPNAME                        "cmbacktrace_test"
    #define HARDWARE_VERSION               "V1.0.0"
    #define SOFTWARE_VERSION               "V0.1.0"
    
    • 1
    • 2
    • 3

    在main函数中调用初始化函数;
    写一个除零错误的函数模拟hard fault;
    创建一个任务调用除零函数模拟任务中错误的情况,main函数完整代码如下:

    int main(void)
    {
        /* Init board hardware. */
        BOARD_ConfigMPU();
        BOARD_InitBootPins();
        BOARD_InitBootClocks();
        BOARD_InitDebugConsole();
      
        /* CmBacktrace initialize */
        cm_backtrace_init("CmBacktrace", HARDWARE_VERSION, SOFTWARE_VERSION);
      
        if (xTaskCreate(hello_task, "Hello_task", configMINIMAL_STACK_SIZE + 100, NULL, hello_task_PRIORITY, NULL) !=
            pdPASS)
        {
            PRINTF("Task creation failed!.\r\n");
            while (1)
                ;
        }
        if (xTaskCreate(test_task, "test_task", configMINIMAL_STACK_SIZE + 100, NULL, test_task_PRIORITY, NULL) !=
            pdPASS)
        {
            PRINTF("Task creation failed!.\r\n");
            while (1)
                ;
        }
        vTaskStartScheduler();
        for (;;)
            ;
    }
    
    /*!
     * @brief Task responsible for printing of "Hello world." message.
     */
    static void hello_task(void *pvParameters)
    {
        for (;;)
        {
            PRINTF("Hello world.\r\n");
            vTaskSuspend(NULL);
        }
    }
    
    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);
    }
    
    static void test_task(void *pvParameters)
    {
      fault_test_by_div0();
        for (;;)
        {
          PRINTF("cmbacktrace.\r\n");
          vTaskDelay(100);
        }
    }
    
    • 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
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    编译并下载运行,在串口助手中可以看到如下输出信息。
    要注意的是,不管是debug工程还是release工程,都需要进入keil的debug界面运行代码才会有输出,目前暂时不清楚为啥。
    在这里插入图片描述

    定位到具体的出错代码

    串口打印出了当前发生的是哪种hard fault,定位到具体的代码还需要addr2line工具,工具的可执行文件addr2line.exe就在一开始下载的源码包的tools\addr2line\win64路径下。
    解压addr2line.exe到工程.axf文件所在的文件夹,并在此文件夹下打开命令行工具,墙裂建议安装Windows Terminal,用过最好用的win命令行工具。
    在这里插入图片描述

    打开工具以后,把串口助手最后一行打印的命令复制到命令行工具内,把cmbacktrace.axf替换成自己工程里的文件名。不管后缀是.out还是.axf都是可以的,然后回车就能看到具体的出错代码位置。
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    【无标题】
    LVDS、LVPECL、CML三种高速逻辑电平的比较
    云原生之深入解析如何使用Vcluster Kubernetes加速开发效率
    3d激光SLAM:LIO-SAM框架---IMU预积分功能数据初始化
    FFT专题:IFFT后信号如何重建
    Java 19的未来:新特性、性能优化和更多
    操作符编程练习题
    70、Spring Data JPA 的 自定义查询(全手动,自己写完整 SQL 语句)
    6数据层相关框架-基本
    Vue生命周期
  • 原文地址:https://blog.csdn.net/zzz_xxj/article/details/127810268