这个话题之前发过, 但是好像很多人没有明白当中的原理. 不停地有人问我, 加上Dave这工具虽然好用, 但是小毛病其实不少, 尤其是几种特殊情况撞在一起了, 不用例子说明好难理解. 所以再来发一贴分享下使用Dave定位HardFault的一个过程.
首先要讲的是XMC1系列的MCU没有按照ARM公司的初衷来设计,具体表现是HardFault以及之下的Exception不是真正的向量式设计. XMC4纠正了这一不规范的行为. TLE等其他英飞凌公司的Cortex M系列的MCU都没有这问题. 这个严格来讲不是bug, 但是毫无意义的给程序员添堵. 如果你要使用XMC1系列的MCU, 调试HardFault的时候不得不把这个差异了解透, 但是这个知识在其他Cortex M的MCU上用不着. 非常D疼, 也没有办法.
按照向量式的的设计, Flash的向量表中都存放的ISR的函数指针, 比如另外一家的Cortex M0的向量表(没有贴完全,但可以说明问题):
__Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler ; SVCall Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD PendSV_Handler ; PendSV Handler DCD SysTick_Handler ; SysTick Handler
XMC1系列的向量表:
.align 1 .thumb_func .weak Default_handler .type Default_handler, %function Default_handler: b . .size Default_handler, . - Default_handler Insert_ExceptionHandler HardFault_Handler Insert_ExceptionHandler SVC_Handler Insert_ExceptionHandler PendSV_Handler Insert_ExceptionHandler SysTick_Handler
/* A couple of macros to ease definition of the various handlers */ .macro Insert_ExceptionHandler Handler_Func .weak Handler_Func .thumb_set Handler_Func, Default_handler .endm
.globl HardFault_Veneer HardFault_Veneer: MOVS r0, #4 MOV r1, LR TST r0, r1 BEQ stacking_used_MSP MRS R0, PSP // first parameter - stacking was using PSP B get_LR_and_branch stacking_used_MSP: MRS R0, MSP // first parameter - stacking was using MSP get_LR_and_branch: MOV R1, LR // Second parameter is LR current value LDR R2,=HardFault_Handler BX R2 .long 0 .long 0
最后为什么要放两个.long 0?
因为XMC1系列的MCU:
除了Reset也就是上电复位这个向量是在Flash当中, 其余向量都在固定的SRAM中. 所以汇编语言写的Handler不能超过所留的固定位置. 幸亏Cortex M0只有HardFault这一个Fault, 所以留的空间有一点.可以完成上面的Hard Fault的预处理.
因为Cortex M0的指令集又有16bit的Thumb,又有几个32bit的Thumb2指令, 这里的处理非常讨厌. 之所以增加两个.long 0是要最后生成的map文件这样:
*(.XmcVeneerCode) .XmcVeneerCode 0x2000000c 0x110 ./Startup/startup_XMC1100.o 0x2000000c HardFault_Veneer 0x2000002c SVC_Veneer
也就是HardFault_Veneer必须在0x2000000C, SVC_Veneer必须在0x2000002C. 如果汇编的Hard Fault的预处理代码超过了0x20个Byte, 那么要么你不用SVC这个Exception,要么就得压缩你的代码.
只有注册用户才能在此添加评论。 如果您已经注册,请登录。 如果您还没有注册,请注册并登录。