我正在使用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后,我没有看到并回复电路板。
答案 0 :(得分:0)
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时钟来访问备份寄存器。
答案 1 :(得分:0)
尽量避免使用__set_MSP()
,因为此函数的当前实现 NOT 允许您更改MSP,如果它也是您当前使用的堆栈指针(并且您很可能是)。原因是这个函数将“sp”标记为破坏寄存器,因此它将被保存并在之后恢复。
请参阅此处 - STM32L073RZ (rev Z) IAP jump to bootloader (system memory)
答案 2 :(得分:0)
从参考手册中找到您的引导加载程序起始地址。
然后使用以下代码。
确保在执行此操作之前清理和禁用了中断。
/* 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。