嵌入式系统随着目前科技的发展,正逐步融入人们的生活中。对于嵌入式系统,我们应该有所了解。就专业人员而言,他们对嵌入式系统早已驾轻就熟。为增进大家对嵌入式系统的认识,本文将对嵌入式系统的远程调试予以介绍。注意,本文中的嵌入式系统远程调试方案仅仅代表一种方式,仅提供一种参考。


一、基本方法

图 1(a)是传统的嵌入式调试方法:主机 PC 通过串口与从机嵌入式系统相连,接收从嵌入式系统发来的调试信息并向嵌入式系统发送调试指令,主机和从机之间只能有几米或者几十米的距离。图 1(b)是现在比较流行的远程嵌入式调试方法:主机 PC 和从机嵌入式系统分别通过以太网连接到网络上,主机通过诸如 Telnet 之类的协议向嵌入式系统接收调试信息和发送指令。本文介绍的方法是将这两者结合起来,位于远端的嵌入式系统与其相邻的 PC2 通过串口相连,主机 PC1 和从机 PC2 各自通过以太网连接到网络上,主机 PC1 仍然通过 Telnet 协议(使用 Windows 自带的“超级终端”程序)与从机 PC2 通信,在从机 PC2 上运行一种我们设计的软件 Telent2com,其将 Telnet 协议转换成串口的数据收发。为了能够更好地完成对远端的嵌入式系统的控制,还使用了 Telnet 协议中特殊的控制命令来通过串口的额外控制线和一定的硬件电路完成对嵌入式系统,如电源和 I/O 输入的控制,如图 1(c)所示。

 

使用这种方法单从嵌入式系统的角度来说,基本上没有增加任何额外的电路和成本,仍和第一种方法一样对外使用串口进行通信。虽然增加了一台额外的 PC 机,但是对于那些在正常工作中不需要使用网络,只在测试和调试时需要使用网络来完成调试和更新固件的嵌入式系统来说,这台额外的 PC 机只能算作是一个调试工具。

 

此外,由于增加了通过网络完成对嵌入式系统的电源和 I/O 输入的控制,相对于第 2 种方法,即使在调试中嵌入式系统由于某种原因死机了,仍能从远端通过控制电源,使系统上电复位;而对系统 I/O 输入的控制,则可以更好完成模拟系统与外界的交互模拟。

 

整个系统的工作由两部分构成:① Telnet 到串口之间通信协议转换的 PC 端程序;② 使用串口控制线控制嵌入式系统电源和 I/O 输入的接口电路。

 

二、接口电路的设计

接口电路主要是完成将串口 RXD 和 TXD 以外的控制线(如 RTS、CTS 等)对嵌入式系统电源或者 I/O 输入进行控制。为了防止嵌入式系统可能对 PC 串口的影响,采用图 2 所示的电路。通过使用光耦来达到 PC 串口和嵌入式系统之间的电气隔离,通过使用继电器能够控制不同电压的电源和不同电平的信号。

 


三、Telnet 到串口转换的软件

Telnet 是一种最基本的网络应用层协议,其通信协议由 RFC0854 定义。它是建立于 TCP 协议之上的用于传送数据和控制信息的协议。在默认情况下,其使用 TCP 端口 23。最初设计它的目的,是为建立一种基于网络的串行终端仿真协议。这也正是为什么可以使用 Telnet 协议传送串口数据的原因。

 

通过 Telnet 传送的数据基本以原来的格式(如果是 0xFF 数据,则以两个 0xFF 表示)填充到 TCP 消息的有效数据载荷区。对于控制信息(如转入二进制模式命令,以及我们自定义的控制电源和 I/O 的命令)则通过在控制命令前加 IAC 转意字符(0xFF)方式混杂在普通数据中传送。这样就可以避免像 FTP 协议使用额外的端口来传送控制信息的必要,降低程序的复杂度。

 

这里所要设计的 Telnet 到串口协议的转换程序(telnet2com)实际上是一个 Telnet 的服务器。它接受来自图 1(c)中主机 PC1 客户端的 Telnet 链接请求,然后向 PC1 客户端通过 Telnet 协议发送其从串口接收到的数据,同时将接收到的 Telnet 数据发送到串口。

 

在 Windows 操作系统,大部分的服务器(如 IIS)都是以 Windows NT 服务组件(service)的形式存在于系统中的,它们在系统启动后就一直运行在后台,等待事件的触发(如某个 TCP 端口是否有链接请求)。作为服务组件,其与一般 Windows 程序的不同之处是:它必然包含名为 NtServiceEntry 的入口函数,当 Windows 开始运行一个服务组件时,首先运行这个入口函数,而非通常的 main 函数。

 


在入口函数中,必须定义一个 dispatchTable 的结构,包括服务名称 sServiceName 以及服务的实际主函数 ServiceMain,并通过 StartServiceCtrlDispatcher 函数真正完成服务的注册和运行。一旦一个服务组件启动后,除了不断监听某端口外,还需要响应服务管理器(service mananger)的不同请求(如暂停服务)。因此将服务的实际功能设计成一个子进程 bridgeThread,由服务的主进程调用该子进程,而服务的主进程则专门用来响应服务管理器的请求。

 

图 3 是子进程 bridgeThread 的流程。首先,使用 Winsock 对特定端口进行监听。然后,通过消息循环,当接收到链接请求的事件后,将串口初始化。之后,消息循环就不断响应来自 Telnet 和串口的写请求,将 Telnet 的数据发送到串口,直到收到 Winsock 断开链接的请求。

 


在接收到来自 Telnet 客户端发来的数据后发送到串口之前,必须扫描接收到数据中是否有 IAC 转义字符。如果有,必须将它们去掉,而且对于定义的如控制电源和 I/O 的命令必须进行相关的操作。反之,从串口接收的数据在发送到 Telnet 客户端之前,必须在所有的 0xFF 字符之前多加一个 0xFF。下面是对从 Telnet 接收的数据进行扫描过程的代码。

 


这里主要使用了 Winsock 的 API 来完成 Telnet 部分的数据读取;串口部分是通过将串口虚拟成一个文件,通过文件读写的 API 来完成的。此外,为了对串口其他控制线的控制,使用了 GetCommState( )和 SetCommState ( )两个 Windows API 来完成。

 

在实验中,使用这样一套远程调试系统,曾与远在韩国的设计中心进行联合调试并进行嵌入式系统固件程序更新下载,虽然相对于本地下载速度慢了很多,但是仍然比其他方式(如电子邮件+手工下载)更为便捷,结果更为直观。

 

使用这样一套软硬件系统来完成嵌入式系统的远程调试,既节省了大量的人力物力,又节约了开发的时间。此外,如果它和配套的测试软件结合,可以突破一台电脑只有一两个串口,同时只能测试一个嵌入式系统的局限,使一台主机同时可以和很多个嵌入式系统相连,完成自动测试和协同测试。