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();
我用的是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();