[英]Recover from Hard Fault on Cortex M0+
Until now I had a Hard fault handler in C that I defined in the vector table: 到目前为止,我在向量表中定义了C语言的Hard Fault处理程序:
.sect ".intvecs"
.word _top_of_main_stack
.word _c_int00
.word NMI
.word Hard_Fault
.word Reserved
.word Reserved
.word Reserved
.word Reserved
.word Reserved
.word Reserved
.word Reserved
.word Reserved
.word Reserved
.word Reserved
.word Reserved
.word Reserved
....
....
....
One of our tests triggers a hard fault (on purpose) by writing to a non existing address. 我们的一项测试通过写入不存在的地址触发了有意的硬故障。 Once the test is done, the handler returns to the calling function and the cortex recovers from the fault.
测试完成后,处理程序将返回到调用函数,并且皮质将从故障中恢复。 Worth mentioning that the handler does not have any arguments.
值得一提的是处理程序没有任何参数。
Now I'm in the phase of writing a real handler. 现在,我正在编写一个真正的处理程序。 I created a struct for the stack frame so we can print PC, LR, and xPSR in case of a fault:
我为堆栈框架创建了一个结构,以便在出现故障的情况下可以打印PC,LR和xPSR:
typedef struct
{
int R0 ;
int R1 ;
int R2 ;
int R3 ;
int R12 ;
int LR ;
int ReturnAddress ;
int xPSR ;
} InterruptStackFrame_t ;
My hard fault handler in C is defined: 我在C中的硬故障处理程序定义为:
void Hard_Fault(InterruptStackFrame_t* p_stack_frame)
{
// Write to external memory that I can read from outside
/* prints a message containing information about stack frame:
* p_stack_frame->LR, p_stack_frame->PC, p_stack_frame->xPSR,
* (uint32_t)p_stack_frame (SP)
*/
}
I created an assembly function: 我创建了一个汇编函数:
.thumbfunc _hard_fault_wrapper
_hard_fault_wrapper: .asmfunc
MRS R0, MSP ; store pointer to stack frame
BL Hard_Fault ; go to C function handler
POP {R0-R7} ; pop out all stack frame
MOV PC, R5 ; jump to LR that was in the stack frame (the calling function before the fault)
.endasmfunc
This is the right time to say that I don't have an OS, so I do not have to check bit[2] of LR because I definitely know that I use MSP and not PSP. 现在是说我没有操作系统的正确时机,因此我不必检查LR的bit [2],因为我确实知道我使用MSP而不是PSP。
The program compiles and runs properly and I used JTAG to ensure that all registers restore to the wanted values. 该程序可以编译并正常运行,我使用JTAG来确保所有寄存器都恢复为所需值。 When executing the last command (
MOV PC, R5
) the PC returns to the correct address, but at some point, the debugger indicates that the M0 is locked in a hard fault and cannot recover. 当执行最后一条命令(
MOV PC, R5
)时,PC返回正确的地址,但是在某些时候,调试器指示M0锁定在硬故障中并且无法恢复。
I do not understand the difference between using a C function as a handler or an assembly function that calls a C function. 我不理解使用C函数作为处理程序或调用C函数的汇编函数之间的区别。
Does anyone know what is the problem? 有谁知道这是什么问题?
Eventually, I will use an assert function that will stuck the processor, but I want it to be optional and up to my decision. 最终,我将使用将卡住处理器的assert函数,但是我希望它是可选的,并由我决定。
To explain "old_timer"'s comment: 解释“ old_timer”的评论:
When entering an exception or interrupt handler on the Cortex the LR register has a special value. 在Cortex上输入异常或中断处理程序时,LR寄存器具有特殊值。
Normally you return from the exception handler by simply jumping to that value (by writing that value to the PC register). 通常,您可以通过简单地跳转到该值(通过将该值写入PC寄存器)来从异常处理程序中返回。
The Cortex CPU will then automatically pop all the registers from the stack and it will reset the interrupt logic. 然后,Cortex CPU将自动从堆栈中弹出所有寄存器,并将重置中断逻辑。
When directly jumping to the PC stored on the stack however you will destroy some registers and you don't restore the interrupt logic. 但是,当直接跳转到存储在堆栈中的PC时,您将破坏一些寄存器,并且不恢复中断逻辑。
Therefore this is not a good idea. 因此,这不是一个好主意。
Instead I'd do something like this: 相反,我会做这样的事情:
.thumbfunc _hard_fault_wrapper
_hard_fault_wrapper: .asmfunc
MRS R0, MSP
B Hard_Fault
EDIT 编辑
Using the B
instruction may not work because the "distance" allowed for the B
instruction is more limited than for the BL
instruction. 使用
B
指令可能不起作用,因为B
指令所允许的“距离”比BL
指令受到更多的限制。
However there are two possibilities you could use (unfortunately I'm not sure if these will definitely work). 但是,您可以使用两种可能的方法(不幸的是,我不确定这些方法是否一定可以使用)。
The first one will return to the address that had been passed in the LR
register when entering the assembler handler: 进入汇编器处理程序时,第一个将返回到
LR
寄存器中已传递的地址:
.thumbfunc _hard_fault_wrapper
_hard_fault_wrapper: .asmfunc
MRS R0, MSP
PUSH {LR}
BL Hard_Fault
POP {PC}
The second one will indirectly do the jump: 第二个将间接进行跳转:
.thumbfunc _hard_fault_wrapper
_hard_fault_wrapper: .asmfunc
MRS R0, MSP
LDR R1, =Hard_Fault
MOV PC, R1
EDIT 2 编辑2
You cannot use LR because it holds EXC_RETURN value.
您不能使用LR,因为它具有EXC_RETURN值。 ... You have to read the LR from stack and you must clean the stack from the stack frame, because the interrupted program doesn't know that a frame was stored.
...您必须从堆栈中读取LR,并且必须从堆栈帧中清除堆栈,因为被中断的程序不知道已存储帧。
According to the Cortex M 3 manual you must exit from an exception handler by writing one of the three EXC_RETURN values to the PC register. 根据Cortex M 3手册,您必须通过将三个EXC_RETURN值之一写入PC寄存器来退出异常处理程序。
If you simply jump to the LR
value stored in the stack frame you remain in the exception handler! 如果您只是跳转到存储在堆栈帧中的
LR
值,则将保留在异常处理程序中!
If something stupid happens during the program the CPU will assume that an exception happened inside the exception handler and it hangs. 如果在程序执行过程中发生了一些愚蠢的事情,CPU将假定异常处理程序内部发生了异常并挂起。
I assume that the Cortex M 0 works the same way as the M 3 in this point. 在这一点上,我假设Cortex M 0与M 3的工作方式相同。
If you want to modify some CPU register during the exception handler you can modify the stack frame. 如果要在异常处理程序期间修改某些CPU寄存器,则可以修改堆栈框架。 Thc CPU will automatically
pop
all registers from the stack frame when you are writing the EXC_RETURN value to the PC
register. 当您将EXC_RETURN值写入
PC
寄存器时,CPU将自动从堆栈帧pop
所有寄存器。
If you want to modify one of the registers not present in the stack frame (such as R5
) you can directly modify it in the exception handler. 如果要修改堆栈帧中不存在的寄存器之一(例如
R5
),则可以在异常处理程序中直接对其进行修改。
And this shows another problem of your interrupt handler: 这显示了您的中断处理程序的另一个问题:
The instruction POP {R0-R7}
will set registers R4
to R7
to values that do not match the program that has been interrupted. POP {R0-R7}
指令会将寄存器R4
至R7
设置为与已中断程序不匹配的值。 R12
will also be destroyed depending on the C code. R12
也将根据C代码被销毁。 This means that in the program being interrupted these four registers suddenly change while the program is not prepared for that! 这意味着在被中断的程序中,这四个寄存器突然更改,而程序没有为此做好准备!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.