调试必备,一个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:}
谢谢分享,比较实用 好东西 MARK 谢谢楼主,mark!!! 谢谢楼主分享!!! UI是用什么做的? 谢谢分享,学习了。
但是有一点疑问,没看明白stack[]是从哪里获得的。
谢谢分享, 收藏备用。 之前一直是看LR,LR无法追踪就自猜或反复调试。 MARK{:victory:} 谢谢分享 谢谢分享 请问楼主原文地址你是怎么找到的? mark一下 谢谢分享,非常实用,如果能把在哪个函数的第几行打印出来,就更好啦:) 谢楼主分享! dalarang 发表于 2016-2-25 09:02
谢谢分享,学习了。
但是有一点疑问,没看明白stack[]是从哪里获得的。
函数调用的时候会把关键寄存器放到堆栈里面,函数退出后在恢复到寄存器中。
堆栈压入顺序即 R0 ~ R3 ...,那根传递的参数有毛关系呢,arm编译器约定函数调用的参数在R0寄存器,这里使用堆栈中R0寄存器的地址作为索引。
不知道表达的请不清晰。。。。 没有试过,看着是个好东西 好东西,多谢分享 谢谢楼主分享! 看起来不错,比我做的简单多了。分享快乐 ghostxdy 发表于 2016-2-25 08:58
UI是用什么做的?
emWin,启用皮肤就是这个效果 liyang121316 发表于 2016-2-25 09:54
请问楼主原文地址你是怎么找到的?
人在国外,平时都习惯用Google。
还有就是因为GFW上国内网太慢。。。。{:sweat:} 谢谢楼主,好资料! MasterPhi 发表于 2016-2-25 15:41
人在国外,平时都习惯用Google。
还有就是因为GFW上国内网太慢。。。。...
了解!!!你在国外上学还是工作?嵌入式行业怎么样? 这确实是个好方法,只不过原文作者也不是原创的,我早在09年就在墙外找到这种方法并发在本坛了,可惜后来论坛转换服务器后多了很多乱码看不清楚了。前两年在STM32的技术支持网站上也看到过介绍这种方法中文文章,印象中后来的RT-Thread上也有这种处理。
09年发的原贴子:http://www.amobbs.com/thread-2013982-1-1.html {:handshake:}{:handshake:}{:handshake:} 楼主,你的代码在746里面编译会出错, 谢谢分享,好东西支持一个 很不错,谢谢分享! Elex 发表于 2016-2-25 17:04
这确实是个好方法,只不过原文作者也不是原创的,我早在09年就在墙外找到这种方法并发在本坛了,可惜后来论 ...
一直没看过Rtt的详细代码,平时偶尔用用,原来也是这样的。我当时为了找故障,也是在.s文件里写了段代码从堆栈里把PC找到打出来。看是哪个函数出的错。 编译遇到这个错误,不知道咋回事 mark: HardFault_Handler处理代码 涵潇舒雅 发表于 2016-2-25 21:00
编译遇到这个错误,不知道咋回事
你把_asm里面的分开3行写试试,我用的iar {:handshake:}很实用的资料,谢谢分享了 学习了,以前遇到过的问题!
东西不错 楼主USB bootloader程序是否可以共享下。 谢谢分享,好东西 这个不错,查问题方便 非常好,多谢LZ共享! 我也想要usb bootloader,既然秀了就要shareshare 感谢分享,以前调HardFault折腾了好久 相当赞!谢谢分享! cdtlzhou 发表于 2016-2-29 12:00
相当赞!谢谢分享!
你能编译通过吗? 今天有时间,试了一下楼主的代码,确实编译不过。 Mark一下,虽然现在看不懂,但我相信终有一天可以看懂!!! pldjn 发表于 2016-4-21 11:50
今天有时间,试了一下楼主的代码,确实编译不过。
我用的IAR 7.50,其他的编译器内嵌汇编的语法可能不同。 大神,高级的玩意,村底层的东西,老有用了。! 不错 谢谢分享, 收藏备用。 这个我也要试试,每次hardfault都找不到北{:mad:} 可以更直观地显示硬件错误类型,很方便! 直接copy到工程里了 哈哈 mark一下 iar 需要设置吗?没有打印出来 lihaimeng@163 发表于 2016-8-25 14:17
iar 需要设置吗?没有打印出来
ITM介绍
ITM需要swd方式,并且需要接swo,是不是这个问题引起的 7802848 发表于 2016-8-25 14:50
ITM介绍
多设置了,没效果,设置了SWO, 用标准的JTAG口内部已经连接了SWO,还是不行
lihaimeng@163 发表于 2016-8-25 15:18
多设置了,没效果,设置了SWO, 用标准的JTAG口内部已经连接了SWO,还是不行
...
semihost retarget
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);
}
还是没效果 真的是好东西啊, 7802848 发表于 2016-8-25 15:23
semihost retarget
已经可以了,是硬件问题,开发板上SWO接了芯片,所以通讯可能不正常了,换了stm32
discover 就可以了,谢谢 这方法确实不错,多谢楼主 硬件错误的处理代码,不错 __ASM volatile("BKPT #01");这句话是什么意思 IAR中编译不过 碰到比较少,但是很有用 推荐尝试下 CmBacktrace ,一款 开源 的 针对 ARM Cortex-M 系列的 MCU 错误追踪库 https://github.com/armink/CmBacktrace ,支持追踪各种 hardfault sunnydragon 发表于 2017-8-24 21:44
推荐尝试下 CmBacktrace ,一款 开源 的 针对 ARM Cortex-M 系列的 MCU 错误追踪库 https://github.com/arm ...
使用中硬件上需要具备哪些条件 还有那个addr2line是怎么用的 看看学习了 涵潇舒雅 发表于 2016-2-25 21:00
编译遇到这个错误,不知道咋回事
你编译通过了吗?我的和你一样。 最新版IAR已经有了异常原因分析功能 mark:调试必备,一个HardFault_Handler处理代码 mark 一下 谢谢分享, 收藏备用。 兄弟这句通不过__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
兄弟为什么我这个输出查看的窗口没有东西显示,网上找了一圈别人也有这样问题,照他们的方法也不行
是不是需要完整的jtag接口,才行,我现在只用swo接口的2条线 cnxh 发表于 2023-3-13 08:45
兄弟为什么我这个输出查看的窗口没有东西显示,网上找了一圈别人也有这样问题,照他们的方法也不行
...
(引用自75楼)
没有SWO的话得配置其他底层输出的方法,比如说RTT
硬件错误的处理代码
页:
[1]