单片机 IAP 功能基础开发篇之APP升级(二)

1、前言

上一篇 单片机 IAP 功能基础开发篇之APP升级(一)讲到了单片机 IAP 功能给 APP 程序升级的设计思路,这篇介绍的是具体实现方式。

下一篇 单片机 IAP 功能基础开发篇之APP升级(三)


1.1、目的

本文所写的是如何不通过下载器的方式实现单片机中的程序更新,目前介绍的是 STM32 的 BootLoader 简易设计方案(便于初步理解)。


2、设计方案


2.1、升级方式

在开发单片机的 bootloader 功能时,首先需要选择通过什么样的方式进行升级,在单片机 IAP 功能基础开发篇之APP升级(一)介绍了三种升级方式,该篇先介绍串口通信升级方式。

选定升级方式后,就需要选择串口通信协议,这里我们可以选择 Modbus通讯协议(当然,可以自己定义协议,这样更快,但是需要对应的上位机也支持该协议)。

选择Modbus通讯协议的原因:

1、完善健壮的通信协议内容,属于工业领域通信协议的业界标准(肯定要有所了解和使用业界标准协议)

2、 嵌入式软件开发之常用软件(六)介绍的串口调试助手 XCOM 就有该协议的功能,方便使用

扩展:选择串口通信可以通过连接蓝牙模块,从而实现无线升级

2.2、分区划分

升级方式选定后,则需要划分 Bootloader 和 app 的 Flash 空间,分别用来存放 bootloader 和 app 的程序,在没有开发 bootloader 之前,整个 Flash 都可以是 app 的程序空间。

以 STM32F103ZET6 为例,STM32 的 flash启动地址为 0x0800 0000,则根据下表进行划分(分区大小可根据芯片内存大小自行决定):

MCU分区

描述

起始地址

大小备注

Bootloader 程序区

BOOT 可执行程序(程序启动区)

0x0800 0000

32K

用户程序区(APP)

APP 可执行程序(应用程序区)

0x0800 8000

480K

疑问:为什么 BootLoader 的起始地址为 0x0800 0000,难道 app 的起始地址不能是 0x08000000 吗?

首先了解 STM32 芯片上电的时候,首先会从内存地址位 0x0800 0000(由启动模式决定)的地方加载栈顶地址(4字节),从 0x0800 0004 的地方加载程序复位地址(4字节),然后跳转到对应的复位地址去执行。

假设 app 的起始地址是 0x0800 0000,那么芯片上电就会直接执行 app 程序(没有 BootLoader 功能的就是这种情况),升级的时候肯定就是由 APP 程序跳转 BootLoader 中,但因为 BootLoader 是用来升级 app 程序,那就意味着 app 程序不一定时刻都存在,如在升级过程中若出现断电或其他问题引起升级失败导致 app 程序被擦除且掉电,那么下次启动时就因为没有 app 程序而进入硬件错误中断(堆栈溢出,程序指针指飞),即无法进入 BootLoader 重新升级,只能重新通过下载器烧写 app 程序。但如果 BootLoader 先启动,那这种情况就不会存在。

2.2.1、编译器设置

Bootloader 和 app 属于两个独立的工程,不是一个工程!!!

独立的工程意味着程序可以独立运行(将两个工程的起始地址设置 0x0800 0000),不受另一个工程影响,只是程序的功能不一样。

但是 APP 工程的起始地址变了,所以跑不起来,需要 bootloader 进行引导。

  • BootLoader 的编译器设置

  • App 的编译器设置

2.2.1、APP 程序有效标志

程序启动后,首先进入 bootloader 程序中,再跳入APP 程序中,如果APP 程序不存在,则一直在bootloader 中等待升级;那么,如何识别 APP 程序是否存在或者有效呢?

通常升级 APP 程序后,即通过 bootloader 烧录 APP 程序后,会在 APP 中的指定位置设置标志,然后 bootloader 去检查该标志是否有效。

为确保该标志不影响 APP 可执行程序,一般放在 APP可执行程序之后。

可执行程序包括:代码、初始化数据段和未初始化数据段等不仅仅只是代码

目前不清楚APP可执行程序的结束地址怎么办?

可以在 APP 程序预留分区的最后地址预留 4 个字节的标志位,标志可设置为 0x5a5a(该方式每次擦除 APP 程序时必须将 APP 分区全部擦除,否则该标志就没有意义)。

下篇会讲如何在程序编译完之后得到 APP 可执行程序结束地址,将标志放置 APP 可执行程序结束地址后,这样擦除时就只需要擦除升级程序需要的内存了,节约擦除时间(擦除较耗时),当然优点不止这些。

2.3、流程图


2.4、Bootloader 设计

2.4.1、初始化

初始化和正常没有bootloader 的程序一下,该咋样就咋样,为了避免无效功耗损失,一般是需要什么就初始化什么。

  • 时钟初始化
  • 串口初始化
  • 定时器初始化(如果有用到定时轮询或者定时器延时等可以初始化)

2.4.2、检查APP 程序是否存在

       初始化完成后,首先检测 APP 分区中最后地址的标志位是否符合(如是否等于0x5a5a),如果符合,启动倒计时(时间大约几百毫秒就行,根据实际情况决定),等待进入 APP 程序,在此期间,也会等待接收升级的指令;否则,则一直等待接收升级的指令。

2.4.3、升级

       接收到升级指令后,则启动升级流程,升级期间不允许进入 APP 程序。升级流程如上流程图

2.4.3、跳转APP程序

升级完成后,需要跳转到 APP 程序(可以自动跳转,也可以增加跳转指令手动跳转),跳转前的准备:

  1. 检测 APP 程序是否存在,若存在,则继续往下执行
  2. 关闭全局中断
  3. 清除所有中断标志位
  4. 跳转 APP 启动程序地址

当然,也能直接跳转到 APP 程序的 main 函数,但在跳转前需要重新初始化堆栈等内容,所以最好还是交给启动文件处理


2.5、App 设计

2.5.1、初始化

APP 程序初始化之前,需要重定向中断向量表。

重定向中断向量表的原因:由于 bootloader 占用了原来的芯片中断向量表地址,为了防止进入 APP 程序区后产生的中断进入 bootloader 的中断处理程序,所以需要重新定向到 APP 程序的中断向量表。

注1:并不是说进入 APP 程序后产生的中断就会执行 APP 中断程序,跳转 APP 程序可以简单理解成为 bootloader 的一个 APP 函数,进入函数执行后只不过无法退出而已,难道执行函数会影响原有的中断程序吗!!!

注2:STM32 可以设置重定向中断向量表寄存器,不代表所有芯片都有该寄存器功能,比如 STM8 就不行,需要通过额外的处理做到类似重定向中断向量表的处理(相对复杂)。

重新定向中断向量表后,重新清除所有中断标志为,接着就可以正常初始化,正常执行了。

2.5.1、热启动升级

什么?APP 程序还能跳转 bootloader?

是的,当然可以,有两种方式:

1、通过函数指针跳转,即和跳转 APP 是一样的方式,跳转之前的做法是一样的,只不过没有检测 bootloader 存在标志(都能运行 APP 怎么可能没有),但是这样需要在 bootloader 也要做重定向中断向量表功能,麻烦!!!

2、软复位:通过软复位让程序复位,这样啥都不要处理,快速(程序复位,啥数据都没了,不关心无所畏惧)

跳转的目的是?都执行 APP 程序了,还跳转回去干嘛,闲的?

目的是为了下发升级固件时不需要冷启动(单片机重新上电),即在 APP 程序中需要实现接收升级准备指令(避免误触发,通常时一定时间接收到多少升级准备指令),然后通过上述的方式进入 bootloader 执行升级,不需要再像 51 单片机一样下载程序还需要重新上电才能下载。


3、代码片段

3.1、APP 跳转代码片段

#define APP_FLASH_CODE_BASE 0x08008000
#define APP_FLASH_CODE_SIZE 0x78000

int CheckIfAPPCanJump(void)
{
    uint32_t *pFlag = (uint32_t *)(APP_FLASH_CODE_BASE + APP_FLASH_CODE_SIZE - 4);

    if (*pFlag == 0x5A5A)
    {
        return 1;
    }

    return 0;
}

void JumpJumpApplication(void)
{
    typedef  void (*iapfun)(void);  /* 定义一个函数类型的参数 */
    iapfun jump2app; 

    if (CheckIfAPPCanJump())        /* 检测APP应用程序段是否可正常跳转 */
    {
        __disable_irq();                      /* 全局中断关闭 */
        jump2app = (iapfun)*(vu32*)(APP_FLASH_CODE_BASE + 4);/* 用户代码区第二个字为程序开始地址(复位地址) */
        MSR_MSP(*(vu32*)APP_FLASH_CODE_BASE);/* 初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址) */
        jump2app();		  /* 跳转到APP */   
    }
}

3.2、重定向中断向量表

void SetVectorTable(void)
{
    uint8_t i;

    SCB->VTOR = APP_FLASH_CODE_BASE;

    /* 清除所有中断标志 */
    for(i= 0; i < CRS_IRQn; i++)
    {
        NVIC_ClearPendingIRQ((IRQn_Type)i);
    }
    
    /* 在BOOT中跳转之前关闭了全局中断, 因此需要重新打开 */
    __enable_irq();
}

  • 18
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
### 回答1: 51单片机iap(In-Application Programming)在线升级是一种在单片机系统中通过编程的方式对在线设备进行升级的技术。 通过IAP技术,在单片机系统运行的过程中,对内部存储器进行读取和修改,并将新的程序代码下载到内存中,从而实现在线升级IAP不需要擦除内存,能够有效地避免数据丢失,提高系统的稳定性和安全性。 51单片机IAP在线升级技术可以在系统运行时进行程序升级,更新新的功能,增强系统性能,并具有快速、灵活、方便的特点。但是,IAP技术需要对硬件进行支持,如双系统设计和FLASH存储器等。 因此,在进行51单片机IAP在线升级时,需要根据硬件支持条件选择不同的技术实现方案。同时,在进行在线升级时,需要注意保护程序的完整性和安全性,以免出现不良影响。 总之,51单片机IAP在线升级技术是一种便捷、灵活、高效、先进的升级方式,广泛应用于各类嵌入式系统中,有利于实现软件功能的快速升级和系统的优化。 ### 回答2: 51单片机指的是一种基于Intel 8051指令集的单片机,它是广泛应用于嵌入式系统中的一种芯片。而IAP(In-Application Programming)在线升级则是指在不需要任何外部设备的情况下,通过程序自身对芯片中的代码进行更新。 在51单片机中,实现IAP在线升级需要结合程序设计和硬件电路设计两个方面。首先,程序中需要预留出一定的存储空间,用于存储升级程序的代码。其次,需要设计一个与单片机相连的串行接口,如UART或SPI等,以便实现与外界通信,接收升级程序的数据。 整个IAP升级的流程如下:首先,单片机在运行过程中通过串口接收到升级程序的数据,将数据暂存至内部存储器。然后,单片机停止当前程序执行,切换到专门的IAP程序,读取内部存储器中的升级程序数据,并将其写入到指定的程序存储区。最后,单片机重新启动程序执行,完成升级。 通过IAP在线升级技术,可以大大简化芯片升级的操作流程,并节省升级的时间和成本,适用于各种嵌入式场景的应用。 ### 回答3: 51单片机iap在线升级是通过网络或串口实现对51单片机程序的在线更新和升级。它可以通过服务器端的推送或客户端的请求,将新的程序固件通过网络传送到目标单片机,然后在单片机中通过IAP(In-Application Programming)实现程序的自我升级。这种在线升级方式可以极大地简化单片机的维护和升级,提升单片机的灵活性和可用性。它适用于广泛的应用场景,如远程设备控制、智能家居、远程医疗等。同时,为了保证在线升级的安全性和准确性,需要特别注意数据传输的可靠性和过程的安全性。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大橙子疯

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值