MasterPhi 发表于 2016-2-25 06:21:10

调试必备,一个HardFault_Handler处理代码(非原创)

最近看好几个人做Bootloader被HardFault折磨的不行,我潜水太久太无聊出来冒个泡。

原文地址: Developing a Generic Hard Fault handler for ARM Cortex-M3/Cortex-M4

我看大家进到HardFault_Handler基本都是靠看LR 寄存器进行猜测,有人做了个很好用的HardFault_Handler处理代码,可以直接把错误类型和寄存器内容通过SWO打印出来。
由于ARM在中断的时候会把主要的CPU寄存器自动入栈,所以用这个代码显示出来的结果更精确,尤其是PC跑到0xffffff00左右的情况。

先上个例子,我把PC直接加了0x01000000:



我自从用了以后根本停不下来,直接加到所有工程模板里面了,从Cortex M3 到M7都能用,M0没设备没试过。

不废话了上代码:
/* Private typedef -----------------------------------------------------------*/
enum { r0, r1, r2, r3, r12, lr, pc, psr};
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void Hard_Fault_Handler(uint32_t stack[]);
/* Private functions ---------------------------------------------------------*/
static void printErrorMsg(const char * errMsg)
{
   while(*errMsg != '\0'){
      ITM_SendChar(*errMsg);
      ++errMsg;
   }
}

static void printUsageErrorMsg(uint32_t CFSRValue)
{
   printErrorMsg("Usage fault: \n");
   CFSRValue >>= 16; // right shift to lsb

   if((CFSRValue & (1<<9)) != 0) {
      printErrorMsg("Divide by zero\n");
   }
   if((CFSRValue & (1<<8)) != 0) {
      printErrorMsg("Unaligned access\n");
   }
}

static void printBusFaultErrorMsg(uint32_t CFSRValue)
{
   printErrorMsg("Bus fault: \n");
   CFSRValue = ((CFSRValue & 0x0000FF00) >> 8); // mask and right shift to lsb
}

static void printMemoryManagementErrorMsg(uint32_t CFSRValue)
{
   printErrorMsg("Memory Management fault: \n");
   CFSRValue &= 0x000000FF; // mask just mem faults
}

static void stackDump(uint32_t stack[])
{
   static char msg;
   sprintf(msg, "R0= 0x%08x\n", stack);printErrorMsg(msg);
   sprintf(msg, "R1= 0x%08x\n", stack);printErrorMsg(msg);
   sprintf(msg, "R2= 0x%08x\n", stack);printErrorMsg(msg);
   sprintf(msg, "R3= 0x%08x\n", stack);printErrorMsg(msg);
   sprintf(msg, "R12 = 0x%08x\n", stack); printErrorMsg(msg);
   sprintf(msg, "LR= 0x%08x\n", stack);printErrorMsg(msg);
   sprintf(msg, "PC= 0x%08x\n", stack);printErrorMsg(msg);
   sprintf(msg, "PSR = 0x%08x\n", stack); printErrorMsg(msg);
}

void Hard_Fault_Handler(uint32_t stack[])
{
   static char msg;
   //if((CoreDebug->DHCSR & 0x01) != 0) {
      printErrorMsg("\nIn Hard Fault Handler\n");
      sprintf(msg, "SCB->HFSR = 0x%08x\n", SCB->HFSR);
      printErrorMsg(msg);
      if ((SCB->HFSR & (1 << 30)) != 0) {
         printErrorMsg("Forced Hard Fault\n");
         sprintf(msg, "SCB->CFSR = 0x%08x\n", SCB->CFSR );
         printErrorMsg(msg);
         if((SCB->CFSR & 0xFFFF0000) != 0) {
            printUsageErrorMsg(SCB->CFSR);
         }
         if((SCB->CFSR & 0xFF00) != 0) {
            printBusFaultErrorMsg(SCB->CFSR);
         }
         if((SCB->CFSR & 0xFF) != 0) {
            printMemoryManagementErrorMsg(SCB->CFSR);
         }
      }
      stackDump(stack);
      __ASM volatile("BKPT #01");
   //}
   while(1);
}
/******************************************************************************/
/*            Cortex-M7 Processor Exceptions Handlers                         */
/******************************************************************************/

/**
* @briefThis function handles NMI exception.
* @paramNone
* @retval None
*/
void NMI_Handler(void)
{
}

/**
* @briefThis function handles Hard Fault exception.
* @paramNone
* @retval None
*/
void HardFault_Handler(void)
{
   __asm("TST lr, #4");
   __asm("ITE EQ \n"
         "MRSEQ r0, MSP \n"
         "MRSNE r0, PSP");
   __asm("B Hard_Fault_Handler");
}


最后上几个自己的USB Bootloader的照片{:lol:}


kxb 发表于 2016-2-25 07:56:39

谢谢分享,比较实用

jacky82512 发表于 2016-2-25 08:53:31

好东西 MARK

ltgkl199011 发表于 2016-2-25 08:54:41

谢谢楼主,mark!!!

mega1702 发表于 2016-2-25 08:55:13

谢谢楼主分享!!!

ghostxdy 发表于 2016-2-25 08:58:38

UI是用什么做的?

dalarang 发表于 2016-2-25 09:02:25

谢谢分享,学习了。

但是有一点疑问,没看明白stack[]是从哪里获得的。

zhangxun0712 发表于 2016-2-25 09:07:26


谢谢分享, 收藏备用。

liyang121316 发表于 2016-2-25 09:12:29

之前一直是看LR,LR无法追踪就自猜或反复调试。

xld826 发表于 2016-2-25 09:15:16

MARK{:victory:}

chengsong 发表于 2016-2-25 09:19:29

谢谢分享

sunzhuojun 发表于 2016-2-25 09:32:50

谢谢分享

liyang121316 发表于 2016-2-25 09:54:56

请问楼主原文地址你是怎么找到的?

308594151 发表于 2016-2-25 10:04:10

mark一下

sblpp 发表于 2016-2-25 10:36:15

谢谢分享,非常实用,如果能把在哪个函数的第几行打印出来,就更好啦:)

7nian 发表于 2016-2-25 11:06:05

谢楼主分享!

macaroni 发表于 2016-2-25 11:21:01

dalarang 发表于 2016-2-25 09:02
谢谢分享,学习了。

但是有一点疑问,没看明白stack[]是从哪里获得的。

函数调用的时候会把关键寄存器放到堆栈里面,函数退出后在恢复到寄存器中。

堆栈压入顺序即 R0 ~ R3 ...,那根传递的参数有毛关系呢,arm编译器约定函数调用的参数在R0寄存器,这里使用堆栈中R0寄存器的地址作为索引。

不知道表达的请不清晰。。。。

Michael_STM 发表于 2016-2-25 11:36:23

没有试过,看着是个好东西

aaabbbad 发表于 2016-2-25 11:37:45

好东西,多谢分享

bigwolf-mcu 发表于 2016-2-25 12:48:08

谢谢楼主分享!

pldjn 发表于 2016-2-25 13:17:59

看起来不错,比我做的简单多了。分享快乐

MasterPhi 发表于 2016-2-25 15:40:21

ghostxdy 发表于 2016-2-25 08:58
UI是用什么做的?

emWin,启用皮肤就是这个效果

MasterPhi 发表于 2016-2-25 15:41:34

liyang121316 发表于 2016-2-25 09:54
请问楼主原文地址你是怎么找到的?

人在国外,平时都习惯用Google。
还有就是因为GFW上国内网太慢。。。。{:sweat:}

guaiguaima 发表于 2016-2-25 15:45:55

谢谢楼主,好资料!

liyang121316 发表于 2016-2-25 15:53:06

MasterPhi 发表于 2016-2-25 15:41
人在国外,平时都习惯用Google。
还有就是因为GFW上国内网太慢。。。。...

了解!!!你在国外上学还是工作?嵌入式行业怎么样?

Elex 发表于 2016-2-25 17:04:35

这确实是个好方法,只不过原文作者也不是原创的,我早在09年就在墙外找到这种方法并发在本坛了,可惜后来论坛转换服务器后多了很多乱码看不清楚了。前两年在STM32的技术支持网站上也看到过介绍这种方法中文文章,印象中后来的RT-Thread上也有这种处理。
09年发的原贴子:http://www.amobbs.com/thread-2013982-1-1.html

Excellence 发表于 2016-2-25 17:15:21

{:handshake:}{:handshake:}{:handshake:}

stevenli 发表于 2016-2-25 17:34:58

楼主,你的代码在746里面编译会出错,

weiwei4 发表于 2016-2-25 18:37:50

谢谢分享,好东西支持一个

blxy 发表于 2016-2-25 20:37:08

很不错,谢谢分享!

pldjn 发表于 2016-2-25 20:47:44

Elex 发表于 2016-2-25 17:04
这确实是个好方法,只不过原文作者也不是原创的,我早在09年就在墙外找到这种方法并发在本坛了,可惜后来论 ...

一直没看过Rtt的详细代码,平时偶尔用用,原来也是这样的。我当时为了找故障,也是在.s文件里写了段代码从堆栈里把PC找到打出来。看是哪个函数出的错。

涵潇舒雅 发表于 2016-2-25 21:00:16

编译遇到这个错误,不知道咋回事

kaomantou 发表于 2016-2-25 21:46:49

mark: HardFault_Handler处理代码

MasterPhi 发表于 2016-2-26 00:08:45

涵潇舒雅 发表于 2016-2-25 21:00
编译遇到这个错误,不知道咋回事

你把_asm里面的分开3行写试试,我用的iar

windancerhxw 发表于 2016-2-26 20:51:29

{:handshake:}很实用的资料,谢谢分享了

lijg8421 发表于 2016-2-27 08:43:50

学习了,以前遇到过的问题!

majay123 发表于 2016-2-27 08:54:38

东西不错

hyghyg1234 发表于 2016-2-27 09:03:30

楼主USB bootloader程序是否可以共享下。

Suna 发表于 2016-2-27 09:04:44

谢谢分享,好东西

zchong 发表于 2016-2-27 09:18:42

这个不错,查问题方便

hy2515131 发表于 2016-2-27 09:41:03

非常好,多谢LZ共享!

futurekwong 发表于 2016-2-29 10:12:21

我也想要usb bootloader,既然秀了就要shareshare

cqsrmxxzyx 发表于 2016-2-29 11:48:49

感谢分享,以前调HardFault折腾了好久

cdtlzhou 发表于 2016-2-29 12:00:28

相当赞!谢谢分享!

涵潇舒雅 发表于 2016-4-1 09:39:17

cdtlzhou 发表于 2016-2-29 12:00
相当赞!谢谢分享!

你能编译通过吗?

pldjn 发表于 2016-4-21 11:50:17

今天有时间,试了一下楼主的代码,确实编译不过。

wofei3344 发表于 2016-4-21 13:50:17

Mark一下,虽然现在看不懂,但我相信终有一天可以看懂!!!

MasterPhi 发表于 2016-4-21 14:32:13

pldjn 发表于 2016-4-21 11:50
今天有时间,试了一下楼主的代码,确实编译不过。

我用的IAR 7.50,其他的编译器内嵌汇编的语法可能不同。

jiki119 发表于 2016-4-21 15:14:24

大神,高级的玩意,村底层的东西,老有用了。!

chengying 发表于 2016-6-20 11:20:16

不错                     

leonliu_1128 发表于 2016-6-27 18:00:19

谢谢分享, 收藏备用。

JJKwong 发表于 2016-6-27 18:28:25

这个我也要试试,每次hardfault都找不到北{:mad:}

铁驴不倒! 发表于 2016-6-28 14:01:27

可以更直观地显示硬件错误类型,很方便! 直接copy到工程里了 哈哈

308594151 发表于 2016-6-28 17:49:53

mark一下

lihaimeng@163 发表于 2016-8-25 14:17:09

iar 需要设置吗?没有打印出来

7802848 发表于 2016-8-25 14:50:25

lihaimeng@163 发表于 2016-8-25 14:17
iar 需要设置吗?没有打印出来

ITM介绍


ITM需要swd方式,并且需要接swo,是不是这个问题引起的

lihaimeng@163 发表于 2016-8-25 15:18:32

7802848 发表于 2016-8-25 14:50
ITM介绍




多设置了,没效果,设置了SWO, 用标准的JTAG口内部已经连接了SWO,还是不行

7802848 发表于 2016-8-25 15:23:10

lihaimeng@163 发表于 2016-8-25 15:18
多设置了,没效果,设置了SWO, 用标准的JTAG口内部已经连接了SWO,还是不行
...

semihost retarget

lihaimeng@163 发表于 2016-8-25 15:36:12

7802848 发表于 2016-8-25 15:23
semihost retarget

放了,

#define ITM_Port8(n)    (*((volatile unsigned char *)(0xE0000000+4*n)))
#define ITM_Port16(n)   (*((volatile unsigned short*)(0xE0000000+4*n)))
#define ITM_Port32(n)   (*((volatile unsigned long *)(0xE0000000+4*n)))
#define DEMCR         (*((volatile unsigned long *)(0xE000EDFC)))
#define TRCENA          0x01000000

struct __FILE { int handle; /* Add whatever you need here */ };
    FILE __stdout;
    FILE __stdin;
   
int fputc(int ch, FILE *f)
{
    if (DEMCR & TRCENA)
    {
      while (ITM_Port32(0) == 0);
      ITM_Port8(0) = ch;
    }
    return(ch);
}


还是没效果

ckhf 发表于 2016-8-25 16:46:23

真的是好东西啊,

lihaimeng@163 发表于 2016-8-26 09:21:03

7802848 发表于 2016-8-25 15:23
semihost retarget

已经可以了,是硬件问题,开发板上SWO接了芯片,所以通讯可能不正常了,换了stm32
discover 就可以了,谢谢

浮生莫若闲 发表于 2016-8-26 11:03:56

这方法确实不错,多谢楼主

zhangxwnoah 发表于 2016-8-26 13:39:19

硬件错误的处理代码,不错

justdomyself 发表于 2017-8-24 14:31:36

__ASM volatile("BKPT #01");这句话是什么意思   IAR中编译不过

xuzhiping9889 发表于 2017-8-24 16:25:51

碰到比较少,但是很有用

sunnydragon 发表于 2017-8-24 21:44:15

推荐尝试下 CmBacktrace ,一款 开源 的 针对 ARM Cortex-M 系列的 MCU 错误追踪库 https://github.com/armink/CmBacktrace ,支持追踪各种 hardfault

justdomyself 发表于 2017-8-24 22:47:24

sunnydragon 发表于 2017-8-24 21:44
推荐尝试下 CmBacktrace ,一款 开源 的 针对 ARM Cortex-M 系列的 MCU 错误追踪库 https://github.com/arm ...

使用中硬件上需要具备哪些条件   还有那个addr2line是怎么用的

caoxuerji 发表于 2017-8-24 23:38:55

看看学习了

fbwcpu 发表于 2018-2-13 11:02:32

涵潇舒雅 发表于 2016-2-25 21:00
编译遇到这个错误,不知道咋回事

你编译通过了吗?我的和你一样。

anjiyifan 发表于 2018-2-13 14:02:29

最新版IAR已经有了异常原因分析功能

windancerhxw 发表于 2018-3-3 10:03:21

mark:调试必备,一个HardFault_Handler处理代码

308594151 发表于 2018-3-4 00:13:17

mark 一下

fangy 发表于 2018-8-8 08:43:37

谢谢分享, 收藏备用。

cnxh 发表于 2022-5-3 17:54:12

兄弟这句通不过__asm("B Hard_Fault_Handler");
错误提示,8多,9多的版本都试过
Error: Unknown symbol in inline assembly: "Hard_Fault_Handler" N:\NewMcuLib\Apply\Algorithm\Apply_HardFault.c 115
Error: Error in inline assembly: "Expression can not be forward" N:\NewMcuLib\Apply\Algorithm\Apply_HardFault.c 115

cnxh 发表于 2023-3-13 08:45:19

兄弟为什么我这个输出查看的窗口没有东西显示,网上找了一圈别人也有这样问题,照他们的方法也不行

cnxh 发表于 2023-3-14 07:24:15

是不是需要完整的jtag接口,才行,我现在只用swo接口的2条线

MasterPhi 发表于 2023-3-14 19:07:42

cnxh 发表于 2023-3-13 08:45
兄弟为什么我这个输出查看的窗口没有东西显示,网上找了一圈别人也有这样问题,照他们的方法也不行
...
(引用自75楼)

没有SWO的话得配置其他底层输出的方法,比如说RTT

waymcu 发表于 2023-3-14 19:16:32


硬件错误的处理代码
页: [1]
查看完整版本: 调试必备,一个HardFault_Handler处理代码(非原创)