基于STM32 的HAL库的boot+app项目,app一直重启问题的解决方案

一、项目概况:

基于STM32F103,使用HAL库进行开发,自己开发设计的boot加app。使用freertos操作系统。

二、问题描述:

app程序中中断向量、程序起始地址等均已经做了正确配置。但是跳转到APP后,程序反复复位重启。


三、具体分析:

调试发现程序卡死在调用HAL_Delay的时候。 uwTick 一直没有更新,所有导致超时后,看门狗复位重启。

SysTick中断无法更新uwTick计数器的根本原因在于ARM Cortex-M内核的中断屏蔽机制(PRIMASK/FAULTMASK)未解除,导致SysTick中断请求(IRQ)或其关联的异常(如SysTick_Handler)无法被内核响应。以下是详细分析:

1. PRIMASK屏蔽全局中断(CPSIE I的作用)

ARM Cortex-M内核通过 PRIMASK 寄存器控制全局中断的使能状态:

        PRIMASK=1:屏蔽所有可配置优先级的中断(包括SysTick、外部中断等)。
        PRIMASK=0:允许中断请求被响应。
__ASM("CPSIE I") 是一条ARM汇编指令,用于清除PRIMASK寄存器的I位(即关闭全局中断屏蔽)。若未执行此指令:

        SysTick定时器产生的中断请求(IRQ)会被屏蔽,无法触发中断服务程序(SysTick_Handler)。
        HAL_IncTick()(通常在SysTick_Handler中调用)不会被执行,导致全局变量 uwTick 停滞 。

2. FAULTMASK屏蔽系统异常

ARM Cortex-M内核的 FAULTMASK 寄存器用于屏蔽所有异常(包括SysTick异常):

        FAULTMASK=1:屏蔽所有异常(如MemManage、BusFault、SysTick等)。
        FAULTMASK=0:允许异常被响应。
__set_FAULTMASK(0) 通过CMSIS函数将FAULTMASK寄存器清零,确保异常(包括SysTick)可以被处理。若未清除FAULTMASK:

        即使SysTick中断请求未被PRIMASK屏蔽,其对应的异常处理流程仍会被阻止。
        SysTick_Handler无法执行,uwTick 不会递增 。

3. SysTick中断的工作机制依赖中断使能

SysTick定时器的工作流程如下:

        定时器计数到0 → 触发SysTick异常(属于系统异常,编号为15)。
        内核检查PRIMASK和FAULTMASK:
                若其中任意一个被置位,异常处理流程(调用SysTick_Handler)将被阻断。
        执行SysTick_Handler → 调用 HAL_IncTick()uwTick 递增。


如果未显式开启全局中断(PRIMASK=1)或FAULTMASK=1,则步骤2会失败,导致流程中断 。

4. Bootloader跳转到APP时的上下文残留

在从Bootloader跳转到APP的过程中,若未显式重置中断屏蔽状态,可能继承Bootloader的配置:

  • Bootloader可能关闭了全局中断(例如在跳转前通过 __ASM("CPSID I") 关中断)。
  • Bootloader可能设置了FAULTMASK=1(例如在关键代码段中屏蔽异常)。

若APP未重新开启中断和异常,上述状态会残留至APP执行阶段,导致SysTick中断无法响应

5. HAL_Delay()的实现依赖uwTick

HAL_Delay(uint32_t Delay) 的实现依赖全局变量 uwTick

uint32_t tickstart = HAL_GetTick();
while ((HAL_GetTick() - tickstart) < Delay)
{
    if (Timeout != HAL_MAX_DELAY)
    {
        // 超时检测逻辑
    }
}

若SysTick中断未触发(导致 uwTick 不递增),循环条件 (HAL_GetTick() - tickstart) < Delay 永远为真,程序卡死在此处 。

6. 验证与解决方法

验证步骤
  1. 在APP启动代码中插入调试代码,读取 PRIMASK 和 FAULTMASK 的值:
    uint32_t primask = __get_PRIMASK();    // 读取PRIMASK
    uint32_t faultmask = __get_FAULTMASK(); // 读取FAULTMASK
    
  2. 若 primask != 0 或 faultmask != 0,则中断或异常仍被屏蔽。
解决方案

在调用 HAL_Init() 和 HAL_InitTick() 之后,显式开启全局中断和异常:

HAL_Init();
HAL_InitTick();  // 确保SysTick已初始化
__ASM("CPSIE I");    // 清除PRIMASK,开启全局中断
__set_FAULTMASK(0);  // 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值