基于嵌入式系统程序升级的架构设计

2022-02-14 07:36潘文卿刘兴义王飞飞宋炳雨王琳琳
汽车电器 2022年1期

潘文卿, 刘兴义, 王飞飞, 宋炳雨, 王琳琳

(潍柴动力股份有限公司, 山东潍坊 261061)

在汽车领域, 随着智能化的不断提升, 汽车各方面的功能越来越多, 越来越复杂, 软件会不断地迭代升级, 而且更新周期开始变得越来越短, 所以需要不断地更新升级程序。 程序升级的流程和架构需要保证正确稳定, 安全可靠。 在汽车领域的嵌入式系统软件中, 主要包含两部分程序, 一部分是引导加载程序, 主要负责完成初始化硬件设备, 建立内存空间的映射关系, 升级控制程序, 即Bootloader程序, 以下简称Boot程序; 另一部分是实现相关控制功能的应用程序即APP程序。

1 Bootloader的相关概念

Bootloader就是在操作系统内核运行之前运行的一段程序, 初始化硬件设备, 建立内存空间的映射关系, 从而将系统的软硬件环境带到一个合适状态, 以便最终调用操作系统内核做好正确的环境。 Bootloader是依赖于硬件而实现的, 特别是在嵌入式系统中。 因而我们可以构建一个具有适用性、 安全可靠的架构。

2 单Boot刷写架构

单Boot刷写的架构, 即系统一上电, 先进入Boot程序,进行软硬件的初始化, 建立内存空间的映射关系, 然后校验应用程序的完整性, 如果程序是完整的, 当前也没有程序更新需求进入, 将跳转到APP程序中运行。 如果应用程序运行过程中收到刷写的命令, 则跳转到Boot程序进行APP软件升级的会话流程。 这种单Boot的架构随着功能的不断迭代升级, 局限性已日渐明显。 一旦Boot程序烧录到控制器中, 即无法再更新。 图1是Boot程序和APP程序运行及刷写架构图。

图1 Boot和APP的跳转及刷写流程

这种单Boot的架构适用于项目规划最初就能够将应用程序的架构划分明确, 不会因为功能的增加, 程序的迭代导致程序区或者数据区空间不够, 需要重新划分区间的情况。 一旦应用程序的架构有调整, 单Boot的刷写架构将不再适用, 控制器将不再支持软件版本上下兼容, 持续升级。

3 双Boot刷写架构

3.1 双Boot刷写架构1

为了规避单Boot 的架构带来的不便, 再单独拿一块Flash区域做成双Boot, 我们分别用BootA (更新应用程序的Bootloader), BootM (更新BootA的Bootloader) 区分。 BootA中有启动程序, 一上电, 程序就从BootA中启动运行, 上电后初始化软硬件, 完成内存空间的映射关系, 校验APP应用程序的完整性, 在BootA中停留一定时间后跳转到APP应用程序, 如果在此停留期间收到更新APP的会话请求, 按照标准的UDS刷写流程进行APP应用程序更新, 更新完成后, 则跳转到APP入口运行应用程序; 如果在BootA运行期间收到更新BootA的会话命令, 则跳转到BootM中, 按照标准的UDS刷写流程更新BootA, 更新完成后, 先从BootM跳转到BootA, 然后再跳转到APP。

如果在APP运行期间收到更新BootA的会话请求, 则先从APP跳转到BootA, 再从BootA跳转到BootM, 进行BootA的程序更新, 更新完成后则由BootM 先跳转到BootA, 再由BootA跳转到APP。 BootM和APP之间不能直接跳转, 以保证BootM的独立性。

为了防止出现异常复位或者刷死APP的情况, 设定复位机制, 强制停留在BootA程序中, 并发送一条具有复位原因标识内容的报文到总线上以便分析, 当前因异常强制停留在了BootA, 可以分析APP程序进行定位以便重新进行程序刷写。

此架构的优点是随着程序的不断迭代升级, 当BootA的刷写流程或者程序设计不满足要求的时候, 可以通过BootM进行更新, BootM仅有更新BootA的功能, 比较纯粹和独立,仅仅是用来更新BootA, 因此它占用的空间会比较小, 对整个嵌入式系统程序的设计不会带来太大的影响。

如图2 所示, BootM 和APP 没有直接的跳转关系,都是通过BootA来跳转, 这样BootM 会比较独立, 不受APP 的影响,但是同时更新BootA 时风险比较大, 此时要保持通信的设备和线路稳定, 通信会话流程设计要安全可靠, 如果在更新BootA的过程中出现间断、 卡滞等问题会导致刷写失败, 如果BootA不能正常启动运行, 会导致控制器失效。 因此更新BootA的风险性较高。

图2 BootA-BootM-APP跳转关系1

3.2 双Boot刷写架构2

控制器上电首先进入BootM, BootM中包含了启动程序,初始化程序, 校验APP完整性功能, 在BootM运行期间收到刷写会话命令, 如果要更新BootA, 则按照标准的UDS刷写流程更新BootA, 更新完毕后, 跳转到APP; 如果收到更新APP的会话命令, 则先跳转到BootA, 然后更新APP; 如果没有收到任何更新程序的会话命令, 则直接跳转到APP。

在APP程序运行期间, 如果收到更新BootA的会话命令,则跳转到BootM, 更新BootA, 更新完毕后跳转到APP; 如果收到更新APP的会话命令, 则跳转到BootA, 对APP程序进行更新, 更新完毕后跳转到APP运行。 BootM的功能保证了不管什么情况下即便是BootA异常刷死了, 也可以重新上电跳转到APP正常运行。

如图3 所示, 在此架构关 系 中 ,BootM、 BootA、 APP 三者建立相互跳转关系, BootM承接一部分初始化的功能,更 新 BootA,如果更新BootA失败, 则停留在BootM中。 BootA保留更新APP的功能, 如果APP存在异常, 连续复位或者被刷死的时候, 设定复位机制, 停留在BootA中, BootA会通过一条可以标识复位原因的报文发送到总线上以便分析并进一步更新APP; 如果APP更新失败, 会停留在BootA中; 如果BootA更新失败, 停留在BootM中, 以便程序进一步更新, 可以保证控制器不会因为程序问题而失效。

图3 BootA-BootM-APP跳转关系2

4 结论

本文以实际的嵌入式系统程序升级为例, 提出了3种嵌入式系统程序升级Boot架构设计, 并对每一种Boot架构的优缺点进行了分析。 在功能不断智能化、 多样化的情况下,程序不断迭代升级, 频繁升级程序是不可避免的, 在优化过程中, Boot也会升级。 为了保证控制器下线后, Boot程序和应用程序都能够不断地升级, 我们提出了双Boot的概念,用一个Boot升级另一个Boot, 另一个Boot升级应用程序, 这样上电后的启动顺序以及跳转关系成了关键。 本文从两种Boot架构中分析了各自的优缺点, 在架构2中弥补了架构1的缺点, 降低了Boot刷写的风险, 提高了系统的稳定性。