我需要固件升级。我打算使用USB DFU类。但在我的情况下,固件升级命令将来自PC应用程序。所以我需要切换到系统内存中的bootloader。最初我正在运行应用程序,因此它从用户闪存启动,即我为用户闪存配置了Boot0和Boot 1引脚。由于DFU引导加载程序存在于系统闪存中,现在需要更改Boot0和Boot1引脚设置。有没有像Boot 0和Boot 1设置保持用户闪存一样的方法,在应用程序中我们跳转到系统内存?
答案 0 :(得分:22)
仅在处理器启动时对Boot0 / 1引脚进行采样,以检查是否应从内存加载用户代码或是否应加载引导加载程序。 之后这些引脚的状态对引导加载程序没有影响。
我遇到了类似的请求,并找到了2种按需加载引导加载程序的方法。
首先,你可以" JUMP"从用户代码到引导加载程序。例如,您可以在按下按钮时跳转到引导加载程序。
但是......这比简单的JUMP指令复杂得多:一些寄存器和设备必须正确配置才能与引导加载程序配合使用,你必须确保在JUMP期间不会触发IRQ,...事实上,您必须重新配置处理器,就像它在重置后刚刚启动一样。 您可以找到有关此技术的一些信息:on this video from ST。
我设法在STM32F1xx项目上做了这样的事情。 然而,在基于STM32F4的更复杂的项目中,这将变得非常困难......我将不得不停止所有设备(定时器,通信接口,ADC,DAC ......),确保不会触发IRQ,重新配置所有时钟,......
相反,我决定实现第二个解决方案:当我想跳转到引导加载程序时,我在其中一个备份寄存器中写入一个字节,然后发出软复位。然后,当处理器重新启动时,在程序的最开始,它将读取该寄存器。该寄存器包含指示应在引导加载程序模式下重新引导的值。然后,跳转到引导加载程序要容易得多,如the youtube video中所示。
答案 1 :(得分:4)
In MicroPython there is a pyb.bootloader() function which is used to enter into DFU mode.
The C code which implements that can be found in their source repository.
I've used the STM32F4 version extensively (the #else
block), and the F7 variant a few times (although its been a while).
I'll put the body of the function here since the above links could become stale if that file changes:
// Activate the bootloader without BOOT* pins.
STATIC NORETURN mp_obj_t machine_bootloader(void) {
pyb_usb_dev_deinit();
storage_flush();
HAL_RCC_DeInit();
HAL_DeInit();
#if defined(MCU_SERIES_F7)
// arm-none-eabi-gcc 4.9.0 does not correctly inline this
// MSP function, so we write it out explicitly here.
//__set_MSP(*((uint32_t*) 0x1FF00000));
__ASM volatile ("movw r3, #0x0000\nmovt r3, #0x1FF0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");
((void (*)(void)) *((uint32_t*) 0x1FF00004))();
#else
__HAL_REMAPMEMORY_SYSTEMFLASH();
// arm-none-eabi-gcc 4.9.0 does not correctly inline this
// MSP function, so we write it out explicitly here.
//__set_MSP(*((uint32_t*) 0x00000000));
__ASM volatile ("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");
((void (*)(void)) *((uint32_t*) 0x00000004))();
#endif
while (1);
}
The pyb_usb_dev_deinit() function shuts down USB, and storage_flush writes out any cached filesystem data. The HAL functions come from the STM32Cube HAL files.
If you use a newer version of dfu-util (IIRC 0.8 or newer) then you can specify the -s :leave
command line option to have your newly flashed program executed at the end of flashing. Combining with the above I go through flash/test cycles without having to touch the board, and only use BOOT0/RESET when the firmware hard-crashes.
There is also a python DFU flasher called pydfu.py: https://github.com/micropython/micropython/blob/master/tools/pydfu.py which is a little faster than dfu-util.
答案 2 :(得分:3)
要跳转到新图像那很难。作为自我测试的一部分,我已经成功地完成了它。
void (* const jumpFunction)(void) = (void (*)(void))(APPLICATION_ADDRESS + 4ul + 1ul);
偏移量为4是越过堆栈指针,偏移量为1表示Thumbmode。__set_MSP((uint32_t)*APPLICATION_ADDRESS)
,第二个映像的前四个字节将包含新的堆栈指针。jumpFunction();
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
。您必须将其更改为SCB->VTOR = APPLICATION_ADDRESS | VECT_TAB_OFFSET;
我在FLASH_BASE
有一个POST程序,它使用核心耦合的SRAM作为其堆栈,然后在主SRAM上运行内存检查,检查主程序的真实性,然后跳转到主程序。 / p>
我仍然可以调试主程序,好像没有任何改变。
NB!我最近才这样做。我需要验证一些事项。一个问题是软件重置会发生什么。如果从第二个程序调用它,我认为它将进入第二个程序的重置例程,而不是第一个程序。
答案 3 :(得分:2)
您可以模拟引导加载程序条件。将BOOT引脚与地之间的电容和并联电阻连接起来。将另一个自由引脚连接到BOOT引脚。电容可以通过外部引脚充电,并通过电阻放电。我不记得你可以计算/试验它们的确切值(重要的是RC电路的时间常数)。
通过将外部引脚设置为1来为此电容器充电,通过NVIC_SystemReset
执行软件复位。重置后,它将运行bootloader。连接到电容器的电阻器将执行放电。固件更新后,您可以重置设备,它将运行到您的应用程序。
我们在某些应用程序中使用它并且运行良好。这个解决方案的缺点是你需要外部电路,但它很容易实现,并且它适用于所有STM32设备。
答案 4 :(得分:0)
我在此问题上挣扎了一段时间,试图从 STM32L4A6xx
上的 FreeRTOS 应用程序跳转到 USB OTG DFU。经过大量的反复试验,我能够使它工作,所以我想我会在这里发布它,因为我在其他任何地方都找不到明确的说明。
注意此代码适用于 STM32L4,遵循相同的模式应该适用于其他代码。
此外,当您使用 STM32CubeProgrammer 刷写映像时,请务必选中“运行应用程序”复选框,否则它往往会停留在引导加载程序模式。
void JumpToBootloader(void)
{
HAL_SuspendTick();
/* Clear Interrupt Enable Register & Interrupt Pending Register */
for (int i=0;i<5;i++)
{
NVIC->ICER[i]=0xFFFFFFFF;
NVIC->ICPR[i]=0xFFFFFFFF;
}
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
// RM0351 Rev 7 Page 93/1903
// AN2606 Rev 44 Page 23/372
CLEAR_BIT(FLASH->OPTR, FLASH_OPTR_nBOOT0);
SET_BIT(FLASH->OPTR, FLASH_OPTR_nBOOT1);
CLEAR_BIT(FLASH->OPTR, FLASH_OPTR_nSWBOOT0);
SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
while(READ_BIT(FLASH->SR, FLASH_SR_BSY));
HAL_FLASH_OB_Launch();
}