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

时间:2017-02-03 09:27:06

标签: stm32 bootloader

我使用的是STM32L073RZ(Nucleo 64板)。

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

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

我阅读勘误表,没有给出详细信息,只是根据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))))();
    }
}   

按下BP1按钮后,我会调用这两行,在重置μC后触发跳转操作:

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

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

4 个答案:

答案 0 :(得分:1)

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

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

软件可以跳转到引导程序,但它会执行双引导机制。 因此,引导加载程序返回到bank1(如果代码“有效”,则返回bank2)。

今天,我无法绕过双库机制来使用我的配置执行引导加载程序: boot0引脚复位且保护级别为0(参见参考手册中的“表11.引脚和BFB2位配置”)。

答案 1 :(得分:1)

解决方案是跳转两次到系统内存。 首先跳转到引导加载程序启动以初始化RAM中的数据,直到程序计数器将由Dualbank管理返回到Flash。 第二跳:跳转到Dualbank绕过的地址

使用方法:用户首先在Flash中初始化变量“Data_Address”(必须是偏移Flash扇区对齐的地址),以区分第一/第二跳。

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

答案 2 :(得分:0)

致电__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH()时,您的计划柜台在哪里?

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

答案 3 :(得分:0)

首先要注意的是:您使用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))
);

BTW - 您不需要设置内存重映射以使引导加载程序正常工作。