【问题标题】:stm32L476RG - how to execute the bootloader from firmwarestm32L476RG - 如何从固件执行引导加载程序
【发布时间】: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 连接后,我没有看到电路板并没有响应。

【问题讨论】:

    标签: embedded stm32 bootloader


    【解决方案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 。感谢您的尝试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    • 2021-10-12
    • 1970-01-01
    • 2019-07-08
    • 1970-01-01
    • 2012-01-30
    相关资源
    最近更新 更多