观察盒子内部:调试动态系统
作者:Jean J.Labrosse, President, Micrium
翻译:北京麦克泰软件公司 张爱华
摘要:
随着低成本的在线调试能力的增强,例如ARM的ICE(在线仿真器),通过指令单步调试变得更容易,成本也比较低。这种方式可以查看和修改变量值,显示寄存器的内容,查看内存块,但通常只有在目标系统停止运行的时候才可以实现。然而,很多实时系统是不能停止的。因此,在不设置断点的情况下,如何查看系统正在做什么?如何在不妨碍和影响系统动态性能的前提下,实时查看和监测系统的行为?
当我们试图观测实时系统的动态行为时,传统的调试技术功能很快就变得有限了。自从第一片微处理器诞生以来,用于监控和调试动态系统的工具基本上没有发生什么变化。为了解决这个问题,嵌入式工程师采用了诸如LED、测试端口、示波器、逻辑分析仪、仿真器、字符型LCD、图形显示等工具。事实上,上述的任何一种方式都可以从嵌入式系统中获取一些正在运行的线索,每种方式都可以提供观察嵌入式硬件操作的观察点,用以揭露系统内部发生的神秘事情。但是,其中许多技术需要额外的硬件和软件来记录和查看目标系统发生的事情。
我们首先简要评估在监控目标系统实时行为时,嵌入式工程师常用的一些技术,然后推荐一种便宜的、使用简单,但非常强大的新技术。
使用LED
很多嵌入式系统都会包含一个,在某些情况下会有多个发光二极管(LED)。LED被用来显示各种各样的动态信息。它们可以指示嵌入式系统是否在运行,某个条件是否发生,系统是否发生了错误,已经运行到了某个位置等等。LED是一种简单、有效且比较便宜的设备,但同时它们也有局限性。首先,它们增加了成本,除非将它们进行组合,形成条形或其它更复杂的显示方式,否则它们不能传递变量的值。其次,LED显示的数据量是有限的,并且大多以一种并不友好的方式进行显示。必须承认,LED存在一些比较好的方式来指示一个系统正在运行或一个特定的事件已经发生,但在其它方面并不擅长。
使用printf()函数
嵌入式工程师转向在代码中使用printf()函数(假设采用C语言编程)来输出对象的动态行为。因此,printf()函数被插入到代码中的关键位置来查看系统的行为。在调试过程中,printf()函数被到处移动来显示目标应用的不同方面,以此在系统开发过程中获取信息。不难想象,过度使用printf()函数将导致应用程序臃肿。通常printf()输出会放在主机的终端输出窗口,由于这个原因,当数据连续获得时,工程师需要将各种数据流实时地重新分类。这些数据流一般是由整型或浮点型数据转换得到的文本值,它迫使工程师读取每个值时,调整它的量级,理解它的重要性。大多数情况下,采用数据值曲线图或许比文本值更恰当。
由于printf()函数占用代码量,在一些系统中,特别是在8位微控制器中,不能简单地应用这种方法。即使在代码不受限制的情况下,printf()函数在格式化输入时也会引起延时。当通过串口传递信息时,这个延时会更长,更不用说增加到系统上的负载。况且新的PC机不再包含串行接口(即RS-232C),因此这个技术几乎要销声匿迹了。
使用字符型LCD
有一些嵌入式处理器拥有额外的I/O口与字符型液晶显示器(LCD)。这种方式相对费用比较昂贵,且需要写代码来显示我们希望得到的状态和变量的值。这种设备可以显示的变量数是有限的,需要一次或几次完成所有的显示。此外,我们还需要实现一个用户接口来选择查看变量的值。很明显,这种方式占用了嵌入式工程师开发实际产品精力。取决于产品本身的成本或其它原因,显示可能不会作为最终产品的一部分。
图1:带有LCD可以显示2行16个字符的嵌入式系统
采用图形显示
那些拥有图形显示设备的嵌入式系统可以传递很多系统的实时信息。值、图、图表、柱状图等都可以很容易的显示出来。然而,这种显示手段会导致系统成本价格的增长,如增加电子显示设备,实现显示功能的图形用户接口(GUI)软件,创建接口将感兴趣的信息传递给工程师所用的时间。尽管在开发的初级阶段,显示设备可以被借用来帮助开发,事实上,很多嵌入式系统拥有的显示设备,通常是将其作为用户接口,而不是开发使用。
转移显示使之更加直观
我们需要的是允许我们监测目标系统,而不需要负担额外的费用或增加设备的负载。有一种设备允许我们以图形方式显示我们希望从目标系统获取的任何信息,这个设备是普遍存在的且易于使用,它就是一台PC机。
以上结论使得Micrium公司开发了µC/Probe。这个概念很简单,我们可以把大部分的负担转移到运行Microsoft Windows的PC机上,而将尽量少的代码放到目标系统中。µC/Probe是一个基于Microsoft Windows的应用程序,可以实时显示产品中任何变量的值,内存分配和I/O口的值。µC/Probe允许通过逻辑图、数据指示器、温度计、柱状图、速度图、饼图、LED以及其他方式来显示变量的值。而且不需要在嵌入式产品中写入任何代码,不需要使用printf()函数,也不需要在产品中包含用户接口。Micrium公司以源代码的方式提供了一个小且简单的树桩(stub),在创建你的目标应用时需要包含它。在PC机端,树桩(stub)接口使用通用的串行异步接收发送器接口(UART),通用串行接口(USB),网口(采用TCP/IP),调试接口(JTAG或其它的接口)或其它目标系统可以使用的接口。在开发产品的过程中,一旦在树桩(stub)与产品一起编译连接,可以立即开始查看嵌入式系统的实时行为。
µC/Probe可以用于任何编译器和处理器(8,16,32位CPU或DSP)。事实上,任何工具链(编译器、汇编器、连接器)都是适合的。如果系统中有RTOS,可以与RTOS结合使用。它可以用于任何RTOS。
{{分页}}
µC/Probe工作流程如下,Windows应用程序分析由工具链的连接器产生的文件,确定目标板上每个全局变量的名称、类型和地址,并在符号浏览器中列出所有的变量。然后用户将图形组件(虚拟对象)拖拽到一个画布,也就是数据屏幕中,并为每一个对象指定符号浏览器中的一个变量。在目标系统接口允许的情况下,放在开放数据屏幕中的图形组件关联符号值将很快获得更新。如果工程师需要修改目标代码,连接器则将改变变量的地址,µC/Probe将重新加载新的连接文件,调整数据屏幕中所有图形组件的信息。
图2 三个简单步骤:拖拽一个图形组件,挑选一个监控的符号,点击运行,观察图形组件表示的符号的值
图3 µC/Probe提供了可视对象的完整集合,包括虚拟LED,标签,标准尺,图和表
事实上,目标系统中只需要很少的代码,就足够响应如“发送地址0x40102030地址开始的12个字节”这样的要求。Windows应用程序在收到应答后,根据新的值更新数据屏幕中相关的组件。因为代码位于RTOS的空闲任务中,在与RTOS一起使用时,目标驻留代码通常不会插入。换句话说,因为在空闲任务中CPU不执行任何操作,它不占用应用程序的CPU周期。如果工程师希望仅仅更新某一段代码中的变量的值,他可以将目标驻留代码放在那个位置。无论如何,用于与Windows应用程序通信占用的时钟周期的百分比,可以通过简单地修改目标系统中调用驻留代码的频率(和调用的位置)来满足用户的需求。
采用µC/Probe可以显示温度,压强,湿度,过程变量,状态变量,定时器,计算结果,逻辑输入和输出,最大最小值,执行时间,堆栈使用,I/O寄存器,I/O口,表,数组,绘图变量随时间的变化等等。也可以显示布尔型、整型、浮点型数据和字符串。
µC/Probe允许创建多个数据屏幕,通过逻辑分组来显示变量,来查看目标的行为。如果设计一个发动机控制器,可以通过创建一个数据屏幕来显示控制器的实时数据,例如:制动位置、电流和每分钟最大转数、气缸温度、发动机运行时间、发动机油压和温度、空气压强和温度、停止时间、燃料数量等等。
图4:飞机驾驶舱工具例程
图5:可以用来显示变量当前值的一些图形
µC/Probe提供了完整的图形的对象,包括模拟LED、标签、标准尺、图、表(增强了控制的灵活性),当然,LED可用来显示布尔型变量的值,开或关。
标签用于显示变量的值或者内容,比如ASCII 字符串,但作为数字量则代表了一个整型或浮点型数。或者用于简单地显示一个字符串(可配置长度)。
标准尺允许使用模拟的标准尺或者仪表方式来显示值数据。图则通过两种通用的图格式:线图和柱状图来显示数据。线图用于追踪一个或几个变量或数组变量的值随时间的变化。柱状图为每个数组变量的当前状态提供了一个图形化的比较。
表是最灵活的,并且有一个电子数据表接口,允许数据单元包含采用其它数据单元数据(可能是目标系统中变量的值)的计算公式。极大增强了表的扩展性和灵活性。以枚举类型为例,可以从整型值转换为逻辑字符串的形式表示,因此比数值更有意义。
应用
对于应用级别的调试来讲,高级调试工具,例如µC/Probe比初级的工具更合适。由实现相关功能的几个任务组成的嵌入式系统,不适合采用断点和LED的方式来调试。通过使用µC/Probe窗口接口,可以在一个观察点获取更广泛的信息,更适合这种类型的调试工作。为某一个特定的模块,如RTOS,TCP/IP协议栈或USB协议栈等开发的数据屏幕,可以用于使用这些模块的任何嵌入式系统。与模块相对应的数据屏幕可以用于新的工作屏幕,与图形相关联的变量将被重新连接,这意味着变量的地址将从运行在新的目标上的代码的连接输出文件中自动获取。
“高级调试工具在对有问题的低层代码函数调试时缺乏洞察力”的评论也是正确的。对这种任务调试来说,断点和LED是不可替代的。无论如何,µC/Probe可以作为在所有产品的初期开发阶段使用的工具,为系统高级特性的缺陷,比如任务的性能,堆栈使用,或缓存使用,在早期就提供一些警告信息。
评论