硬汉嵌入式论坛

 找回密码
 立即注册
查看: 889|回复: 4
收起左侧

[有问必答] 在进入异常服务程序后LR被自动更新为EXC_RETURN

[复制链接]

39

主题

127

回帖

244

积分

高级会员

积分
244
发表于 2025-2-18 20:56:19 | 显示全部楼层 |阅读模式
本帖最后由 坚持再坚持 于 2025-2-18 21:07 编辑

在STM32F407的FreeRTOS中,程序运行几天后会进入硬件异常中断,所以在进入“HardFault_Handler”中断时打印 MSP 或 PSP 堆栈中的LR 和PC。
在进入硬件异常中断后,无法获取正确的LR值(LR被更新为EXC_RETURN),进而无法判断是 MSP 还是 PSP!!
这句话怎么理解:“在进入异常服务程序后, LR的值被自动更新为特殊的EXC_RETURN”?
1)假如在RTOS的某一个任务中触发硬件异常中断,则R0-R3、LR、PC等被写入 PSP;
2)进入HardFault_Handler()硬件异常中断函数,LR的值被自动更新为特殊的EXC_RETURN,这里的LR值应该怎么获取??
3)更新后的LR没有执行写入 MSP 的操作,那么代码中的    stack_ptr = (uint32_t *)__get_MSP();                /* 使用主堆栈指针 */
                                                                                     LR = stack_ptr[5];                                          /* 获取EXC_RETURN的值 */
                                                                                      这样写不多吧?

微信截图_20250218205544.png 微信截图_20250218205912.png








回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-2-19 05:58:45 | 显示全部楼层
不建议在硬件异常中断里面定义局部变量,导致还得手动计算下进入异常前,栈空间位置。

然后这计算,可以直接使用MDK的方案就行,可以硬件异常里面什么都不写


apnt209.pdf (1.13MB)
回复

使用道具 举报

39

主题

127

回帖

244

积分

高级会员

积分
244
 楼主| 发表于 2025-2-19 11:03:43 | 显示全部楼层
本帖最后由 坚持再坚持 于 2025-2-19 11:05 编辑
eric2013 发表于 2025-2-19 05:58
不建议在硬件异常中断里面定义局部变量,导致还得手动计算下进入异常前,栈空间位置。

然后这计算,可以 ...


谢谢解答!后续再了解您建议的内容,因为目前这种方式简单易易懂。


int main(void)
{
        a = 调用函数A();                                                        /* 此时 LR 保存的是 函数A返回的地址 */

         volatile uint32_t *pInvalid = (uint32_t*)0xDEADBEEF;  /* 设置一个无效的内存地址 */

         volatile uint32_t value = *pInvalid;                             /* 尝试访问无效地址,将触发硬件异常 */

         /* 此时,进入硬件异常中断,将 LR 的值入栈,但是 LR 的值没有更新,还是函数A的返回地址,则是将函数A的返回地址入栈了 */
         请问,这是什么原因?


}

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-2-19 11:14:55 | 显示全部楼层
坚持再坚持 发表于 2025-2-19 11:03
谢谢解答!后续再了解您建议的内容,因为目前这种方式简单易易懂。

这里你应该用PC才合理,用于指示退出硬件异常下一条要执行的指令
回复

使用道具 举报

39

主题

127

回帖

244

积分

高级会员

积分
244
 楼主| 发表于 2025-2-20 14:24:12 | 显示全部楼层
本帖最后由 坚持再坚持 于 2025-2-20 14:32 编辑


之前发帖的疑问点是没有考虑到:在进入硬件异常中断时,如果在中断函数里面定义了局部变量,则会更新 MSP 的指针,因为局部存储在栈里面。
针对2楼管理员建议的方法,我做了注释说明:(在打印出 PC 和 LR 的值后,可以利用 addr2line.exe 定位具体的代码位置,管理员介绍过:addr2line.exe的使用方法)
__asm void HardFault_Handler(void)      /* __asm放在函数返回类型之前,说明函数体内部是汇编代码,asm是assembly的简写 */
{
    TST    LR, #4                                  /* 这条指令用于测试 LR 寄存器中的第三位(即值4对应的位),通过按位与操作来确定这一位置的值 */
    ITE    EQ                                        /* ITE是 If-The-Else指令。EQ 表示如果上一个指令的结果是零(也就是 TST LR #4 的结果为零,即 LR 的第2位为0),那么执行MRSEQ */
    MRSEQ  R0, MSP                            /* 如果 LR 的第2位为0(即 EQ 条件成立),表示使用的是 MSP,则将 MSP 的值加载到 R0 */
    MRSNE  R0, PSP                             /* 如果 LR 的第2位为1(即 EQ 条件不成立),表示使用的是 PSP,则将PSP的值加载到R0 */
    MOV    R1, LR                                /* 将 LR 寄存器的值复制到 R1 寄存器 */
    B      __cpp(HardFault_Handler_C)   /* B是Branch指令,表示调转到指定的地址;__cpp()是Keil编译器的语法,表示调转到C语言函数。调转时将将 R0 和 R1 的值作为参数传递给HardFault_Handler_C */
}
void HardFault_Handler_C(unsigned long * hardfault_args, unsigned int lr_value)
{
    unsigned long stacked_r0;
    unsigned long stacked_r1;
    unsigned long stacked_r2;
    unsigned long stacked_r3;
    unsigned long stacked_r12;
    unsigned long stacked_lr;
    unsigned long stacked_pc;
    unsigned long stacked_psr;
    unsigned long cfsr;
    unsigned long bus_fault_address;
    unsigned long memmanage_fault_address;
    uint32_t i = 0;

    bus_fault_address               = SCB->BFAR;
    memmanage_fault_address = SCB->MMFAR;
    cfsr                                   = SCB->CFSR;

    stacked_r0  = ((unsigned long) hardfault_args[0]);
    stacked_r1  = ((unsigned long) hardfault_args[1]);
    stacked_r2  = ((unsigned long) hardfault_args[2]);
    stacked_r3  = ((unsigned long) hardfault_args[3]);
    stacked_r12 = ((unsigned long) hardfault_args[4]);
    stacked_lr  = ((unsigned long) hardfault_args[5]);
    stacked_pc  = ((unsigned long) hardfault_args[6]);
    stacked_psr = ((unsigned long) hardfault_args[7]);

    DEBUG_TRACE(255, "[HardFault]\n");
    DEBUG_TRACE(255, "- Stack frame:\n");
    DEBUG_TRACE (255, " R0  = %x\n", stacked_r0);
    DEBUG_TRACE (255, " R1  = %x\n", stacked_r1);
    DEBUG_TRACE (255, " R2  = %x\n", stacked_r2);
    DEBUG_TRACE (255, " R3  = %x\n", stacked_r3);
    DEBUG_TRACE (255, " R12 = %x\n", stacked_r12);
    DEBUG_TRACE (255, " LR  = %x\n", stacked_lr);
    DEBUG_TRACE (255, " PC  = %x\n", stacked_pc);
    DEBUG_TRACE (255, " PSR = %x\n", stacked_psr);
    DEBUG_TRACE (255, "- FSR/FAR:\n");  
    DEBUG_TRACE (255, " CFSR = %x\n", cfsr);
    DEBUG_TRACE (255, " HFSR = %x\n", SCB->HFSR);
    DEBUG_TRACE (255, " DFSR = %x\n", SCB->DFSR);
    DEBUG_TRACE (255, " AFSR = %x\n", SCB->AFSR);
    if (cfsr & 0x0080) DEBUG_TRACE (255, " MMFAR = %x\n", memmanage_fault_address);
    if (cfsr & 0x8000) DEBUG_TRACE (255, " BFAR = %x\n", bus_fault_address);
    DEBUG_TRACE (255, "- Misc\n");
    DEBUG_TRACE (255, " LR/EXC_RETURN= %x\n", lr_value);

    while(1);
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-12 06:27 , Processed in 0.057142 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表