黄 鑫, 吴跃前, 王德明
(1. 华南师范大学物理与电信工程学院, 广州 510006; 2. 广东省工业和信息化厅, 广州 510030)
嵌入式系统具有功耗低、集成度高的特点,随着工业4.0、物联网和智能制造等快速的发展和推进,其结构越来越复杂、功能越来越强大,在生产和生活中具有广阔的应用前景[1]. 预计到2025年,投入使用的嵌入式设备将会有1~3万亿台[2].
固件(包括操作系统、应用程序、驱动程序、中间件、用户接口资源文件和配置文件等)是嵌入式系统中基础、底层的工作软件. 嵌入式系统在开发过程中需要频繁更新固件来进行调试,在使用过程中也需要偶尔更新固件来进行功能升级[3]. 根据运算和内存资源的大小,将嵌入式系统分为资源丰富型嵌入式系统(Resource-rich Embedded System,RRES)[4-5]和资源紧缺型嵌入式系统(Resource-scarce Embedded System,RSES)[6]. 其中,RRES的内存在MB级以上,其操作系统已集成了调试子系统,可以采用高效的基于GDBServer的固件局部更新方法(GDBServer-based Local Firmware Update,GDBL-FU)[7];RSES的内存在MB级以下,不足以支撑GDB调试机制,一般采用低效、耗时的固件整体更新方法. 然而,RSES因为其成本低的优势,在消费类电子产品中广泛应用.
在使用过程中,嵌入式系统普遍采用在线升级的固件整体更新方法[8]:在不断电或保持系统正常运行的情况下,通过JTAG(Joint Test Action Group)接口[9-10]、串口[11]、无线网络[12]或有线网络[13]实现对固件的整体更新. 目前,这方面的研究比较成熟,如:李苑等[11]提出了一种兼容串口纠错协议和远程文件传输协议的固件升级方法;许金宇等[14]提出了一种基于S3C2440A芯片的嵌入式设备在线系统升级的方法;陈长等[13]提出了一种基于SiTCP通信协议的FPGA可回滚远程固件更新方法;袁凤培[15]针对煤矿多层异构网络提出了一种远程固件整体更新方法,其目的在于高效地批量更新多个设备的固件;何国锋等[16]以可穿戴设备为例,通过模拟BIOS程序,对Flash分块操作来实现设备的固件在线升级. 然而,上述固件整体更新方法[11,13-16]存在效率低的问题. 为此,王豫新和高美凤[5]提出了一种内存消耗低的固件局部更新方法,但是该方法仅适用于RRES,不适用于RSES. 在开发过程中,RSES普遍采用基于JTAG调试器的固件整体更新(JTAG Debugger-based Overall Firmware Update,JDO-FU)方法[1,17]:先打包整个新固件,然后利用外存烧写工具将新固件烧写到固件区,再使用调试器进行调试[18]. 采用JDO-FU需要耗时间打包和烧写整个固件,同样存在效率低的问题. 为了提高效率,郭俊等[6]针对RISC-V处理器,基于BootROM引导流程技术和IAP技术[19]提出了一种易操作、高效且稳定的固件整体更新方法. 然而,目前尚未有文献研究RSES在开发过程中的固件局部更新问题.
针对JDO-FU方法所存在的效率低问题,本文提出了一种高效的固件局部更新方法(Efficient Local Firmware Update,EL-FU),并在实际系统中对使用该方法的RSES进行了性能测试.
图1 RSES的典型固件分布
RSES的开发人员在调试阶段需要频繁更新自己所负责的局部代码,目前普遍采用JDO-FU方法更新整个固件(图2). 因为JTAG协议接口不能访问外存,所以该方法需要用到调试器和烧写工具.
图2 RSES采用JDO-FU方法更新固件的连接示意图
JDO-FU方法的具体流程(图3)为:
图3 JDO-FU方法的流程
步骤1:将各个应用程序、驱动程序和内核程序分别编译链接为hex文件;
步骤2:将操作系统、中间件、配置文件、hex文件和用户接口资源文件整体打包成一个新固件;
步骤3:使用烧写工具擦除外存中的整个旧固件,并将整个新固件烧写到外存中;
步骤4:断开烧写工具,连接JTAG调试器,将宿主机上调试环境软件(如IAR、KEIL等)发出的接收机数据接口(Receiver Data Interface,RDI)命令转化为JTAG命令,以对RSES的内存区域进行调试.
在上述过程中:打包(步骤2)是一个耗时操作,固件越大,耗时越长;切换烧写工具和调试器(步骤4)也是一个耗时操作. 因此,JDO-FU方法需要耗费较长时间,使得RSES的开发存在效率低的问题.
通往空间想象能力深层的必由之路就是由基本知识、基本技能铺设的,双基内容应该是作为社会人生存、发展的必备平台。没有基础,就缺乏发展潜能。
为了缩短RSES的固件更新时间,提高开发效率,本文提出了一种高效的固件局部更新(EL-FU)方法. 采用该方法不需要使用烧写工具,新的局部固件首先由调试器写入内存,然后由驱动程序写入外存中预留的局部更新区域,再由调试器来调试(图4).
图4 RSES采用EL-FU方法更新固件的连接示意图
EL-FU方法的核心在于修改操作系统,增加了更新触发、固件更新、目录添加和提醒4个模块(图5),实现了更新局部固件的功能.
图5 应用了EL-FU方法的RSES的系统框图
RSES采用EL-FU方法后的固件分布(图6)与典型固件分布(图1)的区别在于:(1)在固件区的末尾预留局部更新区域,用于写入需要更新运行的程序;(2)由于存储在外存(一般是FLASH)中的文件目录项不能直接修改,需要在其末尾增加一条指向更新文件的目录项记录.
采用EL-FU方法后,RSES具有固件局部更新和程序加载2个状态(图7). 如EL-FU方法的流程(图7)所示,系统上电后,由启动模块加载并运行操作系统,然后由更新触发模块判断是否收到“更新固件”的命令. 若收到,则进入固件局部更新状态,并执行以下步骤:
(1)由操作系统加载固件更新模块及外存对应的驱动程序,运行固件更新模块程序,接管CPU控制权,等待用户通过调试器写入新的局部固件;
(2)用户利用调试器下载新的局部固件到内存,然后将该固件的名称、大小和起始地址写入到预定内存,下载时通过脚本控制,采用分块下载的方式,根据实际可用内存的大小来调整分块的大小;
(3)当固件更新模块监控到上述预定内存发生变化后,解析该预定内存中的内容,将新固件写入到外存固件区的预留局部更新区域;
(4)目录添加模块在文件目录项区的末尾新增一条指向更新文件的目录项. 这时,指向新版本文件的目录项位于目录项区的末尾,而指向旧版本文件的目录项位于目录项区域的前面;
(5)提醒模块提示更新结束,重启系统.
若没有收到,则进入程序加载状态,并执行以下步骤:
(1)目录检索模块从文件目录项区的末尾开始往前检索,即可最先找到最新版本的程序对应的目录项;
(2)程序加载模块加载并运行更新后的程序;
(3)调试模块启动调试器,调试更新后的程序.
与JDO-FU方法相比,EL-FU方法不需要重新打包、擦除和烧写整个固件,也不需要切换调试工具和烧写工具,可缩短固件更新的时间,从而提高开发的效率. EL-FU方法适用于更新应用程序、驱动程序、中间件、用户接口资源文件和配置文件等固件,但该方法需要操作系统的协助来更新固件,因此该方法不适用于更新操作系统.
在某资源紧缺型嵌入式系统(RSES)上,比较分别使用EL-FU、JDO-FU方法更新局部固件的效率.
该RSES(图8)的特征为:(1)属于蓝牙音频片上系统;(2)内核为MIPS32 M4K、主频为104 MHz、内存为128 KB;(3)上层应用的代码约200 KB,蓝牙协议栈的代码约500 KB,操作系统、中间件和驱动程序等代码约400 KB;(4)主要应用于有屏音箱方案,支持蓝牙播放、录音、迷你卡拉OK和电子书等功能;(5)调试器使用SWD(Serial Wire Debug)模式,下载速率为5 Mbit/s;(6)具有芯片原厂统一发布的针对NAND FLASH量产的烧写工具. 为了实现EL-FU方法,需要修改该RSES的操作系统,但修改后的操作系统仅增加了3 KB代码,对系统固件大小的改变可以忽略.
图8 测试装置图
EL-FU方法的主要操作步骤包括:(1)切换到编译目录进行编译;(2)重启开发板,通过按键进入局部更新状态;(3)利用调试器下载新的局部固件;(4)重启开发板,进入正常运行状态;(5)执行调试命令,启动调试. JDO-FU方法的主要操作步骤包括:(1)切换到编译目录进行编译;(2)切换到打包目录打包新的整体固件;(3)运行量产烧写工具,下载新的整体固件;(4)重启开发板,进入正常运行状态;(5)切换到新的固件目录;(6)执行调试命令,启动调试.
EL-FU方法能够通过脚本控制来支持大容量(通常指超过100 KB)固件的更新. 在实际开发过程中,RSES需要更新的局部固件大小通常为30~100 KB. 因此,本文在该RSES上比较了分别采用EL-FU、JDO-FU方法更新大小分别为30、50、300 KB和1 MB的4个局部固件的时间. 其中,50、300 KB和1 MB的固件都是通过在30 KB固件的基础上用0填充const data数据段来获得的. 固件更新时间是指从某个应用程序修改完源代码算起,直至完成固件更新重新进入到程序调试入口所需要的时间,且为连续20次重复测试的平均值. 该过程中包含的切换开发工具、操作电脑目录等动作均按照开发人员的日常操作速度来进行. 经过80次的重复测试,在RSES上采用EL-FU方法更新固件的成功率为100%,且系统各项功能运行正常,无异常情况发生. 因此,在RSES上利用EL-FU方法更新固件是可靠和稳定的.
由测试结果(表1)可知:(1)在开发过程中,RSES采用传统JDO-FU方法更新固件需要耗费近480 s的时间,采用EL-FU方法后固件更新时间缩短为67 s,可见,EL-FU方法能够解决RSES在固件更新时所存在的效率低问题;(2)EL-FU方法的固件更新时间随着固件大小的增加而小幅增长,这是因为其需要通过脚本控制来分块下载大容量的固件;(3)JDO-FU方法的固件更新时间随着固件大小的增加基本保持不变.
表1 在RSES上利用2种方法更新固件的时间
为了进一步对比分析,在某资源丰富型嵌入式系统(RRES)上,测试了采用GDBL-FU方法更新大小分别为30、50、300 KB和1 MB的4个局部固件的效率(表2). 该RRES的特征为:(1)属于树莓派Raspberry Pi 3代B型;(2)内核版本为linux-rpi-4.9.y;(3)CPU为四核ARM Cortex-A53,主频为1.2 GHz;(4)内存为1 GB. 可知,该系统的资源比上述RSES充裕很多,其操作系统已集成了调试子系统,可以采用高效的固件局部更新GDBL-FU方法. 该方法的主要操作步骤包括:(1)切换到编译目录进行编译;(2)下载新的局部固件;(3)执行调试命令,启动调试.
由表2可知:在RRES上使用GDBL-FU方法的固件更新时间较短,且随着局部固件大小的增加而略微增加(增加了1~2 s),所增加的1~2 s主要由步骤(2)的编译过程产生. 对比上述RSES和RRES的特征,两者的运算和内存资源相差悬殊. 由于嵌入式系统的资源和成本成正比,因此,成本低的RSES在消费类电子产品中得到了广泛的应用. 然而,在RSES上使用传统JDO-FU方法更新固件的效率低. 由表1和表2可知:在RSES上使用EL-FU方法更新固件的效率与在RRES上使用GDBL-FU方法更新固件的效率相近. 这表明:在RSES上使用EL-FU方法更新固件能够克服运算和内存资源少的限制,EL-FU方法是一种适用于RSES的高效固件更新方法.
表2 在RRES上利用GDBL-FU方法更新固件的时间
应用广泛的RSES在开发过程中需要频繁地更新固件,而采用传统的JDO-FU方法更新固件存在耗时长、效率低的问题. 因此,本文提出了一种高效的固件局部更新(EL-FU)方法. 在RSES上采用该方法,不需要使用烧写工具,不需要打包整个固件,仅利用调试器就完成局部固件更新.
测试结果表明:EL-FU方法能够大大缩短RSES上固件更新的时间,并接近于在RRES上采用GDBL-FU方法更新固件所用时间;应用了EL-FU方法的RSES具有可靠性与稳定性. 可见,在RSES开发过程中,可采用EL-FU方法更新应用程序、驱动程序、中间件、用户接口资源文件和配置文件等固件.
然而,本文所提出的EL-FU方法不能用于更新RSES的操作系统,目前仍需要使用固件整体更新方法来更新操作系统. 下一步将针对RSES继续开展如下研究:(1)操作系统层的局部更新方法;(2)不需要操作系统协助的固件局部更新方法.