【问题标题】:STM32F4: jump from custom bootloader to user application triggers a HardFault exceptionSTM32F4:从自定义引导加载程序跳转到用户应用程序触发 HardFault 异常
【发布时间】:2021-10-26 14:09:27
【问题描述】:

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

  1. 我有一个小的自定义最小引导加载程序应用程序(它转到位于内部闪存中 0x08000000 的扇区 0) 我的用户应用程序存储在内部闪存中位于 0x08020000 的扇区 5 中。所以我的引导加载程序不会在 MCU 的内部闪存中刷新任何用户应用程序。它只跳转到用户应用程序。 自定义引导加载程序使用对此函数的调用跳转到应用程序: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 "

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

【问题讨论】:

    标签: bootloader stm32f4


    【解决方案1】:

    我认为问题出在这一行:

    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();
    

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

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

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

    【讨论】:

    • 感谢尼尔森的回复。试过了,但它仍然不起作用。我用来从简单的自定义引导加载程序跳转到任何 STM32F4 应用程序的任何简单示例。
    • @YounesCHTIOUI 我已经用我成功使用的代码和有关应用程序链接器脚本的信息更新了答案。还要确保将VECT_TAB_OFFSET 设置为0x00020000 - 而不是0x08020000(您在问题中提到了这两个值)。祝你好运!
    • 嗨 Nielsen,我使用 STM32CubeProgrammer 对应用程序进行编程。闪现。我确定这是正确的。我可以使用 IAR 调试器查看闪存内容,并且可以看到应用程序二进制文件已正确写入正确的地址 (0x08004000)。一个问题:我没有这个STM32F4?????_FLASH.ld。我在我的项目中查找任何 .ld 文件,但我没有。我怎么没有这个文件。感谢您的帮助
    • @YounesCHTIOUI 我(天真地)假设您使用了 STM32CubeIDE,它会生成上述链接描述文件。 IAR 可能使用类似的东西,但我自己没有使用过 IAR。如果您的应用程序是为正确的地址构建的,那应该没问题。
    • 我正在使用 IAR IDE。等效的链接描述文件是 stm32F479xx_flash.icf。我确实在上面的链接器脚本文件中将 ICFEDIT_intver_start 设置为 0x08020000 并将 __ICFEDIT_region_ROM_start 设置为 0x080020000 并且确实解决了问题......确保在主 while 循环之前在用户应用程序中调用了 __enable_irq()。感谢尼尔森的洞察力。
    猜你喜欢
    • 2013-08-15
    • 2020-01-30
    • 2020-07-10
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 2019-12-26
    • 2021-01-16
    • 2022-09-29
    相关资源
    最近更新 更多