申 臻,宋雷军,魏冬冬,于清华,刘 涛
(上海航天电子技术研究所,上海 201109)
8051单片机已在航空航天控制领域广泛应用,需要测评的嵌入式软件数量逐年增多。软件测试又是保障软件安全、正确、完整的关键环节[1]。测试人员使用被测件的硬件平台完成测试,通常会面临两个问题:1)重大科研或者重要型号项目的物理环境,难以为测试工作提供足够的使用时间[2];2)不能执行可能引起物理环境破坏的异常测试,测试的覆盖性得不到保证[3]。面对只有软件源代码,实物测试环境不具备、故障测试用例无法执行的测评任务,如何提供有效测试环境成为软件测评单位的难题。
编译软件Keil C51(美国Keil Software公司开发)为51系列单片机程序[4]提供开发调试环境,涵盖编辑、编译、连接、调试、仿真等整个开发流程。在测试中,通过Keil编译被测试的嵌入式软件(以下简称为“被测件”)代码,并提供被测件运行的仿真环境。基于Keil提供的高级仿真接口(AGSI,advanced generic simulator interface)[5]自研全数字测试平台(以下简称“测试平台”)模拟芯片指令[6],实现被测件的仿真运行、外围激励注入、外设硬件接口模拟、覆盖率统计等。
基于以上背景,Keil C51为被测件提供运行环境;测试平台提供虚拟化接口、外围激励环境[7],实现测试用例执行、故障注入、边界测试以及测试结果的观察。测试平台与Keil之间通过用户数据报协议(UDP,user datagram protocol)完成数据交互[8]。
本文基于Keil C51及测试平台,完成被测件外设的虚拟化,生成可在测试平台上运行的可复用模块。虚拟化外设包括:1553B总线、模数转换 (AD,analog digital)采集、输入/输出(I/O,input/output)数据、RS422总线。测评人员通过测试平台选择被测件运行所需的虚拟化外设模块,构建全数字测试环境,实现被测件运行过程的可控,内存、寄存器信息的可改。最后,以开发某电源下位机测试平台为例,完成故障注入、测试用例执行、测试结果观测,验证虚拟化外设在嵌入式软件测试过程中的有效性和可靠性。
嵌入式软件测试需要具备两个条件:1)嵌入式软件的运行环境[9];2)测试激励注入及嵌入式软件输出数据的解析与显示[10]。虚拟化的外设、通讯中间件、Keil,三者关系结构如图1所示。测试平台的上位机部分,完成测试激励注入以及接收、解析、显示嵌入式软件输出的数据;测试平台的下位机部分,基于AGSI实现嵌入式软件运行时内存、寄存器读写监控、数据同步、触发中断、UDP通信等;Keil C51的uVision版本提供Windows下的集成开发环境(IDE,integrated development environment),实现嵌入式软件的编译、调试、运行[11-13]。本文重点介绍1553B虚拟化、AD采集虚拟化、RS422虚拟化、I/O虚拟化。
图1 测试平台架构
嵌入式软件运行过程会响应不同中断源,CPU检测到中断请求,执行中断服务程序做相应的处理。测试平台根据不同中断源,更改对应寄存器地址中的值,Keil内核监测到特殊寄存器值更改时触发中断,嵌入式软件进入中断服务程序。其中特殊寄存器包括:串行口控制寄存器(SCON,serial control)、中断开发/禁止(IE,interrupt enable)、P0口、P1口、P2口、P3口(8bit分别代表不同的中断源,如P3.2为外部中断INT0,P3.3为外部中断INT1)等。对于中断方式为电平触发、边沿触发,测试平台可向P3口对应bit位写入高电平、低电平、上升沿、下降沿,实现中断的触发。
测试平台实现对被测件内存、寄存器的读写仿真,模拟总线1553B、AD、RS422、I/O接口等外设与被测件交互数据的过程。仿真过程如下:
1)上位机监控被测件需要向外设写数据的全部地址。当Keil软核识别到被测件运行至向外设输出数据处(即被测件写地址操作),虚拟软核触发下位机中的写回调函数,通知下位机此时被测件向哪个地址写入何值。下位机将收到的地址值及数据,通过UDP发送给上位机程序,上位机收到地址及数据完成数据解析与界面显示等后续处理。实现嵌入式软件内存、寄存器写地址动作的仿真。
2)上位机监控被测件需要从外设读数据的全部地址。当Keil软核识别到被测件运行至从外设读取数据处(即被测件读地址操作),虚拟软核触发下位机中的读回调函数,通知下位机当前被测件读取的地址值。下位机将收到的地址值,通过UDP发送给上位机程序。上位机将虚拟外设向该地址写入的模拟数据,通过UDP发送给下位机通讯接口,使得被测件采集到上位机写入的数据。实现嵌入式软件内存、寄存器读地址动作的仿真。
测试平台的上位机部分主要包括上位机界面和虚拟外设。上位机界面分为输入数据、输出数据两大部分:1)输入数据部分,测试人员根据测试需求设置仿真数据,通过虚拟外设将仿真数据发送给被测件。测试人员可设置不同的测试数据,完成被测件的边界测试、故障测试,保障测试充分性;2)输出数据部分,实时显示被测件运行过程中输出数据的解析及状态显示,供测试人员分析测试结果。
虚拟外设将测试人员在上位机界面设置的仿真数据,转换为满足外设特定格式的数据帧,将转换后的数据帧发送给被测件,实现测试激励的注入。同时,虚拟外设接收被测件运行过程中输出的数据,转交给上位机界面,完成数据的解析、显示、存储等处理。
其中,虚拟外设的设计与实现主要包括:总线1553B虚拟化、AD采集虚拟化、总线RS422虚拟化、被测件I/O接收虚拟化。
开展总线1553B虚拟化工作之前,需要研究1553B总线的物理实现逻辑,分析开发测试平台需要仿真1553B总线的方法及内容。本小节首先介绍测试平台所关注的1553B总线简介、1553B物理实现逻辑。其次,根据总线1553B物理实现逻辑的研究,设计并实现1553B中总线控制器(BC,bus controller)、远程终端(RT,remote terminal)的仿真。
2.1.1 1553B总线简介
1553B出自美军标准MIL-TD-1553B,原为美军航空电子综合通信的标准,全称为“飞机内部时分制指令响应式多路传输数据总线”[14]。1553B为基于消息(Message)的通信协议,每条消息的最大信息量32字,分为命令字、数据字、状态字,每类字长20 bit(有效数据16 bit),每个字的前3位为单字的同步字头,最后1位是奇偶校验位[15]。命令字位于每条消息的起始部分,其内容决定消息的特征与标识,状态字只能由RT发出,其内容表征RT向BC发出的有效命令的反馈,BC根据状态字内容决定下一步操作。数据字支持RT->BC、BC->RT、RT->RT传输数据[16],具体字内容如图2所示。
图2 1553B总线字格式
1553B总线采用指令/响应型通信协议,包括3种终端:总线控制器BC、远程终端RT、总线监视器(MT,monitor terminal)。传输的信息格式有BC->RT、RT->BC、RT->RT、广播方式和系统控制方式,且全部在BC的参与下完成。1553B总线传输消息的标准过程为:BC向某RT发送接收/发送指令,RT在给定的响应时间范围内发回一个状态字,并执行消息的接收/发送[17]。消息传输格式如图3所示。其中*表示响应时间,范围是4.0~12.0 μs,表示消息间隔时间,规定>4 μs。
图3 消息传输格式
2.1.2 1553B物理实现逻辑研究
1553B实现虚拟化,完成与被测件数据、指令交互,需要清晰的梳理出1553B物理实现逻辑。在1553B总线简介中指出3种终端:BC、RT、MT,其中BC、RT完成总线指令、总线数据的收发。本段着重介绍BC、RT的物理逻辑。
RT存储器结构在非增强模式和增强模式下,有如表1所示几个区域均被设置为专用区。其他区域为数据块等。RT查找表实现将TX/RX/BCST子地址对应的数据块映射到共享RAM区的机制。可对单独子地址所指向的存储空间进行读写操作,对广播、接收、发送数据分离处理,实现安全、独立的存取数据。RT指令堆栈的长度可设为125字、512字、1 024字、2 048字。
1553B采用双缓存机制,对应查找表A、B。每个查找表分4块:32个发送子地址、32个接收子地址、32个广播子地址、32个子地址控制字。RT查找表具体内容如表2所示。
表1 RT存储器机构固定部分
表2 RT查找表
子地址控制字中存储管理器2、存储管理器1、存储管理器0(MM,memery management)3 bit的取值,设置每次发送、接收或广播数据的长度,长度可设置为128字、256字、512字、1 024字、4 096字及8 192字。1553B虚拟化设计中要支持根据子地址控制字设置收发缓存大小[18]。
在1553B虚拟化时,根据总线指令的收发子地址,对应查找表查询到该子地址对应的内存存储起始地址。接收到的数据被写入由查找表指针指向的数据块,需要发送的数据从查找表指针指向的数据块取出并发送。
2.1.3 BC虚拟化实现
1553B的BC虚拟化需要仿真上述“物理实现逻辑研究”中指出的1553B初始化、查询查找表、读写子地址对应存储区等。仿真BC2RT数据、BC2RT指令、RT2BC数据、RT2BC指令等数据、指令的交互过程。使用共享内存模拟查找表及数据块的存储逻辑。定义两个枚举结构体Enum1553B_Channel_Num、EnumCommand分别表示AB区、BC指令类型,对应代码如下所示:
public enum Enum1553B_Channel_Num{
ChannelA = 0,
ChannelB = 1
}
public enum EnumCommand{
BC2RT,
RT2BC,
RT2RT,
Broadcast,
RT2RTs,
ModeCode,
BroadcastModeCode,
NoUsed,
Error
}
定义BC仿真类BcHelper,完成1553B总线的初始化。初始化包括:映射的内存地址StartAddr、1553B指令地址BcCmdAddr,1553B相关寄存器地址映射(RT指令堆栈指针A、RT指令堆栈指针B、传送矢量字、数据同步、查找表A起始地址、查找表B起始地址、发送查找指针表、接收查找指针表、广播查找指针表、子地址控制字表等),初始化内容如下所示:
public static EnumIntName IntName = EnumIntName.NoInt;
// BC模拟器地址映射
public static UInt32 StartAddr = 0; //映射的mem地址
public static UInt16 BcCmdAddr = 0; //映射的1553B指令地址
//增强型1553B寄存器地址映射
private static UInt32 AddressStackA = 0; //堆栈
public static UInt32 AddressRtCommandStackPointerA = 0x100;
public static UInt32 AddressRtCommandStackPointerB = 0x104;
private static UInt32 AddressTransmitVetcorWord = 0x120;
private static UInt32 AddressSynchronizeWithData = 0x111;
private static UInt32 AddressReceiveLookupPointerTableA = 0x140;
private static UInt32 AddressReceiveLookupPointerTableB = 0x1c0;
private static UInt32 AddressTransmitLookupPointerTableA = 0x160;
private static UInt32 AddressTransmitLookupPointerTableB = 0x1e0;
private static UInt32 AddressBroadcastLookupPointerTableA = 0x180;
private static UInt32 AddressBroadcastLookupPointerTableB = 0x200;
private static UInt32 AddressSubaddressControlWordTableA = 0x1a0;
private static UInt32 AddressSubaddressControlWordTableB = 0x220;
private static UInt32 AddressDataBlock = 0x260;
}
BC端发送控制命令的仿真函数如下所示:
///
/// 发控制命令
///
/// RT地址
/// 发送标志,0标识RT端接收
/// 子地址
/// 长度/方式字(指1553B发送的"字"的长度)
/// 发送的数据
/// 是否是广播标志
/// 通道标志
public static void SendCmd(Enum1553B_Channel_Num channel, bool bcst, int rtAddr, bool rx, int sa, int len, byte[] data)
仿真控制命令后可实现如下过程模拟:BC发送广播、BC2RT数据、BC2RT命令、方同步码等。控制命令流程如图4所示。其中查找表仿真方法为:
1)判断当前控制命令的类型:广播、发送。
2)判断当前命令由BC发到RT的哪个SA。
3)查询查找表中该SA对应的存储起始地址,以及嵌入式软件设置的内存起始地址,计算出该SA数据块在共享内存中的存储区域。
4)将SA对应的存储区域数据取出后发送给RT。
图4 控制命令仿真流程
BC端接收RT发来数据(RT2BC数据)的仿真过程如图5所示。其中对查找表的使用与发送控制命令仿真部分相同。
图5 BC接收RT数据流程
2.1.4 RT虚拟化实现
实际应用中被测件有时作为BC端使用,在构建测试环境时需要对外设RT进行虚拟化仿真,即实现RT2BC数据、RT2BC指令、RT2RT、RT2RTS、BC2RT等数据、指令的交互过程[19]。
模拟RT端接收BC发来的指令、数据,将收到的数据放入本地共享内存,共享内存的组织方式与“BC端仿真模拟”一致。外设RT收到作为BC的被测件发送的。模拟RT端的处理流程如图6所示。
图6 RT端仿真处理流程
2.2.1 AD采集虚拟化设计
实际应用中嵌入式软件通过AD采集模块采集模拟信号,经过模数转化,将转换后的数字量用于软件的后续使用[20]。
嵌入式软件采集信号后的处理过程,实际使用的是数字量而非模拟量。因此,在测试平台中无需仿真模数转换过程,可直接将数字量值赋给嵌入式软件。数字量可通过AD采集界面设置任意值,供嵌入式软件采集。既能满足嵌入式软件从AD采集模块获取数字量的要求,又能满足AD采集模块测试的充分性。
2.2.2 AD采集虚拟化实现
不同被测件AD采集部分的处理过程有相似之处,将通用的处理过程抽象为AD采集模块,完成AD采集外设的虚拟化。AD数据的采集与外设的交互部分涉及采集通道选择、采集高低字节、采集次数等。嵌入式软件与外设交互的流程如图7所示。
图7 AD采集外设交互流程
实现AD采集虚拟化,需要开辟一段共享内存用于存储测试人员设置的一组AD值,数值内容要求:
1)采集的路数;
2)每路数据采集次数;
3)每次采集值,支持设置不同值。
被测件第某次采集某路AD数据时,触发测试平台的读回调函数。在回调函数中判断当次采集为嵌入式软件第几次采集第几路AD数据,取出共享内存中对应的AD值,供嵌入式软件采集。AD采集虚拟化处理流程与图7所示的嵌入式软件与AD外设交互流程相同。
不同嵌入式软件通过测试平台界面可配置采集AD数据通道、采集地址、CPU时钟频率、采集方式等信息,如图8所示。
图8 AD采集配置界面
2.3.1 总线RS422虚拟化设计
串行总线RS422通信由于其在传输距离、抗干扰能力方面的优势,在航天嵌入式软件中普遍应用[21]。嵌入式软件测试时主要关心被测件从串口采集数据之后的处理流程正确与否,以及观察被测件输出的串口数据。被测件通过串口采集数据的方式为:MOV A SBUF;通过串口输出数据的方式为:MOV SBUF A。其中SBUF为寄存器0x99。
因此,在测试平台开发中无需仿真串口全部物理功能,只需实现被测件从串口采集、输出数据的过程。测试人员根据测试需求,灵活设置正确值、边界值、异常值等供被测件采集,用白盒测试法分析被测件采集串口数据后不同处理分支的正确性。被测件通过串口输出的数据,由测试平台接收并依据通信协议完成解析,方便测评人员观察。
2.3.2 总线RS422虚拟化实现
实现对总线RS422的虚拟化,处理逻辑如图9所示。
图9 RS422总线数据交互流程
具体方法如下:
1)测试人员设置输入激励并存入共享队列;
2)被测件运行到需要从RS422获取数据处,即从寄存器0x99读取数据,触发测试平台的读回调函数。测试平台将共享队列中的测试激励通过0x99注入被测件;
3)被测件通过串行总线RS422输出数据时,即通过寄存器0x99输出数据,触发测试平台写回调函数。测试平台依据被测件通信协议接收一整帧串口数据后,完成解析并在测试平台界面显示。测评人员通过界面观察被测件输出的串口数据,判断其运行是否合理。
2.4.1 I/O虚拟化设计
嵌入式软件外设包括上述通用的1553B、RS422、AD采集,还包括与FPGA、DSP或其他外设交互的硬件信号、数据等。建立完整的嵌入式软件数字仿真测试环境,还需定制化的完成被测软件全部输入数据、全部输出数据解析的仿真[22]。这部分定制化的外设仿真统称为I/O虚拟化。
2.4.2 I/O虚拟化实现
I/O虚拟化实现过程与总线RS422虚拟化相似,与流程图9不同之处为:“测试人员设置外围激励”,此处提供两种设置激励的方法,测试人员可通过界面和具有固定格式的Excel表格设置外围激励;其次,被测件从总线RS422取数,改为从通过I/O交互数据的外设采集取数。I/O虚拟化实现的具体方法如下:
1)针对不同外设开辟一段独占的共享内存,用于存储测试人员设定的测试激励。
2)设计固定格式的Excel表格,如表3所示。测试人员将测试激励填入表格,测试平台运行后自动读取表格内容,将数据及地址成对的存入共享内存。
表3 I/O固定输入数据格式
3)测试过程中,通过界面实时设置测试激励。
4)被测件运行至采集外设数据地址处,触发测试平台的读回调函数。测试平台根据接收到的“读地址”,将共享内存中对应的数据发送给被测软件。
5)被测件向“写地址”输出1字节数据或者一帧遥测数据时,触发测试平台的写回调函数。测试平台记录接收到的“写地址”以及对应1字节数据或者一帧遥测数据,依照通信协议完成被测件输出数据的解析。测试人员可通过界面实时观察被测软件的输出信息。
为验证上述描述的嵌入式软件外设虚拟化的有效性和可靠性。以某电源下位机软件测试平台开发为例,模拟1553B、RS422、I/O、AD采集等外设,实现被测件外围环境的正常功能测试、异常故障用例注入,提高测试的充分性,完成对该电源下位机软件的测试工作。该电源下位机软件主要功能是太阳电池阵功率调节、蓄电池组充放电管理功能。需要完成工程参数的采集处理、遥控指令的执行、蓄电池充电管理、均衡器控制等功能,通过1553B总线实现与综合电子分系统的信息交换。
3.1.1 上位机部分搭建
基于自研测试平台选择1553B模块、AD采集模块、针对该电源下位机开发的I/O模块。测试平台模块选择界面如图10所示。
图10 测试平台搭建界面
总线1553B虚拟化后需要通过界面配置接收发送子地址、广播子地址、寄存器、中断触发等信息,以完成被测试软件与外部设备通过1553B传输数据的仿真。配置界面如图11所示。
图11 总线1553B配置界面
AD采集外设模拟需要配置被测试软件采集地址、采集高低字节地址等信息,配置界面如图8所示。
3.1.2 被测件运行环境配置
嵌入式软件电源下位机程序的仿真运行环境由Keil提供,配置基于AGSI编写的动态链接库,使用Keil加载源程序完成编译。使用Keil软件运行电源下位机程序,可完成电源下位机程序动态运行下的白盒测试。其中动态链接库实现测试平台与Keil软件UDP通信、被测试软件内存、寄存器的读写监视、定时器设置、时需同步、中断触发等。
测试平台运行界面如图12所示。测试人员可通过运行界面的左侧设置注入激励的内容,实时更改注入的总线1553B、RS422的指令帧或者数据,以及被测件需要从I/O外设采集的全部数据。运行界面右侧为被测件上传数据的实时显示。
图12 运行界面
AD采集界面如图13所示,测试人员可实时更改供被测件采集的各路AD数据。支持直接在界面上更改AD值、导入AD数据Excel表格两种方式设置AD值。
图13 AD采集界面
通过测试平台完成被测件中断INT0、T0、T1执行时间、中断响应总线指令时间的记录,以及周期发送指令、覆盖率统计。程序地址计数器(PC,program counter)用于存放要执行指令的地址,16位,能自动加1。一个机器周期(M-Machine周期)是12个时钟周期,当主频为12 MHz时,一个机器周期为:1 M = 1/12 MHz*12=1 μs。被测件某段程序执行时间的计算方法是:记录该段程序起止PC之间执行的机器周期数,乘以一个机器周期的时间,得到该段程序的执行时间。
该电源下位机软件共使用3种中断INT0、T0、T1,中断服务程序执行时间的测试结果如表4所示。
表4 中断服务程序执行时间
覆盖率统计支持被测件目标码覆盖率情况保存、多个覆盖率文件合并,源码目标码对照显示。统计结果针对目标码执行情况进行分析,其中包括6种执行结果:
1)EX:executed,该条目标码语句执行,覆盖率统计结果中以绿色显示;
2)NE:Not Executed,语句没有执行,覆盖率统计结果中以红色显示;
3)JF:Jump Fully,分支完全执行,覆盖率统计结果中以黄色显示;
4)JN:Jump Never,分支顺序执行,但是没有跳转,即每次执行到这条语句,跳转条件都不满足,覆盖率统计结果中以黄色显示;
5)JO:Jump Only,执行了分支跳转,但是没有顺序执行,即每次执行到这条语句都是跳转,覆盖率统计结果中以黄色显示;
6)JNE(jump not executed),跳转分支、顺序分支都没有执行,覆盖率统计结果中以红色显示。
目标码覆盖率统计结果中先显示一句源码,紧接着显示对应的目标码,并在第一列显示每条目标码的执行情况。根据每条目标码的执行情况标示绿色、红色、黄色,方便测评人员观察,如图14所示。
被测件目标码覆盖率统计情况如表5所示,包括目标码模块名、总指令数、执行指令数、执行百分比、总跳转指令数、JF指令数、JO指令数、JN指令书、JNE指令数、JF执行百分比。部分嵌入式软件目标码分支、语句覆盖率均要达到百分之百。表5展示覆盖率统计功能,并非电源下位机软件第三方测试的最终覆盖率统计结果。
实验结果证明,在自研测试平台基础上,基于Keil C51完成嵌入式软件外设虚拟化,实现嵌入式软件仿真运行、外围激励注入、外设硬件接口模拟的方法切实可行。通过数字测试平台不仅能够完成与实物测试平台相同的测试效果,还能完成故障注入、边界测试、目标码覆盖率等。
表5 目标码覆盖率统计结果
附注:表格中为第三方测试进行中,被测件目标码覆盖率统计结果的部分展示
本文提出的基于Keil C51的嵌入式软件外设虚拟化,实现了在真实环境中运行的嵌入式软件与全部外部设备交互数据的仿真,使得测试过程不受硬件实物平台的使用限制,拥有充分的测试时间。
1)在测试过程中,外部设备的虚拟化提供了灵活的测试激励注入方式,能够完成实物测试环境难以模拟的故障注入、边界测试以及测试结果实时显示。
2)目标码覆盖率统计能够帮助测评人员分析被测件代码执行情况,精准定位未执行的语句、分支。辅助测评人员分析未执行的原因,针对性的设计测试用例,进而完成未执行语句、分支的覆盖。
3)嵌入式软件外设虚拟化后,主要解决了测试工作中的两个问题:测试过程不依赖嵌入式软件真实的运行环境;测试过程内存、寄存器信息可控可改,测试用例注入方式灵活,能够完成实物测试环境不能满足的故障、边界测试。
4)外设的虚拟化设计,不仅能够缓解目前航天型号领域嵌入式软件测试过程中实物运行环境使用时间冲突的问题,而且对提高嵌入式软件的测试效率和测试充分性也有帮助。