HardFault

HardFault

MSP的含义是Main_Stack_Pointer,即主栈
PSP的含义是 Process_Stack_Pointer,即任务栈

armcortex-m的设计,一共有32个寄存器

13个通用寄存器,r0-r12
1个栈指针寄存器SP(r13),PSP(SP_process)和MSP(SP_main)
1个链接寄存器LR(r14),执行下一级函数自动存放LR压栈,函数返回的时会弹出LR到PC
1个程序计数器PC(r15),指向当前指向的程序地址
1个程序状态寄存器(xPSR)

r0~r3 用作传入函数参数,传出函数返回值。在子程序调用之间,可以将 r0-r3 用于任何用途。被调用函数在返回之前不必恢复 r0-r3。如果调用函数需要再次使用 r0-r3 的内容,则它必须保留这些内容。
r4~r11 被用来存放函数的局部变量。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。
r12 是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 r12。
r13 是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。
r14 是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复
r15 是程序计数器 PC。它不能用于任何其它用途。

注意:在中断程序中,所有的寄存器都必须保护,编译器会自动保护R4~R11

不同的模式下,R0-R12、SP、LR是各有一份的,所以这样算下来,总共是32个寄存器,
但是在不同的模式下,并不能完全看到这32个寄存器的状态,只能看到其中的一部分。

自动压栈处理:xPSR->PC->LR->r12->r3->r2->r1->r0

xPSP寄存器的 bit9被用来指示 SP是否需要对齐,bit9如果为1的话就需要双字对齐
如果为0的话就不需要双字对齐

当触发了PendSV异常进入中断后,系统默认是出于MSP状态的。
当切换任务时,就需要使用PSP作为任务堆栈指针。

一般使用修改LR寄存器的值来改变SP使用MSP还是PSP.

LR =0xFFFFFFF9 使用MSP堆栈指针
LR =0xFFFFFFFD 使用PSP堆栈指针

所以一般PendSV中任务堆栈处理完毕后,需要使用LDR LR,=0xFFFFFFFD
指令进行PSP任务堆栈的选择。再执行BX LR 指令,即可切换到堆栈保存的任务中去

LR寄存器记录函数或子程序调用后的返回地址,若函数又调用了函数或子程序,为了保证LR值不丢失,需要将LR入栈.
在异常处理时LR会被更新为特殊的EXC_RETURN数值。典型的有如下3种值:

0xFFFFFFF1 中断返回时从MSP恢复栈,返回之后操作模式为处理模式,使用MSP栈,即在中断嵌套情况下,返回上一级中断
0xFFFFFFF9 中断返回时从MSP恢复栈,返回之后操作模式为线程模式,使用MSP栈,该情况在只使用MSP不使用PSP时发生
0xFFFFFFFD 中断返回时从PSP恢复栈,返回之后操作模式为线程模式,使用PSP栈,即一般的从中断返回用户线程的情况

参考

GCC下
daplink

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//hexdump logic on hardfault
__USED __NO_RETURN void _fault_handler(uint32_t _lr)
{
uint32_t stk_ptr;
uint32_t * stack = (uint32_t *)__get_MSP();

if ((_lr & 0xF) == 0xD) { //process stack
stack = (uint32_t *)__get_PSP();
}

//calculate stack ptr before fault
stk_ptr = (uint32_t)stack + 0x20;
if ((stack[7] & 0x200) != 0) { //xpsr bit 9 align
stk_ptr += 0x4;
}
if ((_lr & 0x10) == 0) { //fp
stk_ptr += 0x48;
}

config_ram_add_hexdump(_lr); //EXC_RETURN
config_ram_add_hexdump(__get_PSP());
config_ram_add_hexdump(__get_MSP());
config_ram_add_hexdump(__get_CONTROL());
config_ram_add_hexdump(stk_ptr); //SP
config_ram_add_hexdump(stack[5]); //LR
config_ram_add_hexdump(stack[6]); //PC
config_ram_add_hexdump(stack[7]); //xPSR

#if !defined(__CORTEX_M)
#error "__CORTEX_M not defined!!"
#elif (__CORTEX_M > 0x00)
config_ram_add_hexdump(SCB->HFSR);
config_ram_add_hexdump(SCB->CFSR);
config_ram_add_hexdump(SCB->DFSR);
config_ram_add_hexdump(SCB->AFSR);
config_ram_add_hexdump(SCB->MMFAR);
config_ram_add_hexdump(SCB->BFAR);
#endif // __CORTEX_M

util_assert(0);
SystemReset();

while (1); // Wait for reset
}

#if defined(__CC_ARM) // armcc
void HardFault_Handler()
{
register unsigned int _lr __asm("lr");
_fault_handler(_lr);
}
#else // gcc and armclang
void HardFault_Handler()
{
__ASM volatile (
" mov r0, lr \n\t"
" bl _fault_handler \n\t"
);
}
#endif

简易dump

1
2
3
4
5
6
7
8
9
10
11
12
13
14
__USED __NO_RETURN void _fault_handler(uint32_t sp)
{
printf("\narm-none-eabi-addr2line -e _____.elf -a -f %08x\n",((uint32_t *)sp)[6]);
}
void HardFault_Handler(void)
{
__ASM volatile (
" mov r0,sp \n\t"
" bl _fault_handler \n\t"
);
while(1)
{
}
}

其他信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#define SCB_CFSR_MMFSR_IACCVIOL (0x01 << 0)
#define SCB_CFSR_MMFSR_DACCVIOL (0x01 << 1)
#define SCB_CFSR_MMFSR_MUNSTKERR (0x01 << 3)
#define SCB_CFSR_MMFSR_MSTKERR (0x01 << 4)
#define SCB_CFSR_MMFSR_MMARVALID (0x01 << 7)


#define SCB_CFSR_BFSR_IBUSERR (0x01 << (0 + 8))
#define SCB_CFSR_BFSR_PRECISERR (0x01 << (1 + 8))
#define SCB_CFSR_BFSR_IMPRECISERR (0x01 << (2 + 8))
#define SCB_CFSR_BFSR_UNSTKERR (0x01 << (3 + 8))
#define SCB_CFSR_BFSR_STKERR (0x01 << (4 + 8))
#define SCB_CFSR_BFSR_BFARVALID (0x01 << (7 + 8))

#define SCB_CFSR_UFSR_UNDEFINSTR (0x01 << (0 + 16))
#define SCB_CFSR_UFSR_INVSTATE (0x01 << (1 + 16))
#define SCB_CFSR_UFSR_INVPC (0x01 << (2 + 16))
#define SCB_CFSR_UFSR_NOCP (0x01 << (3 + 16))
#define SCB_CFSR_UFSR_UNALIGNED (0x01 << (8 + 16))
#define SCB_CFSR_UFSR_DIVBYZERO (0x01 << (9 + 16))


void FAULT_PrintFaultRegs(void)
{
DBG_SendPolling("MMFSR : %x[%s%s%s%s%s]\r\n",
SCB->CFSR & SCB_CFSR_MEMFAULTSR_Msk,
(0 == (SCB_CFSR_MMFSR_IACCVIOL & SCB->CFSR)) ? "":"IACCVIOL|",
(0 == (SCB_CFSR_MMFSR_DACCVIOL & SCB->CFSR)) ? "":"DACCVIOL|",
(0 == (SCB_CFSR_MMFSR_MUNSTKERR & SCB->CFSR)) ? "":"MUNSTKERR|",
(0 == (SCB_CFSR_MMFSR_MSTKERR & SCB->CFSR)) ? "":"MSTKERR|",
(0 == (SCB_CFSR_MMFSR_MMARVALID & SCB->CFSR)) ? "":"MMARVALID|");

DBG_SendPolling("BFSR : %x[%s%s%s%s%s%s]\r\n",
SCB->CFSR & SCB_CFSR_BUSFAULTSR_Msk,
(0 == (SCB_CFSR_BFSR_IBUSERR & SCB->CFSR)) ? "":"IBUSERR|",
(0 == (SCB_CFSR_BFSR_PRECISERR & SCB->CFSR)) ? "":"PRECISERR|",
(0 == (SCB_CFSR_BFSR_IMPRECISERR & SCB->CFSR))? "":"IMPRECISERR|",
(0 == (SCB_CFSR_BFSR_UNSTKERR & SCB->CFSR)) ? "":"UNSTKERR|",
(0 == (SCB_CFSR_BFSR_STKERR & SCB->CFSR)) ? "":"STKERR|",
(0 == (SCB_CFSR_BFSR_BFARVALID & SCB->CFSR)) ? "":"BFARVALID|");

DBG_SendPolling("UFSR : %x[%s%s%s%s%s%s]\r\n",
SCB->CFSR & SCB_CFSR_USGFAULTSR_Msk,
(0 == (SCB_CFSR_UFSR_UNDEFINSTR & SCB->CFSR)) ? "":"UNDEFINSTR|",
(0 == (SCB_CFSR_UFSR_INVSTATE & SCB->CFSR)) ? "":"INVSTATE|",
(0 == (SCB_CFSR_UFSR_INVPC & SCB->CFSR)) ? "":"INVPC|",
(0 == (SCB_CFSR_UFSR_NOCP & SCB->CFSR)) ? "":"NOCP|",
(0 == (SCB_CFSR_UFSR_UNALIGNED & SCB->CFSR)) ? "":"UNALIGNED|",
(0 == (SCB_CFSR_UFSR_DIVBYZERO & SCB->CFSR)) ? "":"DIVBYZERO|");

DBG_SendPolling("HFSR : %x[%s%s%s]\r\n",
SCB->HFSR,
(0 == (SCB_HFSR_DEBUGEVT_Msk & SCB->HFSR)) ? "":"DEBUGEVT|",
(0 == (SCB_HFSR_FORCED_Msk & SCB->HFSR)) ? "":"FORCED|",
(0 == (SCB_HFSR_VECTTBL_Msk & SCB->HFSR)) ? "":"VECTTBL|");
DBG_SendPolling("DFSR : %x\r\n", SCB->DFSR);
DBG_SendPolling("MMFAR : %x\r\n", SCB->MMFAR);
DBG_SendPolling("BFAR : %x\r\n", SCB->BFAR);
}
-->

请我喝杯咖啡吧~

支付宝
微信