STM32F4:从自定义bootloader跳转到用户应用触发HardFault异常

STM32F4: jump from custom bootloader to user application triggers a HardFault exception

我使用的是基于 STM32F4 的定制板,带有 2MB 内部闪存。

  1. 我有一个小型自定义最小引导加载程序应用程序(转到位于内部闪存中 0x08000000 的扇区 0) 我的用户应用程序存储在位于内部闪存中 0x08020000 的扇区 5 中。所以我的引导加载程序不会在 MCU 的内部闪存中闪存任何用户应用程序。它只跳转到用户应用程序。 自定义引导加载程序使用对此 function:bootloader_jump_to_user_app 的调用跳转到应用程序:

uint32_t nAppAdr=0x08020000;

bool bootloader_jump_to_user_app(uint32_t nAppAdr)
{
bool ret = true;
void(*app_reset_handler)();

//shut down any tasks remaining

HAL_RCC_DeInit();// to turn off the PLL and set the clock to it's default state
HAL_DeInit();// to disable all the peripherals

SysTick->CTRL = 0;//to turn off the systick
SysTick->LOAD = 0;
SysTick->VAL = 0;

//disable interrupts
__set_PRIMASK(1);
__disable_irq();.

SCB->VTOR = nAppAdr;//change this

//configure the MSP by reading the value from the base address 
uint32_t msp_value = *(__IO uint32_t*) nAppAdr;

__set_MSP(msp_value);

uint32_t resethandler_address = *(__IO uint32_t*) (nAppAdr + 4);

//app_reset_handler = (void*)resethandler_address;
app_reset_handler = (void (*)(void)) (*((uint32_t*)(resethandler_address)));

//jump to reset handler of the user app.
app_reset_handler();

return ret;

}

  1. 在我的用户应用程序中,在文件 system_stm32f4xx.c 中,我定义了 USER_VECT_TAB_ADDRESS,并将 VECT_TAB_OFFSET 设置为 0x08020000(在我的用户应用程序的内部闪存中的位置

#define USER_VECT_TAB_ADDRESS

#define VECT_TAB_OFFSET 0x00020000

这应该使我的用户应用程序可引导加载。

  1. 我把我的用户应用程序烧录到扇区5的内部闪存中(起始地址0x08020000。我检查了这一步(比较这个位置的第一个字节和bin文件的前几个字节)。

执行自定义引导加载程序时,函数 bootloader_jump_to_user_app 的最后一条语句,特别是对 app_reset_handler() 的调用,导致类型异常: “硬故障异常。 处理器已将可配置优先级异常升级为 HardFault。 指令预取 (CFSR.IBUSERR,BFAR) 时发生总线故障。 异常发生在 PC=0x1478048,LR=0x8000f85 “

这应该很简单。有什么我想念的吗?为什么我得到例外? 任何帮助表示赞赏 谢谢

我认为问题出在这一行:

app_reset_handler = (void (*)(void)) (*((uint32_t*)(resethandler_address)));

resethandler_address 已经包含地址,但您正在获取地址处的值,从而跳转到“未知”。它应该只是:

app_reset_handler = (void (*)(void)) (resethandler_address);

更新: 我认为你做的一些事情是没有必要的,但我不确定哪些(如果有的话)可能会导致问题。我通常会这样做:

    ...
      <peripheral de-init>
    ...
    __disable_irq(); // Note: remember to enable IRQ in application
    __DSB();
    __ISB();
    uint32_t mainStackPointer = *(volatile uint32_t *)(nAppAdr);
    __set_MSP(mainStackPointer);
    uint32_t programResetHandlerAddress = *(volatile uint32_t *) (nAppAdr + 4);
    void (* programResetHandler)(void) = (void (*)(void)) programResetHandlerAddress;
    programResetHandler();

你没有提到你是如何将应用程序烧录到闪存中的。您确定它位于正确的地址吗?

在Application的链接描述文件(STM32F4?????_FLASH.ld如果你使用的是STM32CubeIDE),你需要将FLASH定义为从0x08020000开始:在MEMORY 部分,将 FLASH 的行更改为如下内容(LENGTH 取决于分配给应用程序的特定区域):

FLASH (rx)       : ORIGIN = 0x08020000, LENGTH = 5*128K  /* Sector 5-9 */