【经验】 EFM32工程代码HardFault异常故障调试方法

2017-12-09 世强 Carol
MCU,EFM32,EFM32GG-STK3700,Silicon Labs MCU,EFM32,EFM32GG-STK3700,Silicon Labs MCU,EFM32,EFM32GG-STK3700,Silicon Labs MCU,EFM32,EFM32GG-STK3700,Silicon Labs

最近有客户反馈使用EFM32系列MCU开发时,遇到HardFault问题,但是很难定位到导致故障的代码。本篇文章为大家讲解EFM32工程代码HardFault异常故障调试方法,来定位故障原因。使用Simplicity IDE开发环境调试,编译器是GNU ARM v4.8.3,硬件基于EFM32GG-STK3700


原理介绍

Cortex-M架构定义了硬件故障处理(HardFault Handlers)程序,当内核企图执行无效的操作时,例如操作一个无效的操作码或访问非映射内存,就会进入到这个程序。Cortex-M3或Cortex-M4内核的器件,定义了下面的处理程序:

• Bus Fault

• Memory Management Fault

• Usage Fault

• Hard Fault


前面3个处理程序必须特别启用,如果未启用,将自动升级为第4个硬件故障。当错误发生,SCB->CFSR寄存器包含有关故障原因的信息。此外,硬件在进入硬件故障处理中断程序之前会自动将多个CPU寄存器推送到堆栈上进行保存,如图一。因此在进入中断程序后可以读取到这些值,对其进行检查,以便进一步调试故障的原因。LR是Link Register,它存储子程序、函数调用和异常的返回信息。PC是Program Counter,它指程序运行的地址,而错误产生时保存的就是出现错误时的程序地址。通过LR和PC两个寄存器的值,就可以定位到故障原因。


 

图一:中断前后堆栈指针指向


添加程序代码

需要在HardFault_Handler(void)函数中使用汇编语句,作用是检查哪个堆栈被使用,并复制堆栈指针到R0寄存器。定义__attribute__( (naked) )是为了避免编译器生成函数修改堆栈指针。添加debugHardfault函数。本文工程中输出是通过SWO引脚输出,因此在工程中还需要添加setupSWOForPrint()函数和retargetio.c文件(路径:


{SimplicityStudio_root}/v4/developer\sdks\exx32\v5.0.0.0\hardwarekits/common/drivers/)。完整代码如下:

#include "em_device.h"

#include "em_chip.h"

#include <stdio.h>


void setupSWOForPrint(void)

{

  /* Enable GPIO clock. */

  CMU->HFPERCLKEN0 |= CMU_HFPERCLKEN0_GPIO;


  /* Enable Serial wire output pin */

  GPIO->ROUTE |= GPIO_ROUTE_SWOPEN;


#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_LEOPARD_FAMILY) || defined(_EFM32_WONDER_FAMILY)

  /* Set location 0 */

  GPIO->ROUTE = (GPIO->ROUTE & ~(_GPIO_ROUTE_SWLOCATION_MASK)) | GPIO_ROUTE_SWLOCATION_LOC0;


  /* Enable output on pin - GPIO Port F, Pin 2 */

  GPIO->P[5].MODEL &= ~(_GPIO_P_MODEL_MODE2_MASK);

  GPIO->P[5].MODEL |= GPIO_P_MODEL_MODE2_PUSHPULL;

#else

  /* Set location 1 */

  GPIO->ROUTE = (GPIO->ROUTE & ~(_GPIO_ROUTE_SWLOCATION_MASK)) |GPIO_ROUTE_SWLOCATION_LOC1;

  /* Enable output on pin */

  GPIO->P[2].MODEH &= ~(_GPIO_P_MODEH_MODE15_MASK);

  GPIO->P[2].MODEH |= GPIO_P_MODEH_MODE15_PUSHPULL;

#endif


  /* Enable debug clock AUXHFRCO */

  CMU->OSCENCMD = CMU_OSCENCMD_AUXHFRCOEN;


  /* Wait until clock is ready */

  while (!(CMU->STATUS & CMU_STATUS_AUXHFRCORDY));


  /* Enable trace in core debug */

  CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;

  ITM->LAR  = 0xC5ACCE55;

  ITM->TER  = 0x0;

  ITM->TCR  = 0x0;

  TPI->SPPR = 2;

  TPI->ACPR = 0xf;

  ITM->TPR  = 0x0;

  DWT->CTRL = 0x400003FF;

  ITM->TCR  = 0x0001000D;

  TPI->FFCR = 0x00000100;

  ITM->TER  = 0x1;

}

void debugHardfault(uint32_t *sp)

{

    uint32_t cfsr  = SCB->CFSR;

    uint32_t hfsr  = SCB->HFSR;

    uint32_t mmfar = SCB->MMFAR;

    uint32_t bfar  = SCB->BFAR;


    uint32_t r0  = sp[0];

    uint32_t r1  = sp[1];

    uint32_t r2  = sp[2];

    uint32_t r3  = sp[3];

    uint32_t r12 = sp[4];

    uint32_t lr  = sp[5];

    uint32_t pc  = sp[6];

    uint32_t psr = sp[7];


    printf("HardFault:\n");

    printf("SCB->CFSR   0x%08lx\n", cfsr);

    printf("SCB->HFSR   0x%08lx\n", hfsr);

    printf("SCB->MMFAR  0x%08lx\n", mmfar);

    printf("SCB->BFAR   0x%08lx\n", bfar);

    printf("\n");


    printf("SP          0x%08lx\n", (uint32_t)sp);

    printf("R0          0x%08lx\n", r0);

    printf("R1          0x%08lx\n", r1);

    printf("R2          0x%08lx\n", r2);

    printf("R3          0x%08lx\n", r3);

    printf("R12         0x%08lx\n", r12);

    printf("LR          0x%08lx\n", lr);

    printf("PC          0x%08lx\n", pc);

    printf("PSR         0x%08lx\n", psr);


    while(1);

}


__attribute__( (naked) )

void HardFault_Handler(void)

{

    __asm volatile

    (

        "tst lr, #4                                    \n"

        "ite eq                                        \n"

        "mrseq r0, msp                                 \n"

        "mrsne r0, psp                                 \n"

        "ldr r1, debugHardfault_address                \n"

        "bx r1                                         \n"

        "debugHardfault_address: .word debugHardfault  \n"

    );

}


int RETARGET_ReadChar(void)

{

    return 0;

}

int RETARGET_WriteChar(char c)

{

    return ITM_SendChar(c);

}


int div(int lho, int rho)

{

    return lho/rho;

}

/**************************************************************************//**

 * @brief  Main function

 *****************************************************************************/

int main(void)

{  int a = 10;

  int b = 0;

  int c;

  /* Chip errata */

  CHIP_Init();

  SCB->CCR |= 0x10;

  setupSWOForPrint();


  printf("Start\n");


     c = div(a, b);

  /* Create an invalid function pointer and call it.

   * This will trigger a Hard Fault.  */

  //void (*fp)(void) = (void (*)(void))(0x00000008);

  //fp();


  /* Infinite loop */

  while (1);

}


分析调试结果

上面代码在主函数里调用了一个除数函数div(int lho, int rho),并人为的让分母为0,造成一个异常。将程序下载到MCU运行后,利用Commander SWO终端可以看到输出结果,如下图二:

 

图二:Commander SWO终端输出结果


在实际开发中我们是不知道是哪个函数导致异常的,那么如何从输出结果中分析出导致异常的函数呢?我们在编译生成的.map文件中找到LR和PC值的地址区间,可以看到LR的值0x000004c5是落在main函数里,main函数在Flash的起始地址是0x00000494。PC的值0x00000482是落在div函数里,div函数在Flash的起始地址是0x00000474,从而定位到导致异常的函数是div函数。定位到异常的函数,大家就可以比较容易查找出错误的原因了。

 

世强元件电商版权所有,转载请注明来源及链接。

授权代理商:世强先进(深圳)科技股份有限公司
技术资料,数据手册,3D模型库,原理图,PCB封装文件,选型指南来源平台:世强硬创平台www.sekorm.com
现货商城,价格查询,交期查询,订货,现货采购,在线购买,样品申请渠道:世强硬创平台电子商城www.sekorm.com/supply/
概念,方案,设计,选型,BOM优化,FAE技术支持,样品,加工定制,测试,量产供应服务提供:世强硬创平台www.sekorm.com
集成电路,电子元件,电子材料,电气自动化,电机,仪器全品类供应:世强硬创平台www.sekorm.com
  • +1 赞 0
  • 收藏
  • 评论 4

本网站所有内容禁止转载,否则追究法律责任!

平台合作

评论

   |   

提交评论

全部评论(4

  • 风云再起 Lv4. 资深工程师 2017-12-09
    好好干
  • ken2089 Lv4. 资深工程师 2017-12-09
    学习了
  • 沈戈戈 Lv7. 资深专家 2017-12-09
    感谢分享,资料不错,学习了解下先
  • 龙大 Lv7. 资深专家 2017-12-09
    不错
没有更多评论了

相关推荐

【经验】MCU EFM32 debug引脚复用引起的代码下载问题分析

在MCU的应用当中,我们经常会利用完MCU的一切资源,比如EFM32中的J-Link调试接口SWDIO和SWCLK,这两个引脚除了作为J-Llink引脚之外,还可以作为通用GPIO来实现其它功能,这样设计并没有问题,但是需要进行代码更新调试或者再次代码下载时,无法进行调试或者下载,具体查看方式为……

2019-05-11 -  设计经验 代理服务 技术支持 采购服务

【经验】如何使用Simplicity Studio查看MCU内部Flash的数据?

Simplicity Studio是Silicon Labs公司免费提供给客户用于MCU、Wireless SOC等平台的开发工具,其支持C8051F系列、EFM8系列、EFM32系列、EZR32系列以及EFR32系列器件。

2019-07-29 -  设计经验 代理服务 技术支持 采购服务

【经验】EFM32系列32位超低功耗MCU之复位源读取

EFM32是Silicon Labs公司推出的32位超低功耗MCU系列,由于其超低功耗和丰富的外设等特性,被广泛的使用各种产品开发。很多时候工程师需要监控MCU的复位原因,根据复位原因来查找程序可能存在的问题。但是很多工程师通过读取RMU_RSTCAUSE寄存器得到复位源不准确,本文以EFM32GG-STK3700 Demo为例,指导大家如何正确读取EFM32的复位源。

2018-08-08 -  设计经验 代理服务 技术支持 采购服务

Silabs的32位MCU EFM32 SWDIO和SWCLK两个管脚被复用之后,无法下载代码,怎么解决?

解决办法1: 在GPIO初始化之前加入一段较长的延迟,上电之后可以进行代码下载。 解决办法2: 需要外部拉低SWDIO引脚,然后上电,就可以进行代码下载了。

2019-05-06 -  技术问答 代理服务 技术支持 采购服务

Silicon Labs EFM8BB1系列8位MCU的量产软件有哪些?

Silicon Labs EFM8BB1系列8位MCU的量产软件可以采用Silicon Labs 原厂提供的MCU Production Programmer 和 Flash Programming Utility软件,建议采用前者,下载效率更高;

2018-11-14 -  技术问答 代理服务 技术支持 采购服务

EFM32 MCU中DMA功能传送是否存在优先级?

silicon labs 32位MCU 内的DMA功能传送中分为高优先级和基础优先级。每种优先级下有各通道的自然优先级,通道 数越大自然优先级越小。

2020-10-23 -  技术问答 代理服务 技术支持 采购服务

silicon labs EFM32G系列32位MCU的TIMER计数器的时钟源有哪些?

silicon labs EFM32G系列32位MCU的TIMER计数器的时钟源如下: 1、由高频外设时钟HFPERCLK经分频后提供给TIMER; 2、由CC1通道输入的外部时钟源,可以选择外部引脚输入或PRS输入; 3、由上一级的TIMER事件作为时钟源。

2019-05-13 -  技术问答 代理服务 技术支持 采购服务

世强是否代理st系列MCU?

世强代理有Silicon Labs EFM8/EFM32系列8位MCU/32位MCU,Renesas 汽车级MCU RL78 系列,RH850、V850系列,工业级MCU RX系列等。 没有ST的

2018-11-08 -  技术问答 代理服务 技术支持 采购服务
展开更多

电子商城

查看更多

品牌:SILICON LABS

品类:开发套件

价格:¥735.8560

现货:3

品牌:SILICON LABS

品类:32位MCU

价格:¥10.4057

现货:21,867

品牌:SILICON LABS

品类:8位MCU

价格:¥5.8534

现货:66,518

品牌:SILICON LABS

品类:8位MCU

价格:¥9.6632

现货:45,605

品牌:SILICON LABS

品类:8位MCU

价格:¥14.1226

现货:37,371

品牌:SILICON LABS

品类:8 BIT MCU

价格:¥4.3667

现货:27,741

品牌:SILICON LABS

品类:32 BIT MCU

价格:¥15.2373

现货:17,600

品牌:SILICON LABS

品类:8位MCU

价格:¥22.0197

现货:17,250

品牌:SILICON LABS

品类:8位MCU

价格:¥7.6187

现货:15,742

品牌:SILICON LABS

品类:8位MCU

价格:¥6.5040

现货:15,000

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

现货市场

查看更多

品牌:SILICON LABS

品类:8位MCU

价格:¥4.9000

现货:12,000

品牌:SILICON LABS

品类:Mixed-Signal MCU

价格:¥10.1700

现货:10,000

品牌:SILICON LABS

品类:Mixed-Signal MCU

价格:¥11.1200

现货:1,201

品牌:SILICON LABS

品类:8位MCU

价格:¥56.0000

现货:550

品牌:SILICON LABS

品类:8 BIT MCU

价格:¥16.8500

现货:550

品牌:SILICON LABS

品类:8位MCU

价格:¥5.1900

现货:396

品牌:SILICON LABS

品类:8位MCU

价格:¥39.8000

现货:266

品牌:SILICON LABS

品类:8 BIT MCU

价格:¥3.7900

现货:1

品牌:RENESAS

品类:16-BIT MCU

价格:¥3.9530

现货:866,395

品牌:RENESAS

品类:MCU

价格:¥5.1500

现货:200,000

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

服务

查看更多

TFT LCD液晶显示屏/模组定制

可定制显示屏的尺寸0.96”~15.6”,分辨率80*160~3840*2160,TN/IPS视角,支持RGB、MCU、SPI、MIPI、LVDS、HDMI接口,配套定制玻璃、背光、FPCA/PCBA。

最小起订量: 1000 提交需求>

IC烧录代工及IC自动化烧录

拥有IC烧录机20余款,100余台设备,可以烧录各种封装的IC;可烧录MCU、FLASH、EMMC、NAND FLASH、EPROM等各类型芯片,支持WIFI/BT模组PCBA烧录、测试。

最小起订量: 1 提交需求>

查看更多

授权代理品牌:接插件及结构件

查看更多

授权代理品牌:部件、组件及配件

查看更多

授权代理品牌:电源及模块

查看更多

授权代理品牌:电子材料

查看更多

授权代理品牌:仪器仪表及测试配组件

查看更多

授权代理品牌:电工工具及材料

查看更多

授权代理品牌:机械电子元件

查看更多

授权代理品牌:加工与定制

世强和原厂的技术专家将在一个工作日内解答,帮助您快速完成研发及采购。
我要提问

954668/400-830-1766(工作日 9:00-18:00)

service@sekorm.com

平台客服
服务热线

联系我们

954668/400-830-1766(工作日 9:00-18:00)

service@sekorm.com

投诉与建议

E-mail:claim@sekorm.com

商务合作

E-mail:contact@sekorm.com

收藏
收藏当前页面