STM32的在线升级(IAP)实现方法:BOOT+APP原理详解

0 工具准备

Keil uVision5
Cortex M3权威指南(中文)
STM32参考手册

1 在线升级(IAP)设计思路

为了实现STM32的在线升级(IAP)功能,通常会将STM32的FLASH划分为BOOT和APP两个部分,BOOT就是引导APP的引导程序,当我们需要在线升级时就可以通过BOOT来实现。BOOT和APP在FLASH中的分布如下:
在这里插入图片描述

原理分析:
(1)当STM32复位后会跳转到FLASH首地址,也就是0x08000000的位置,读取1-4Byte获取主堆栈指针初始值(栈顶值)并设置,然后读取5-8Byte获取复位中断服务函数入口地址并执行,进入BOOT程序
(2)BOOT程序根据用户选择升级APP或者跳转到APP
(2.1)如果用户选择升级APP则擦除APP所在扇区,按照一定协议将APP程序复制到FLASH的APP扇区
(2.2)如果用户选择跳转到APP,首先失能全局中断,然后复位所有外设及RCC时钟,清除所有中断使能位及中断挂起标志,然后执行一些用户自定义的操作。最后设置主堆栈指针,跳转到APP的复位中断服务函数(相当于做了(1)中内核干的事情)。

2 BOOT设计

这里介绍一下BOOT跳转到APP函数的设计思路:

// 复位所有外设
void Per_DeInit(void)
{
    /* 复位APB1上的外设 */
    RCC->APB1RSTR = 0xFFFFFFFFU;
    RCC->APB1RSTR = 0x00U;

    /* 复位APB2上的外设 */
    RCC->APB2RSTR = 0xFFFFFFFFU;
    RCC->APB2RSTR = 0x00U;

    /* 复位AHB1上的外设 */
    RCC->AHB1RSTR = 0xFFFFFFFFU;
    RCC->AHB1RSTR = 0x00U;

    /* 复位AHB2上的外设 */
    RCC->AHB2RSTR = 0xFFFFFFFFU;
    RCC->AHB2RSTR = 0x00U;

    /* 复位AHB3上的外设 */
    RCC->AHB3RSTR = 0xFFFFFFFFU;
    RCC->AHB3RSTR = 0x00U;
}


// 跳转到APP
void Jump_to_APP(void)
{
    uint32_t i = 0;
    void (*SysMemBootJump)(void); /* 声明一个函数指针 */

    /* 关闭全局中断 */
    __disable_irq();

    /* 复位所有外设 */
    Per_DeInit();

    /* 设置所有时钟到默认状态,使用HSI时钟 */
    RCC_DeInit();


    /* 关闭所有中断,清除所有中断挂起标志 */
    for (i = 0; i < 8; i++)
    {
        NVIC->ICER[i] = 0xFFFFFFFF;
        NVIC->ICPR[i] = 0xFFFFFFFF;
    }

    /* 关闭滴答定时器,复位到默认值 */
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;

    /* 重设独立看门狗超时时间为5S */
    IWDG_Config(4, 3125);
    /* 喂狗,给APP预留一些时间 */
    Raise_Dog();

    /* 使能全局中断 */
    __enable_irq();

    /* APP首地址+4就是APP复位中断服务程序地址 */
    SysMemBootJump = (void (*)(void))(*((uint32_t *)(FLASH_APP_ADDR + 4)));

    /* 设置主堆栈指针 */
    __set_MSP(*(uint32_t *)FLASH_APP_ADDR);

	/* 设置为特权级模式,使用MSP指针 (BOOT是RTOS的一定要设置,否则后面的APP无法运行,最好都加上无伤大雅)*/
    __set_CONTROL(0);
    
    /* 跳转到系统BootLoader */
    SysMemBootJump();

    /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
    while (1)
    {
    }
}

相关知识:
(1)涉及到的复位寄存器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
复位寄存器写入1复位相应外设,写入不复位。
(2)涉及到的SysTick寄存器
在这里插入图片描述
SysTick->CTRL:SysTick控制及状态寄存器
SysTick->LOAD:SysTick重装载数值寄存器
SysTick->VAL:SysTick当前数值寄存器
(3)涉及到的NVIC寄存器
(3.1)NVIC->ICER,中断失能寄存器,写入1失能中断
在这里插入图片描述
(3.2)NVIC->ICPR,中断挂起清除寄存器,写入1清除中断挂起
在这里插入图片描述
(4)涉及到的内核控制寄存器
在这里插入图片描述
这里我们设置为0,也就是特权级的线程模式+选择主堆栈指针MSP,恢复到MCU复位状态(BOOT是RTOS的一定要设置,否则后面的APP无法运行,最好都加上无伤大雅)。
(5)APP二进制文件含义
bin文件:
在这里插入图片描述
Byte1-4:0x20014168
Byte5-8:0x080101A1
Byte9-12:0x08012D75
Byte13-16:0x08012851
map文件:
__initial_sp 0x20014168 Data 0 startup_stm32f40xx.o(STACK)
Reset_Handler 0x080101a1 Thumb Code 8 startup_stm32f40xx.o(.text)
NMI_Handler 0x08012d75 Thumb Code 2 stm32f4xx_it.o(i.NMI_Handler)
HardFault_Handler 0x08012851 Thumb Code 8 stm32f4xx_it.o(i.HardFault_Handler)
可以看到,APP工程的bin文件含义如下:
Byte1-4:0x20014168 主堆栈指针初始值(栈顶值)
Byte5-8:0x080101A1 复位中断服务函数地址
Byte9-12:0x08012D75 NMI中断服务函数地址
Byte13-16:0x08012851 HardFault中断服务函数地址
该部分的定义在STM32的参考手册上也可以看到:
在这里插入图片描述
其实,我们只需要关注主堆栈指针初始值(栈顶值)和复位中断服务函数地址即可。如果想要了解APP前几个byte的全部内容,可以参看STM32参考手册的“STM32F405xx/07xx 和 STM32F415xx/17xx 的向量表”。
弄清楚了上述的寄存器使用方法和APP的bin文件内容后,接下来BOOT中跳转到APP的操作原理就一目了然了:
(1)关闭全局中断,避免被打断
(2)复位所有外设,为APP营造一个纯净的环境
(3)设置所有时钟到默认状态,为APP营造一个纯净的环境
(4)关闭所有中断同时清除所有中断挂起标志,避免APP使能中断后异常触发等情况
(5)关闭滴答定时器,复位到默认值,为APP营造一个纯净的环境【自定义】
(6)重设独立看门狗超时时间为10s,喂狗给APP预留一些时间(独立看门狗一旦打开就无法关闭)【自定义】
(7)使能全局中断,避免APP部分没有打开全局中断(这时也清除了所有中断使能位,可以避免跳转到APP过程被中断打断)
(8)函数指针指向APP的复位中断服务函数(也就是APP的第5-8Byte)
(9)设置主堆栈指针(也就是APP的前4Byte)
(10)跳转到APP
以上有2个地方需要特别注意:
(1)APP的复位中断服务函数地址是APP的第5-8Byte
(2)APP的主堆栈指针初始值(栈顶值)是APP的前4Byte

3 APP设计

APP设计时只需要修改工程的flash起始地址以及中断向量偏移地址寄存器即可。
(1)修改FLASH起始地址
在这里插入图片描述
如果我们的APP存放在FLASH的0x8010000开始的位置,则将FLASHA的起始地址修改为0x8010000即可。
(2)修改中断向量偏移地址
BOOT下我们的中断向量偏移地址为0x08000000和默认值一样无须特别设置,APP下由于FLASH起始地址被修改到0x8010000,因此需要将中断向量偏移地址设置为0x1000:

#define VECT_TAB_OFFSET  0x10000

相关寄存器如下:
在这里插入图片描述
当STM32发生了中断需要响应时,内核会根据向量表偏移量寄存器的值在相应的FLASH空间找到异常服务函数入口地址(中断服务函数入口地址保存工作由编译器完成)。上电后的向量表如下:
在这里插入图片描述
假设我们设置的VTOR的值为0x8010000,在发生了硬错误时,会跳转到0x8010000+0x0000000C的位置找到硬错误中断服务函数地址并执行。这也是我们为什么需要在APP中设置VTOR的原因(BOOT里已经默认设置为0x0x8000000),保证我们的中断能够正确执行。

4 总结

(1)APP程序需要修改FLASH起始地址和向量表偏移量寄存器,以便内核能够在中断发生时进入正确的中断服务函数
(2)BOOT程序跳转到APP的过程实际上就是模拟内核的操作
(3)BOOT跳转到APP之前一定要失能所有中断、清除所有中断挂起标志,营造一个纯净的环境。最好将所有外设和RCC全部复位到初始值,使APP的环境更加贴近硬件复位后的环境。
(4)如果在BOOT内使能了独立看门狗,最好调整超时时间并喂狗保证在APP喂狗操作执行前预留足够的时间
(5)如果BOOT是RTOS,则一定要设置堆栈指针为MSP及特权级的线程模式
注意:
在这里插入图片描述
最好在BOOT内使能独立看门狗,当APP错误的时候依然能够触发复位(假如APP错误,会发生不可预知的错误,进入while(1)或其它地方看门狗均会减到0产生复位信号)。另外:独立看门狗的重载值是12位的,最大为4095!!!

  • 38
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
基于Ymodem协议的STM32串口IAP(In-Application Programming)的实现是通过串口通信的方式,实现在设备中对应用程序(APP)进行更新或升级。 在实现过程中,需要涉及三个主要组件:IAPAPP以及上位机。 IAP是指在设备中运行的固件,用于实现应用程序的更新。它需要能够接收上位机传输的数据,并将其写入设备的存储器中,以完成应用程序的更新。 APP是指设备中当前正在运行的应用程序,它需要检测到IAP的存在,并与上位机进行通信。APP需要具备与上位机进行数据交换的能力,并能够接收来自上位机的命令,以控制IAP的运行。 上位机是用于控制设备中IAPAPP的计算机。它通过串口与设备进行通信,并将应用程序的更新数据传输给设备。上位机需要发送命令给设备,控制设备中IAPAPP的运行,并在传输过程中与设备进行数据交换。 在实际操作中,上位机首先向设备发送一个请求,请求设备启动IAP模式。设备在接收到请求后,会进入IAP模式,并向上位机发送确认信息。之后,上位机会将待更新的应用程序数据通过串口传输给设备。设备会根据Ymodem协议对数据进行校验,并将数据写入存储器中。传输完成后,上位机与设备进行数据交换,以确认更新的完成情况。 总结来说,基于Ymodem协议的STM32串口IAP实现包括IAPAPP和上位机三个主要组件,通过串口通信实现应用程序的更新。以上是对该实现过程的简要描述。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NW嵌入式开发

感谢您的支持,让我们一起进步!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值