stm32L476RG - 如何从固件执行引导加载程序
Posted
技术标签:
【中文标题】stm32L476RG - 如何从固件执行引导加载程序【英文标题】:stm32L476RG - how to execute the bootloader from firmware 【发布时间】:2017-07-09 13:30:42 【问题描述】:我正在开发 NUCLEO-L476RG 板,试图从我的固件代码启动引导加载程序,但它不适合我。这是我要执行的代码:
#include "stm32l4xx.h"
#include "stm32l4xx_nucleo.h"
#include "core_cm4.h"
#include "stm32l4xx_hal_uart.h"
GPIO_InitTypeDef GPIO_InitStructure;
UART_HandleTypeDef UartHandle;
UART_InitTypeDef UART_InitStructre;
void BootLoaderInit(uint32_t BootLoaderStatus)
void (*SysMemBootJump)(void) = (void (*)(void)) (*((uint32_t *) 0x1FFF0004));
if(BootLoaderStatus == 1)
HAL_DeInit(); // shut down running tasks
// Reset the SysTick Timer
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL =0;
__set_PRIMASK(1); // Disable interrupts
__set_MSP((uint32_t*) 0x20001000);
SysMemBootJump();
int main(void)
HAL_Init();
__GPIOC_CLK_ENABLE();
GPIO_InitStructure.Pin = GPIO_PIN_13;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
while (1)
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13))
BootLoaderInit(1);
return 0;
执行固件后我希望得到的是我可以通过 UART 连接到板并从引导加载程序发送命令/获取响应。我尝试使用的命令来自这里:USART protocol used in the STM32 bootloader.
在与 UART 连接后,我没有看到电路板并没有响应。
【问题讨论】:
【参考方案1】:以下是从this question 的答案中获得的一些想法。
HAL_RCC_DeInit();
这显然需要在重置后将时钟恢复到状态,正如引导加载程序所期望的那样。
__HAL_REMAPMEMORY_SYSTEMFLASH();
将系统引导加载程序映射到地址0x00000000
__ASM volatile ("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");
从引导加载程序 ROM 设置堆栈指针。你的0x20001000
来自哪里?如果它是任意值,则堆栈可以破坏引导加载程序的变量。
然后有这个替代解决方案:
当我想跳转到引导加载程序时,我在其中一个中写入一个字节 备份寄存器,然后发出软复位。那么,当处理器 将重新启动,在程序的最开始,它会读取这个 注册。
请注意,您需要 LSI 或 LSE 时钟来访问备份寄存器。
【讨论】:
"请注意,您需要 LSI 或 LSE 时钟来访问备份寄存器。" - 这不是真的。这些时钟都不需要访问 STM32 中的任何内容。只有当外设明确选择它们作为时钟源时,它们才需要作为时钟源。【参考方案2】:尽量避免使用__set_MSP()
,因为此函数的当前实现不允许如果它也是您当前使用的堆栈指针(而且您很可能是),则允许您更改 MSP。原因是这个函数将“sp”标记为被破坏的寄存器,所以它会在之前保存,之后恢复。
请看这里 - STM32L073RZ (rev Z) IAP jump to bootloader (system memory)
【讨论】:
还是这样吗?__set_MSP()
的替代品是什么?
@jonnor - 不,当前版本的 CMSIS 已修复。检查你的副本在clobber列表中是否有“sp”。
其实 STM32Cube_FW_L4_V1.13.0(相当新)附带的 CMSIS 仍然存在问题。感谢您的提醒!用于 L4 修复的版本 14 具有该修复。 github.com/STMicroelectronics/STM32CubeL4/blob/…
@jonnor - 你总是可以直接从 ARM 用最新的 CMSIS 替换 Cube 包中的内容(;它可以正常工作。【参考方案3】:
从参考手册中找到您的引导加载程序起始地址。
然后使用下面的代码。
在此之前请确保您已清除并禁用中断。
/* Jump to different address */
JumpAddress = *(__IO uint32_t*) (BootloaderAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
也请查看Official STM32 AppNote。
【讨论】:
我试过这个,但它不适用于我的主板。您提供的链接适用于不同的 MCU - STM32F10xxx 。感谢您的尝试。以上是关于stm32L476RG - 如何从固件执行引导加载程序的主要内容,如果未能解决你的问题,请参考以下文章