在《Cortex-M3开发经验(二):确认发生HardFault的地方》中,咱们提到如何查找出错地方。可是这有一个问题,就是必须连接调试器。那么在某些状况下,咱们没法链接调试器,那么就没法读取到栈信息了吗?咱们能够在进入HardFault时,获取栈指针,而后经过串口的方式打印出来吗?函数
说干就干,有好的想法,也必须有实际的行动验证本身的想法。ui
卡住咱们的第一个问题就是如何获取栈指针了。就是如何获取SP,MSP(主堆栈指针),PSP(进程堆栈指针)的值了。指针
在《Cortex-M3权威指南》中,有这么一段话:CM3微控制器内核中共有两个堆栈指针,因而也就是支持两个堆栈,当引用R13(写做SP)时,引用到的是当前正在使用的那一個(MSP或PSP),另外一个必须用特殊的指令来访问(MRS和MSR指令)。调试
也就是说,咱们须要用汇编的指令来获取栈指针。code
uint32_t get_msp_addr() { __asm("mrs r0, msp"); __asm("bx lr"); } uint32_t get_psp_addr() { __asm("mrs r0, psp"); __asm("bx lr"); } uint32_t get_sp_addr() { __asm("mov r0, sp"); __asm("bx lr"); }
注:每一个编译器所支持C嵌入汇编的方式不一样,也可能一些编译器不支持__asm指令。进程
uint32_t reg_buff[10]; uint32_t *sp = NULL; void HardFault_Handler() { sp = (uint32_t*)get_msp_addr(); reg_buff[0] = *(sp++); reg_buff[1] = *(sp++); reg_buff[2] = *(sp++); reg_buff[3] = *(sp++); reg_buff[4] = *(sp++); reg_buff[5] = *(sp++); reg_buff[6] = *(sp++); reg_buff[7] = *(sp++); reg_buff[8] = *(sp++); reg_buff[9] = *(sp++); while(1){} }
编译,运行!开发
结果有点意料以外!get
LR的值和PC的值跟咱们以前单步调试的不同!偏移了12个字节。为何?后面单步看了一下后发现,咱们在HardFault中调用了get_msp_addr这个函数,而调用函数就意味着使用栈空间。若是我把reg_buff放到HardFault中,这样就不止偏移12个字节了!编译器
有没有更好的方法啊!?io
咱们在进入HardFault_Handler函数以前就获取SP指针的值,并做为参数传入到HardFault_Handler中不就能够了吗?
要解决上面的问题,咱们就须要知道内核在哪里调用中断函数的,这样咱们才能修改对应的中断处理函数,使其能够接收参数。
《Cortex-M3开发经验(二):确认发生HardFault的地方》中,咱们提到过,在发生中断/异常时,内核会去中断向量表中找到对应的中断,找到中断的入口地址。那么咱们就看看中断向量表在哪?
最终,在startup_xxx.S文件中找到了向量表的定义1。咱们也找到了HardFault_Handler的定义
.weak HardFault_Handler .type HardFault_Handler, %function HardFault_Handler: B .
虽然可能不了解汇编,不知道什么意思,但也能猜想出大概的意思,也可能查资料。发现B是跳转指令,这应该就是跳转到同名的C函数中。那么咱们能够修改成:
.weak HardFault_Handler .type HardFault_Handler, %function HardFault_Handler: MOV r0, lr MOV r1, sp BL hardfault_handler
这样就吧LR的值和SP的值传入到hardfault_handler函数中去了2。
编译,运行!
此次的结果就是咱们想要的了。