简介

OTA升级是嵌入式设备几乎都有的一项功能。对于简单的设备来说,例如单片机设备,OTA升级需要将新的固件刷写到FLASH上即可;对于高级一点的Linux设备来说,更加复杂,首先需要对ROM进行分区,再决定升级方式,是单备份升级还是双备份升级。

本文主要讲解嵌入式设备的OTA升级流程架构,虽然会涉及到一些实现细节,但是并不会事无巨细的讲解每一步操作。

升级的本质

所谓的升级,无非是使用新的程序替换旧的程序。

但是,就像一个人不借助镜子永远看不到自己的眼睛一样,程序也永远不能自己替换自己。因此,程序的升级一般有下列几种主流的做法:

  1. 先把自己加载到RAM中执行,然后替换ROM中的程序,接着再重启一下。
  1. 这种做法是Linux或者windows操作系统中最常见的做法,因为在操作系统中,二进制程序默认就会加载 到RAM中执行
  1. 再使用一个程序B,跳转到程序B执行,程序B负责把新的程序替换到旧程序的位置
  2. 再使用一个程序B和单独的一块ROM(以下简称ROM-B),把新的程序放到ROM-B里面去,然后程序B负责在ROM-A和ROM-B中进行切换。


单片机上的OTA

先了解一下单片机程序的执行原理:
通常单片机都内置有一块FLASH用于存储代码,一块RAM用于存储数据。 FLASH中的代码可以直接被CPU读取并执行。

因此单片机进行升级,通常就不能使用上述1的RAM升级方法。都要使用到第三个程序,通常叫做bootloader。

具体做法如下:

单备份升级

  1. 下载升级包 upgrade.bin 到 FLASH的 0x8300000位置
  2. 在FLASH上或者其他任何重启不会丢失的位置设置一个标志位 flag
  3. 重启
  4. 进入Bootloader
  5. Bootloader中判断标志位 flag是否设置,如果设置了,则
  6. 拷贝0x83000000到 0x820000位置
  7. 校验md5
  8. 跳转到0x8200000执行
  9. 完成升级


双备份升级

  1. 下载升级包 upgrade.bin 到 FLASH的 0x8300000位置
  2. 在FLASH上或者其他任何重启不会丢失的位置设置一个标志位 flag
  3. 重启
  4. 进入Bootloader
  5. Bootloader中判断标志位 flag是否设置,如果设置了,则
  6. 跳转到0x8300000执行
  7. 完成升级



Linux系统上的OTA

Linux系统由多个部分组成,如下所示:
![图片.png]([object Object]&name=图片.png&originHeight=147&originWidth=738&originalType=binary&ratio=1&size=32769&status=done&style=none&taskId=u6ed9c885-8bb8-4c72-8967-711c19df36b&width=738)

  • bootloader :
  • 主要用于加载kernel和设备树到ram中
  • 通过传递参数的形式,可以简单的配置kernel,比如配置以太网地址,使用的根文件系统位置
  • 不需要升级
  • kernel
  • 系统核心,需要加载到RAM中运行
  • 根文件系统
  • 比较大,类似于windows中的C盘的概念
  • APP
  • 根文件系统中的一个二进制可执行程序



因此升级也需要分开考虑:

ROM分区

linux的ROM是以分区的形式来管理,而不是像单片机一样直接以地址来管理的,如下图所示:
![图片.png]([object Object]&name=图片.png&originHeight=121&originWidth=746&originalType=binary&ratio=1&size=30596&status=done&style=none&taskId=u2cbafa51-3fe5-40bd-af5b-5fd7d76b60c&width=746)
因此通常可以把上述的每个部分都单独放在一个分区当中,这样方便操作。


APP升级

APP升级比较简单。 APP执行时会加载到RAM中执行,所以可以随时覆盖ROM上的APP,然后重启即可。

根文件系统升级

根文件系统升级比较复杂,因为根文件系统在ROM上,且Linux一直在使用。故只能使用上述的2/3, 配合程序B进行升级。
举例:

单备份升级

首先需要一个额外的kernel和设备树,以及一个很小的ramrootfs。

  1. 下载升级包到备份分区
  2. 修改uboot引导参数
  3. 重启从ramrootfs启动
  4. 检查备份分区的升级包
  5. 拷贝升级包到rootfs分区
  6. 修改uboot引导参数
  7. 重启


双备份升级
  1. 下载升级包到备份分区
  2. 解压升级包到rootfs-2分区
  3. 修改uboot引导参数
  4. 重启
  5. 从rootfs-2启动
  6. 升级完成


kernel升级

kernel会由uboot加载到RAM中运行,因此也只需要直接替换即可。


单备份和双备份

根据上述的描述,可以看出,单备份升级其实存在风险:假设在拷贝升级包的时候设备突然断电,此时设备处于一个中间态 - 既没有升级成功,也没有升级失败。 设备直接变砖。

而双备份升级可以一定程度上的保证原子性,即设备要么升级失败,要么升级成功。