杨志杰,石骥硕,徐 宁,王财进
(中国铁道科学研究院通信信号研究所,北京100081;2.北京交通大学理学院,北京100044)
工业现场设备通常都会长时间运行,为了对设备的运行状况进行更好的监控,可以利用信号采集系统对这些设备运行状况以及产生的数据进行采集,并发送给监控计算机,运行在监控计算机上的分析软件通过对这些数据的分析处理,可以得出设备当前的运行状况,从而可以针对当前的运行状况采取相应的措施。目前,常用的信号采集装置,在其系统软件设计中多采用单片机、DSP或基于嵌入式计算机的架构。然而基于DSP的数据采集系统, 虽然处理速度快,但成本较高,实现通信接口较困难,过多的中断会降低CPU 的效率,系统响应速度变差。而单片机的系统则由于单片机本身的局限性,运行速度低,无法执行多任务操作。基于嵌入式Linux的数据采集系统则很好地完成相应功能,弥补了上面两种系统的缺陷。
嵌入式Linux操作系统作为整个系统的核心部分,完成对任务进行控制和调度,并且实现任务间通信与同步、对系统资源以及存储的管理。
本文以嵌入式Linux操作系统为平台,以基于ARMv5te、XScale架构的PXA270为处理器,设计和实现一种通用的高性能数据采集系统。
数据采集系统采用分布式设计,可以使用以太网、485/422串口、CAN总线等多种通信接口实现系统上位机与现场检测下位机之间的通信。正常运行时,数据采集系统可以用来完成数据采集、数据简单处理、数据在文件中的存储、数据传输等多种任务。系统有一定的自动检测、自动校正能力,可以将检测出的异常情况发送给上位机,方便对系统进行维护。为了适应各种自动检测的需求,采用模块化结构对整个检测系统进行设计,这样可以方便地对模块进行不同的组合,从而构造出不同功能的应用系统。
数据采集系统选用PXA270处理器作为整个系统的核心,其系统硬件组成如图1。从传感器等信号源接收的模拟信号经过调理电路处理后,由模数转换器(ADC)转换为数字信号,输入到PXA270中。根据不同的应用,在ARM中进行数字滤波和其它相应处理,通过通信接口将数据传输到上位机,从而进行进一步的分析和处理。图形界面利用QT技术,利用液晶屏显示软件界面以及调试信息,可以方便地通过图形界面的提示,利用鼠标和键盘进行控制。
图1 基于PXA270的数据采集系统框图
信号调理电路主要是为了将信号分量调整到适当的幅度,并抑制干扰信号。采取的主要措施有:增加衰减器以调整较大信号电压到合适ADC输入的范围,并增加与前端的传感器或接收天线的匹配程度。调理电路中包括LC低通滤波器,滤去干扰信号。
模数转换器采用12 bit双通道、采样速率为65 Msp/s的AD9238。该芯片采用3.3 V供电,与单通道A/D转换器相比,AD9238具有与A/D转换器同样优异的动态性能,但是与两个单通道A/D转换器相比,AD9238可以实现比A/D转换器更好的抗串扰性能。
根据系统需求,外部可扩展相应大小的FLASH,供缓存数据和存贮程序。PXA270处理器集成了存储单元控制器,其外部的存储总线接口支持为:SDRAM、FLASH、ROM、SRAM、PC卡等。SDRAM具有单位空间存储容量大和价格便宜的优点,主要被用作程序的运行空间以及数据集堆栈区。系统上电启动时,CPU首先会读取地址0x0处的代码,在这段代码完成相应硬件初始化后,会将其他相应的程序代码传送到SDRAM中运行。系统设计中,使用4片HY57V561620FTP-H芯片构成128 Mbit的大容量存储空间。HY57V-561620是4 Mbit×4 banks×16 bit的SDRAM,单片容量为32 Mbit,这里,使用位扩展的方式扩展成32 bit的接口。
与上位机通信接口包括:以太网,带光电隔离的3路422/485串口,CAN总线。
针对该系统的特点,将软件平台在嵌入式Linux上实现。
图2 嵌入式Linux的分层体系结构
如图2,嵌入式Linux具有分层的体系结构,每一层都屏蔽了它以下各层具体的实现细节,为上层提供相应的功能接口,上层模块不需要知道下面各层的具体实现细节,只需要利用下层提供的接口来完成相应功能。正因分层的体系结构,提高了嵌入式Linux的安全性、稳定性以及便利性。
由于基于PXA270的系统资源受限,真正标准的Linux操作系统是面向PC的,这就需要裁减Linux内核,只保留所需要的功能使之适应受限的系统资源。对于一些可独立加载或者可以卸载的功能块,可以在配置内核时仅保留嵌入式系统功能真正实现所需要的模块,卸载那些不需要的功能模块。系统对数据采集的实时性有一定要求,而内核中的虚拟内存管理机制对实时性有所影响,可以将其屏蔽从而增强Linux的实时性。
数据采集系统中,PXA270属于X86体系结构,与一般PC使用的Linux操作系统兼容。因此,可以使用X86体系下Linux系统的gcc编译器,对裁剪过的Linux 内核源代码进行编译。本系统增加了对文件系统和GUI的支持,其中所实现的文件系统包括:基本文件的系统体系结构,基本可执行程序,配置文件,设备/dev/hd* 和/dev/tty*,程序运行所需的库文件。GUI是实现软件可视化设计需求所必需的,用其所实现的图形界面也为将来的现场检修维护提供便于操作的图形界面。
BootLoader是一段小程序,用于引导操作系统或者用户应用程序。BootLoader用于对必要的硬件设备进行初始化、建立内存映射,为最终内核或用户应用程序的启用准备好正确的软硬件环境。
为了完成系统的功能,实现应用程序对硬件的控制,需要对串口以及I/O口编写相应的设备驱动程序。设备驱动程序运行在内核空间,是内核的一部分,用于完成内核与硬件之间的交互。设备驱动程序的主要功能包含:对设备初始化、设备使用完成后对设备以及其使用相关资源的释放、驱动程序与硬件之间数据的交互、应用程序与驱动程序之间的数据交流、对设备出现的异常情况的监测和处理。
设备驱动程序的功能主要通过对中断处理实现。为了使系统更好地工作,完成中断的功能,一般把中断处理程序分为上半部和下半部。上半部也就是在关中断方式先被硬件中断触发的一般意义上的中断服务程序,所以要求运行时间应当尽可能短,处理尽可能快,否则影响系统性能;下半部适合处理占用时间较长,甚至有休眠的任务,可以在开中断以及任务串行化的环境下运行。实时性很强的任务被驱动程序上半部处理完成后会调用queue_task函数,这样就会把下半部处理函数挂入到立即队列中,并激活立即队列,再通过调用mark_bh函数,下半部就可以以最高最优级被先执行。
由于中断信号线数目极其有限,当数据采集系统面对多个数据源,如果对每个信号源都独占一根中断信号线时,显然中断信号线的数目无法满足要求。为了解决上面的问题,使系统具有更好的灵活性,则应使用数据源共享某根中断信号线的方式来实现中断。中断信号线共享的实现只需要在申请中断信号线时把request_irq函数的flags参数设置为SA_SHIRQ即可。此时的中断处理例程需要通过inb函数查看AD9238相应的寄存器来判断中断是否是这个芯片发出,如果不是则继续查找中断源。如果找到中断源,则读取相应的数据寄存器中的相关数据,放到驱动程序的缓存区AD_Data中,等待进程通过调用read函数来调用驱动程序中实现的read函数,并通过copy_to_user将数据拷贝到用户空间中。
在接收中断的过程中,为了防止由于丢失中断导致驱动程序没有读取AD9238中的数据并对其进行设置,使其不能发送中断导致整个驱动卡死的这种情况发生,这里需要使用内核定时器,如果在100个时钟滴答内没有收到中断,会自行调动中断处理例程,检测是否芯片已经发出了中断却没有收到。
用户进程是通过/dev目录下的相关设备文件来与硬件打交道的,通过调用对设备文件相关操作的系统调用从而对设备或接口进行操作。需要使用file_operations结构来实现设备驱动程序要实现的系统调用,file_operations结构中每一个成员都对应着一个系统调用。用户进程通过对/dev下设备文件的操作找到相应设备驱动程序的相关调用,通过读取这个设备对应file_operations结构中的函数指针,最终把控制权交给该函数。对设备驱动程序的编写主要是要实现与该设备相关的系统调用,也就是填充file_operations的各个域并编写相对应的函数。
设备驱动程序可以以模块的方式加入内核。init_module函数首先要检测设备是否存在;然后对系统中未使用的空闲中断进行申请;设备驱动申请输入输出缓存队列空间对提高系统的性能有很大帮助,可以通过调用kmalloc函数进行申请;以上工作完成后,对 register_chrdev函数进行调用就可以完成系统对设备驱动程序的加载。在clearup_module时,先通过调用free_irq函数释放掉申请到的中断资源,然后调用kfree函数释放初始化时申请到的内存空间,最后通过调用unregister_chrdev函数来完成对这个已经注册的字符设备驱动程序的释放。
系统的应用程序由多个功能模块构成,包括数据采集、数据处理和数据通信等模块。
(1)数据采集模块通过对I/O接口的操作,实现对数据的采集,系统中利用inb、inb_p、outb、outb_p这4个函数实现设备中数据的读取和写入。inb_p、outb_p相对于inb、outb,需要在存取I/O时有等待(pause),可适应响应较慢的I/O设备。Linux内核提供对端口使用状况的控制及查询功能,合理利用这些功能就可以防止I/O读写时发生冲突。端口使用之前,检查相应的I/O端口是否正在被使用,如果当前状态为空闲,就把相应端口标记为正在使用,在使用完后进行释放。
(2)数据处理模块完成数据的数字滤波以及其它处理功能,并将数据导出存到相应文件中。最终要将处理后的数据经过适当接口传到上位机。
(3)数据通信模块负责从缓冲区读取数据,并发送给上位机。
应用程序的工作流程如图3。
图3 应用程序工作流程图
从图3可以看出,应用程序完成了以下工作:(1)初始化操作,开辟一块共享缓冲区,并为该缓冲区加一个互斥锁。(2)创建3个线程,分别对应3种数据通信方式:socket网络通信,485串口通信,CAN总线通信。这3种数据通信方式负责把数据传送给上位机。
在主线程中,打开驱动程序设备文件,并从这个设备中读取数据。由于设备read()函数是阻塞函数,所以使用了select()函数设置了一个等待时间,使得读取操作为非阻塞操作。当有数据可读时,就调用read()函数,把驱动程序处于内核区的数据传递给用户区的数据缓存,也就是主线程把数据写入了共享缓冲区中。
在socket网络通信线程中,先要创建一个用于通信的socket文件描述符,并使用bind()函数绑定本地的网络地址(IP)、端口号(Port);然后循环检测缓冲区是否有数据可读,如果有,就读取出来并调用sendTo()函数把数据发送给对方。
在485通信线程中,先要打开串口设备,并设置串口的相关数据,如波特率,数据位,停止位等,然后也是到共享缓冲区读取数据,并通过write函数将数据发送给上位机。
在CAN总线通信线程中,首先打开CAN总线设备文件,进行一系列的初始化操作,然后判断共享缓冲区的数据是否可以读取,如果可以就读取下来,通过CAN总线给上位机传输数据。
本文设计了一种通用的高性能信号采集系统,可以通过加载不同的应用程序使用在不同的应用场合,具有集成度高、低成本、高性能、多用途的特点。数据采集系统调试非常方便,可靠性高,扩展方便,组合容易,可以根据现场提供的通信条件如422/485串口、以太网,或者CAN总线与上位机通信,便于将现场采集到的数据可靠地上传。本系统现在已经应用于400 km/h高速综合检测列车上应答器的数据采集,高速列车上多处现场监控和数据采集设备也采用了本系统。
[1] 孙天泽,袁文菊,张海峰. 嵌入式设计及Linux驱动开发指南[M] . 北京:电子工业出版社,2005.
[2] 石秀民,魏洪兴. 嵌入式系统原理与应用—基于Xscale与Linux[M] . 北京:北京航空航天大学出版社,2007.
[3] 朱利利,陈斌,何运桃. 基于PXA270的电源管理[J] . 电脑知识与技术,2009(17).
[4] Marvell Technology Group Ltd. Marvell PXA27x Processor Family Design Guide[Z] . 2007.