繁体   English   中英

从Cortex M0 +的硬故障中恢复

[英]Recover from Hard Fault on Cortex M0+

到目前为止,我在向量表中定义了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
....
....
....

我们的一项测试通过写入不存在的地址触发了有意的硬故障。 测试完成后,处理程序将返回到调用函数,并且皮质将从故障中恢复。 值得一提的是处理程序没有任何参数。

现在,我正在编写一个真正的处理程序。 我为堆栈框架创建了一个结构,以便在出现故障的情况下可以打印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的bit [2],因为我确实知道我使用MSP而不是PSP。

该程序可以编译并正常运行,我使用JTAG来确保所有寄存器都恢复为所需值。 当执行最后一条命令( MOV PC, R5 )时,PC返回正确的地址,但是在某些时候,调试器指示M0锁定在硬故障中并且无法恢复。

我不理解使用C函数作为处理程序或调用C函数的汇编函数之间的区别。

有谁知道这是什么问题?

最终,我将使用将卡住处理器的assert函数,但是我希望它是可选的,并由我决定。

解释“ 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 M 3手册,您必须通过将三个EXC_RETURN值之一写入PC寄存器来退出异常处理程序。

如果您只是跳转到存储在堆栈帧中的LR值,则将保留在异常处理程序中!

如果在程序执行过程中发生了一些愚蠢的事情,CPU将假定异常处理程序内部发生了异常并挂起。

在这一点上,我假设Cortex M 0与M 3的工作方式相同。

如果要在异常处理程序期间修改某些CPU寄存器,则可以修改堆栈框架。 当您将EXC_RETURN值写入PC寄存器时,CPU将自动从堆栈帧pop所有寄存器。

如果要修改堆栈帧中不存在的寄存器之一(例如R5 ),则可以在异常处理程序中直接对其进行修改。

这显示了您的中断处理程序的另一个问题:

POP {R0-R7}指令会将寄存器R4R7设置为与已中断程序匹配的值。 R12也将根据C代码被销毁。 这意味着在被中断的程序中,这四个寄存器突然更改,而程序没有为此做好准备!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM