STM32异常定位方法

时间:2024-04-03 12:47:46

       当单片机发生程序异常时,会进入到HardFault_Handler中断,相当于windows的蓝屏,我现在介绍的是如何获取中断位置,并自动记录异常位置(我的做法是将异常的时间,与代码地址存储到备份区,这样哪怕重启了依旧可以查询上一次发生异常的位置,这部分代码需要自己去实现,我现在实现的是获取异常代码位置)。

 

原理如下:当异常时,硬件会将一些CPU的寄存器保存到栈中,通过在异常时获取堆栈指针SP的值,通过SP获取当前栈的位置,然后获取异常之前的PC指针的值,就知道异常的位置了。

//这个就是CPU寄存器在栈中的排列
//栈数据定义
typedef struct
{
	u32 R0;
	u32 R1;
	u32 R2;
	u32 R3;
	u32 R12;
	u32 LR;
	u32 PC;
	u32 xPSR;
}STACK_DATA_TYPE;


//获取当前CPU堆栈指针
__asm u32 getSP(void) 
{
    mrs r0, msp
	bx lr
}



//硬件中断-可以打印出压栈的CPU寄存器值,包括PC指针(也就是异常位置)
void HardFault_Handler (void)
{
	u32 addr = getSP();		//获取线程模式下堆栈指针位置
	STACK_DATA_TYPE *p;		//堆栈中存储的数据
	
	uart_printf_enable();											//开启串口调试信息
	uart_printf("\r\n-----------------ERROR -----------------\r\nHardFault_Handler\r\n");
	

	if((addr >> 20) != 0x200)		//判断地址范围,必须是0x200xxxxx 范围
	{
		uart_printf("警告:堆栈指针被破坏,无法记录现场!\r\n");
		return;
	}
	addr += 8;					//进入中断后,堆栈又进入了2个u32数据,因此需要往后推
	p = (STACK_DATA_TYPE *)addr;
	uart_printf("R0:0x%08X\r\n", p->R0);
	uart_printf("R1:0x%08X\r\n", p->R1);
	uart_printf("R2:0x%08X\r\n", p->R2);
	uart_printf("R3:0x%08X\r\n", p->R3);
	uart_printf("R12:0x%08X\r\n", p->R12);
	uart_printf("LR:0x%08X\r\n", p->LR);
	uart_printf("PC:0x%08X\r\n", p->PC);
	uart_printf("xPSR:0x%08X\r\n", p->xPSR);


	
	Delay_MS(10); 
	SYSTEM_SoftReset();//复位重启	
}

可以自己将PC指针的值存储到备份区,这样可以查询到产品是否发生过异常,并且异常位置,通过代码仿真可以找到异常代码位置。

STM32异常定位方法

异常前CPU寄存器数据

 

STM32异常定位方法

异常后,通过堆栈指针获取到堆栈中的数据,存放有异常前的PC指针,也就是异常位置。

 

获取了PC指针就能定位位置了

STM32异常定位方法

STM32异常定位方法

STM32异常定位方法

串口输出的异常前CPU寄存器数据