STM32L073RZ (rev Z) IAP 跳转到引导加载程序(系统内存)

STM32L073RZ (rev Z) IAP jump to bootloader (system memory)

我用的是STM32L073RZ(Nucleo 64板)。

我想在应用程序编程(IAP)中跳转到系统内存。

我的代码适用于 STM32L073 微控制器的修订版 B,但在最新修订版 Z 上失败。

我阅读了勘误表 sheet,没有给出任何细节,只是根据 BFB2 位修复了双引导机制进入系统内存的限制。

系统内存是否不再支持IAP跳转执行其代码(通过USB或UART刷入固件而不使用BOOT0引脚)?

该函数是我主程序的第一行,它测试代码是否必须跳转到 booloader:

void jumpBootLoader(void)
{
    /* to do jump? */
    if ( *((unsigned long *)0x20003FF0) == 0xDEADBEEF  ) 
    {
        /* erase the label */
        *((unsigned long *)0x20003FF0) = 0xCAFEFEED;

        /* set stack pointer to the bootloader start address */
        __set_MSP(*((uint32_t*)(0x1FF00000)));

        /* system memory mapped at 0x00000000 */
        __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();

        /* jump to @bootloader + 4 */
        ((void (*)(void))(*((uint32_t*)(0x1FF00004))))();
    }
}   

我在重置µC后一按下BP1按钮就调用了这两行来触发跳转操作:

*((unsigned long *)0x20003FF0) = 0xDEADBEEF;
NVIC_SystemReset();

我使用的是HSI 16Mhz时钟源。

当你调用__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH()时你的程序计数器在哪里?

在同一区域外执行时重新映射内存区域会很糟糕!您可能需要将此代码重新定位到 SRAM 中,或者在 PC 设置为固定闪存映射 (0x0800xxxx) 的情况下执行此代码。

首先重要的是:你使用0x1FF0 0000作为存储SP的地址,这是正确的。然后使用 0x1 FF00 0004 作为加载函数指针的地址。这是不正确的 - 太多了一个零。

请注意,如果您还使用 MSP 作为堆栈指针(您很可能是),那么使用 __set_MSP() 通常不是一个好主意。此函数的最新定义将 "sp" 标记为损坏的寄存器,导致您的更改几乎立即恢复。顺便说一句,今天我做的事情和你做的完全一样,我发现了这个问题。在您的汇编列表中,您会看到 SP 在 msr msp, ... 指令之前保存到其他寄存器中,并在该指令之后立即恢复。

最后我手动写了那个(STM32F4,所以不同的地址):

constexpr uint32_t systemMemoryBase {0x1fff0000};

asm volatile
(
        "   msr     msp, %[sp]      \n"
        "   bx      %[pc]           \n"

        ::  [sp] "r" (*reinterpret_cast<const uint32_t*>(systemMemoryBase)),
            [pc] "r" (*reinterpret_cast<const uint32_t*>(systemMemoryBase + 4))
);

顺便说一句 - 您不需要为引导加载程序设置内存重映射。

感谢您的帮助。我有我的答案!

v4.0 引导加载程序(初始版本)未实现双银行机制,但 v4.1 支持此功能。

软件可以跳转到bootloader但是会执行双引导机制。 因此,引导加载程序返回到 bank1(如果代码为 "valid",则返回 bank2)。

今天无法通过我的配置绕过双银行机制来执行引导加载程序: boot0引脚复位,保护级别为0(参考手册"Table 11. Boot pin and BFB2 bit configuration")。

解决方法是两次跳转到系统内存。 首先跳转到 bootloader 启动以初始化 RAM 中的数据,直到程序计数器将由 Dualbank 管理返回到闪存。 第二跳:跳转到Dualbank旁路地址

使用方法:用户首先要在Flash中初始化一个变量“Data_Address”(必须是偏移Flash扇区对齐的地址)来区分first/second跳转。

EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = Data_Address;
EraseInitStruct.NbPages     = 1;


    First_jump = *(__IO uint32_t *)(Data_Address);

    if (First_jump == 0) {  
        HAL_FLASH_Unlock();
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Data_Address, 0xAAAAAAAA);
        HAL_FLASH_Lock();

        /* Reinitialize the Stack pointer and jump to application address */ 
        JumpAddress = *(__IO uint32_t *)(0x1FF00004);
    }
    if (First_jump != 0) {  
        HAL_FLASH_Unlock();
        HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
        HAL_FLASH_Lock();

        /* Reinitialize the Stack pointer and jump to application address */ 
        JumpAddress =  (0x1FF00369);
    }

    Jump_To_Application = (pFunction) JumpAddress;
    __set_MSP(*(__IO uint32_t *)(0x1FF00000));
    Jump_To_Application();