hardfault问题分析解决及记一次ucosIII环境下的hardfault解决

这里写自定义目录标题

背景

hardfault嵌入式开发中算是比较常见的问题了,前几天正好遇到了一次,虽然比较简单,网上资料也很多,不过自己还是做个review分析总结下方法吧。

环境

板子103+ucosIII,多任务环境,跑着跑着进hardfault。

分析

hardfault主要有两方面的原因:
1、内存溢出或者访问越界,或者直接使用未分配空间的指针。(代码逻辑)
2、堆栈溢出。(调整堆栈大小)
如何排查则可根据hardfalut函数打断点查看寄存器及call stack。这样可以基本了解hardfalut产生的环境
在这里插入图片描述
查看调用堆栈
在这里插入图片描述
寄存器主要看LR寄存器及MSP(Main_Stack_Pointer )及PSP(Process_Stack_Pointer)两个堆栈指针。
直接说结论,hardfault时,LR寄存器0xFFFF_FFF9使用的是MSP,LR寄存器0xFFFF_FFFD使用的是PSP.
MSP和PSP存储着程序未发生hardfalut时的现场环境,根据堆栈中的PC指针可得发生hardfault的代码位置。堆栈先入后出,所以是堆栈之中的第七个寄存器为pc。
在这里插入图片描述
在这里插入图片描述

举例

例程,对空指针直接赋值。

int main(void){
	
    OS_ERR err;	
	OSInit(&err);
	BSP_Init();		                                        
	OSTaskCreate((OS_TCB     *)&AppTaskStartTCB,                // ÈÎÎñ¿ØÖÆ¿éÖ¸Õë          
               (CPU_CHAR   *)"App Task Start",		                // ÈÎÎñÃû³Æ
               (OS_TASK_PTR )Task_Start, 	                // ÈÎÎñ´úÂëÖ¸Õë
               (void       *)0,			                      // ´«µÝ¸øÈÎÎñµÄ²ÎÊýparg
               (OS_PRIO     )STARTUP_TASK_PRIO,			      // ÈÎÎñÓÅÏȼ¶
               (CPU_STK    *)&AppTaskStartStk[0],	            // ÈÎÎñ¶ÑÕ»»ùµØÖ·
               (CPU_STK_SIZE)STARTUP_TASK_STK_SIZE/10,	  // ¶ÑջʣÓྯ½äÏß
               (CPU_STK_SIZE)STARTUP_TASK_STK_SIZE,			  // ¶ÑÕ»´óС
               (OS_MSG_QTY  )0,			                      // ¿É½ÓÊÕµÄ×î´óÏûÏ¢¶ÓÁÐÊý
               (OS_TICK     )0,			                      // ʱ¼äƬÂÖתʱ¼ä
               (void       *)0,			                      // ÈÎÎñ¿ØÖÆ¿éÀ©Õ¹ÐÅÏ¢
               (OS_OPT      )(OS_OPT_TASK_STK_CHK | 
                              OS_OPT_TASK_STK_CLR),	      // ÈÎÎñÑ¡Ïî
               (OS_ERR     *)&err);		                    // ·µ»ØÖµ
	  
  OSStart(&err);                                       
}
void Task_Start(void *p_arg)
{
	OS_ERR err;
	u8 *p;
	IWDG_Init();	
 	*p = 10;  //对未指定地址的指针赋值会hardfalut
	while(DEF_ON)
	{
		IWDG_ReloadCounter();		
		//		printf("喂狗1\r\n");
        OSTimeDlyHMSM(0, 0,1,0,OS_OPT_TIME_HMSM_STRICT,&err);	//ÑÓʱ×èÈû1000ms
		IWDG_ReloadCounter();		
        OSTimeDlyHMSM(0, 0,1,0,OS_OPT_TIME_HMSM_STRICT,&err);
	}
}

进入hardfault,call stack显示如下
在这里插入图片描述
因为我们是任务内的局部指针赋值问题,所以查看call stack及参数传参没有什么太多有用的信息。
寄存器信息如下
在这里插入图片描述
LR 0XFFFFFFFD,说明使用的是PSP寄存器存储现场环境,查看PSP栈顶指针0X20008DA4,找到栈顶7个寄存器PC为0x8023516,说明如果未发生异常下一步将执行0x8023516处的代码。
在这里插入图片描述

然后至Disassembly Windows跳转0x8023516,根据下图可知道将执行IWDG_ReloadCounter(); 时发生hardfault,即 执行*P =10;导致hardfault。在这里插入图片描述

分析

回到我生产环境的程序,按分析过程,打断点,查看发生hardfault的现场环境。
call stack
在这里插入图片描述
可以看到一个局部变量 任务控制块指针异常了,正常ram范围0x20000000起,这种一般来说基本可以考虑任务堆栈大小是否合适了,基本可以就不是代码逻辑问题。调大堆栈后使用ucos自带的堆栈检测函数。

//打开宏定义开关
#define OS_CFG_STAT_TASK_STK_CHK_EN     1u   /* Check task stacks from statistic task      */   
		{
			CPU_STK_SIZE free,used;
			OSTaskStkChk (&CTRL_TCB,&free,&used,&err);
			printf("use/free:%d/%d,%%%d\r\n",used,free,(used*100)/(used+free));
		}

将任务堆栈由80改为160后,正常无hardfault,并且堆栈占用也显示,之前堆栈确实太小了,本身该任务功能很简单,所以之前也设的比较小,但功能一直增加,堆栈需求也在逐渐增加,对于这种问题建议另开一个任务监控自己的其他任务的堆栈使用情况。
在这里插入图片描述

小结

就此,问题解决。

另外附带一句与文无关的牢骚:写博客真是比较费心的事,特别在自己心情十分糟糕的情况,心烦意乱言之无物。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值