从Cortex M0 +上的硬故障中恢复
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从Cortex M0 +上的硬故障中恢复相关的知识,希望对你有一定的参考价值。
到目前为止,我在C中有一个我在向量表中定义的硬故障处理程序:
.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
....
....
....
我们的一个测试通过写入非现有地址来触发硬故障(故意)。测试完成后,处理程序返回调用函数,皮质从故障中恢复。值得一提的是处理程序没有任何参数。
现在我正在编写一个真正的处理程序。我为堆栈框架创建了一个结构,以便我们可以在出现故障时打印PC,LR和xPSR:
typedef struct
{
int R0 ;
int R1 ;
int R2 ;
int R3 ;
int R12 ;
int LR ;
int ReturnAddress ;
int xPSR ;
} InterruptStackFrame_t ;
我在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)
*/
}
我创建了一个汇编函数:
.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
这是说我没有操作系统的正确时间,所以我不必检查LR的位[2],因为我肯定知道我使用MSP而不是PSP。
程序编译并正常运行,我使用JTAG确保所有寄存器恢复到所需的值。当执行最后一个命令(MOV PC, R5
)时,PC返回到正确的地址,但在某些时候,调试器指示M0被锁定在硬故障中并且无法恢复。
我不明白使用C函数作为处理程序或调用C函数的汇编函数之间的区别。
有谁知道这是什么问题?
最终,我将使用一个会阻塞处理器的断言函数,但我希望它是可选的,取决于我的决定。
解释“old_timer”的评论:
在Cortex上输入异常或中断处理程序时,LR寄存器具有特殊值。
通常,您只需跳转到该值(通过将该值写入PC寄存器)从异常处理程序返回。
然后,Cortex CPU将自动弹出堆栈中的所有寄存器,并重置中断逻辑。
当直接跳转到存储在堆栈中的PC时,你会破坏一些寄存器而你不会恢复中断逻辑。
因此,这不是一个好主意。
相反,我会做这样的事情:
.thumbfunc _hard_fault_wrapper
_hard_fault_wrapper: .asmfunc
MRS R0, MSP
B Hard_Fault
编辑
使用B
指令可能不起作用,因为B
指令允许的“距离”比BL
指令更有限。
但是你可以使用两种可能性(不幸的是我不确定这些是否肯定会有效)。
第一个将返回到进入汇编程序处理程序时在LR
寄存器中传递的地址:
.thumbfunc _hard_fault_wrapper
_hard_fault_wrapper: .asmfunc
MRS R0, MSP
PUSH {LR}
BL Hard_Fault
POP {PC}
第二个将间接进行跳转:
.thumbfunc _hard_fault_wrapper
_hard_fault_wrapper: .asmfunc
MRS R0, MSP
LDR R1, =Hard_Fault
MOV PC, R1
编辑2
您不能使用LR,因为它包含EXC_RETURN值。 ...你必须从堆栈中读取LR,并且必须从堆栈帧中清除堆栈,因为被中断的程序不知道存储了帧。
根据Cortex M3手册,您必须通过将三个EXC_RETURN值中的一个写入PC寄存器来退出异常处理程序。
如果您只是跳转到存储在堆栈帧中的LR
值,您将保留在异常处理程序中!
如果在程序期间发生了一些愚蠢的事情,CPU将假定异常处理程序内发生异常并且它会挂起。
我假设Cortex M0在这一点上与M3的工作方式相同。
如果要在异常处理程序期间修改某些CPU寄存器,可以修改堆栈帧。当您将EXC_RETURN值写入pop
寄存器时,CPU将自动PC
堆栈帧中的所有寄存器。
如果要修改堆栈框架中不存在的寄存器之一(例如R5
),可以在异常处理程序中直接修改它。
这显示了中断处理程序的另一个问题:
指令POP {R0-R7}
将寄存器R4
设置为R7
,使其值与已被中断的程序不匹配。根据C代码,R12
也将被销毁。这意味着在程序被中断时,这四个寄存器突然改变,而程序没有为此做好准备!
以上是关于从Cortex M0 +上的硬故障中恢复的主要内容,如果未能解决你的问题,请参考以下文章