我使用的是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时钟源。
答案 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 - 您不需要设置内存重映射以使引导加载程序正常工作。