PSoC4 SoftUart & CmbackTrace -- Hardfault


PSoC4 SoftUart & CmbackTrace – Hardfault

使用CmBackTrace定位PSoC4的hardfault!

背景

调试PSoC4 时很不巧遇到了Hardfault,debug发现程序运行了一段时间后跳到了Cm0plusStart.c中的CY_ISR ( IntDefaultHandler ) 中,查看vector发现,NMI中断和hardfault的处理函数都是调用该函数,于是想到使用CmbackTrace来定位是哪条语句引起的!

CmBackTrace简介

CmBacktrace (Cortex Microcontroller Backtrace)是一款针对 ARM Cortex-M 系列 MCU 的错误代码自动追踪、定位,错误原因自动分析的开源库。主要特性如下:

  • 支持的错误包括:
    • 断言(assert
    • 故障(Hard Fault, Memory Management Fault, Bus Fault, Usage Fault, Debug Fault)
  • 故障原因 自动诊断 :可在故障发生时,自动分析出故障的原因,定位发生故障的代码位置,而无需再手动分析繁杂的故障寄存器;
  • 输出错误现场的 函数调用栈(需配合 addr2line 工具进行精确定位),还原发生错误时的现场信息,定位问题代码位置、逻辑更加快捷、精准。也可以在正常状态下使用该库,获取当前的函数调用栈;
  • 支持 裸机 及以下操作系统平台:
  • 根据错误现场状态,输出对应的 线程栈 或 C 主栈;
  • 故障诊断信息支持多国语言(目前:简体中文、英文);
  • 适配 Cortex-M0/M3/M4/M7 MCU;
  • 支持 IAR、KEIL、GCC 编译器;

Note: 作者朱天龙 (Armink),开源了FlashDB、EasyLogger、CmBacktrace、EasyFlash、SFUD等等非常好用的嵌入式组件,感恩~ 作者Github:https://github.com/armink ,前往作者的Github下载下最新版本的CmBackTrace,开始移植。

PSoC Soft UART – printf

PSoC Creator中神奇的uart组件 – Software Transmit UART,只用一个IO,汇编指令实现的软uart tx。选择它并配置波特率9600,UARTDbg_Start() 后即可使用。
SoftUart

printf输出重定向至软串口发送:

//Heap Size需要改大 -- 0x0400?
int _write(int file, char *ptr, int len)
{
    int i;
    file = file;
    for (i = 0; i < len; i++)
    {
        UARTDbg_PutChar(*ptr++);
    }
    return len;
}

Note: Heap Size一定要改大!!!
程序中包含下头文件 “stdio.h”,然后就可以愉快的调用printf啦。

CmBackTrace移植

  1. 将cm_backtrace相关的文件添加到工程中,配置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")
/* enable bare metal(no OS) platform */
#define CMB_USING_BARE_METAL_PLATFORM
/* cpu platform type, must config by user */
#define CMB_CPU_PLATFORM_TYPE          CMB_CPU_ARM_CORTEX_M0
/* enable dump stack information */
#define CMB_USING_DUMP_STACK_INFO
/* language of print information */
#define CMB_PRINT_LANGUAGE             CMB_PRINT_LANUUAGE_ENGLISH

#endif /* _CMB_CFG_H_ */
  1. 修改Cm0plusStart.c中的 //&IntDefaultHandler, /* The hard fault handler 3 */
    注释掉并修改为&HardFault_Handler, 使用CmBackTrace的HardFault_Handler处理。
  2. 修改cmb_def.h中CMB_CSTACK_BLOCK_START和CMB_CSTACK_BLOCK_END的定义,
    Creator使用的是GNUC的GCC,所以修改#elif defined(GNUC)中:
    #define CMB_CSTACK_BLOCK_START         __cy_heap_end
    #define CMB_CSTACK_BLOCK_END           __cy_stack
  3. 移植demo中的hardfault测试函数:除0和unlign,结果发现都无法引起hardfault,增加一个abnormal_access的测试函数:

void fault_test_by_unalign(void) {
    volatile int * SCB_CCR = (volatile int *) 0xE000ED14; // SCB->CCR
    volatile int * p;
    volatile int value;

    *SCB_CCR |= (1 << 3); /* bit3: UNALIGN_TRP. */

    p = (int *) 0x00;
    value = *p;
    printf("addr:0x%02X value:0x%08X\r\n", (int) p, value);

    p = (int *) 0x04;
    value = *p;
    printf("addr:0x%02X value:0x%08X\r\n", (int) p, value);

    p = (int *) 0x03;
    value = *p;
    printf("addr:0x%02X value:0x%08X\r\n", (int) p, value);
}

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("div0: %d\r\n", z);
}

void fault_test_abnormal_access()
{
    uint32_t addr = 0xCCCCCCCC;
    uint32_t val = *(volatile uint32_t*)addr;
    printf("abnormal_access: %d! \r\n",val);
}

运行测试

main中调用,编译、下载运行:

cm_backtrace_init("SoftUart", HARDWARE_VERSION, SOFTWARE_VERSION);
uartDbgInit();
fault_test_by_div0();
fault_test_by_unalign();
fault_test_abnormal_access(); 

打开串口调试助手:(除0和非对齐访问,都可以正常运行..)
Hardfault

将add2link拷编译目录下并打开命令行程序,运行其中提示的
addr2line -e SoftUart.elf -a -f 000006b4 000006e6 000007a8 0000001a

add2line
找到对应的 main.c : 64行:
abnormal_access

就是它引起的Hardfault !有了它,再也不怕hardfault了~

by the way:
修改Cm0plusStart.c,重新编译生成时有时修改了的HardFault会被默认替换掉,使用时注意下即可。欢迎交流~


文章作者: xArm
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 xArm !
评论
  目录