张丹红,张孝勇,刘 文
(武汉理工大学 自动化学院,湖北 武汉430070)
随着计算机技术的发展,处理器主频的不断提升,要求局部总线速度更快、带宽更宽。20 世纪90 年代提出的PCI(peripheral component interconnect)总线规范[1],很快从众多的局部总线中脱颖而出,得到各大主流半导体厂商的认可,并被越来越多的高档微机和服务器所采用。它支持多个外围设备,时钟为33 MHz,与CPU 时钟无关,它的总线宽度为32 位,并可以扩展到64 位,带宽达132 ~264 MB/s。由于PCI 总线的出色性能,基于PCI 总线的设备开发变得越来越流行[2]。
在自行设计的某过程控制系统中,出于安全性和稳定性等方面的考虑,计算机控制功能和监控功能由不同的计算机完成。监控功能由一台PC 机完成,PC 机需要通过某专用的16 位并行接口与控制计算机进行通信,获取系统的实时状态信息。为了实现监控计算机与控制计算机的高速并行通信,设计了一块基于PCI9054 的数据通信接口卡(简称为PCI_DCIC 接口卡),完成PCI 总线与高速并行总线之间的转换。
PCI 总线协议较为复杂,需要在PCI 总线与外围设备之间增加接口电路[3-4]。目前实现PCI总线接口电路的方法有两种:一是使用可编程逻辑器件FPGA 直接进行接口设计,该方法设计电路简单、集成度高、具有较大的灵活性,但由于PCI 总线时序的复杂性,导致研发周期长、风险高以及逻辑和时序验证工作繁琐;二是使用专用集成芯片结合可编程逻辑器件实现,这类PCI 接口芯片主要有AMCC 公司的S59XX 系列和PLX 公司的PCI90XX 系列。该方法开发周期短,易于实现,笔者采用PCI9054 芯片[5-7]和Altera 公司的MAXⅡ系列CPLD 设计接口电路。
笔者通过CPLD 内部逻辑编程的方法在PCI接口卡上设置控制寄存器、状态寄存器和中断寄存器等内部功能寄存器,用来管理PCI 接口卡的正常工作。同时在接口卡上设计SRAM 进行双向数据缓存,以确保PCI_DCIC 接口卡的数据传输速率和准确性。
PCI_DCIC 接口卡为一块安装在监控计算机中的PCI 接口卡,它与外部控制计算机通过16 位的并行总线相连,以实现监控计算机与控制计算机之间的并行数据传输。
16 位并行接口包括16 位数据信号、8 位状态信号和8 位控制信号。接口卡通过CPLD 芯片与并行接口相连,CPLD 可以方便地通过编程获得与并行接口时序相匹配的接口时序。
整个PCI_DCIC 卡由3 个部分组成,PCI 桥接部分PCI9054、CPLD 控制逻辑和CY7C1022 SRAM,板卡结构如图1 所示。
图1 PCI_DCIC 卡结构图
PCI9054 是PLX 公司生产的专用PCI 桥接芯片,它提供了一种灵活简单的接口,将复杂的PCI总线信号变成简单的用户信号,供开发者使用。
CPLD 控制逻辑的核心部分为可编程逻辑器件EPM570。它负责PCI9054 与静态RAM 之间、静态RAM 与外部并行接口之间、PCI9054 与外部并行接口之间的信号转换。
CY7C1022 SRAM 为32 kb × 16 bit 的静态RAM,作为PC 机与外部并行接口之间数据传输的缓冲存储区,用以提升整个系统的传输速率。SRAM 被分为两个存储区,分别用来存放PCI 接口到外部并行接口和外部并行接口到PCI 接口两个传输方向的数据。采用中断方式实现PCI 接口与外部并行接口之间的双工通信,确保数据的准确传输。当并行接口端准备向PCI_DCIC 接口卡写数据时,首先向控制寄存器内写入相应指令,接口卡通过内部逻辑判断是否同意并行接口端数据传输申请,并将结果反映在状态寄存器上,并行接口端再读取状态寄存器值。若接口卡同意申请,并行接口端开始向接口卡上的SRAM 内写入数据。数据传输完成后,输出中断信号,通知PCI 端数据传输完成,PCI 端便可读取已经写入的数据。
PCI 接口电路采用PCI9054 芯片,其接口电路如图2 所示。
PCI9054 芯片管脚主要包括3 个部分,即PCI总线信号线、本地端信号线和EEPROM 信号线。图2 中的# 表示该信号低电平有效。
图2 PCI9054 接口电路图
PCI9054 上的PCI 总线信号线直接与PCI 总线插槽上的相应端口连接。可在这些信号线之间串联33 Ω 的电阻,改善信号的效果。其他的信号线连接10 kΩ 电阻进行上拉或者下拉,使电路在上电时获得一个初始状态。
将PCI9054 的EECS、EESK、EEDI/EEDO 3个引脚连接至EEPROM,使用33 MHz 有源晶振为PCI9054 以及CPLD 提供时钟信号。
PCI9054 芯片本地端LA[31:2]、LBE[3:0]#、LD[31:0]、LW/R#、ADS#、BLAST#、LHOLD、LHOLDA、READY#和LINT#引脚连接至CPLD 芯片,用于控制PCI9054 芯片对PCI 局部总线时序的转换和数据通信。其他不需要控制的引脚连接10 kΩ 的上下拉电阻。
PCI9054 采用C 模式下的16 位本地端从模式,图3 为该模式下本地端写操作时序图,从图3可以看出PCI 总线经PCI9054 芯片转换后得到的简单本地端总线时序。
图3 PCI9054 从模式16 位本地端写操作时序图
配置PCI 配置寄存器比较简单,主要是填写生产商ID 号、器件ID 号、类码子系统ID 号、子系统生产商ID 号和存储空间配置等基本信息。对于PCI9054,其生产商ID 号为10B5,器件ID 号为9054,子系统号为9054,子系统生产商ID 号为10B5,类码号为0680,表示其为桥设备中的其他桥设备类。
PCI 存储空间分为MEMORY 空间和I/O 空间两类,它们独立寻址,并使用不同的总线操作命令进行访问。MEMORY 空间适用于设备功能寄存器较多或数据流量较大的场合,例如网口芯片、PCI-PCI 桥等。I/O 空间适用于设备功能寄存器较少或数据流量较小的场合,例如串口芯片、LED 控制寄存器等。PCI9054 的BAR2 空间(即本地地址空间为0)设置为I/O 模式,PCI 通过该模式对板卡上设计的功能寄存器进行访问。PCI端BAR3 空间(即本地地址空间为1)设为MEMORY 模式,用于存储数据。
PC 机在上电时需要识别PCI9054,就要根据配置空间的信息来识别该设备,一般使用EEPROM 来保存配置信息。可以利用专用的编程器事先将要配置的信息写入到EEPROM 中,也可以使用plxsdk 软件中的plxmon 工具对EEPROM 进行配置。
EEPROM 选用Microship 公司的93LC66。当电路板上有EEPROM 时,PCI9054 的EEDI/DO管脚连接3. 9 kΩ 上拉电阻;没有EEPROM时PCI9054的EEDI/DO 管脚连接1 kΩ 的下拉电阻。
寄存器LASORR[31:0]:PCI-to-Local 地址空间0 范围寄存器设置为0xFFFFFFF1,表示设置16 位I/O 访问空间,用于存储板卡寄存器上的信息。
寄存器LASOBA[31:0]:PCI-to-Local 地址空间0 的本地基地址设为0x30000001,表示空间0 的基地址为0x30000000。
寄存器LASIRR[31:0]:PCI-to-Local 地址空间1 的范围寄存器设为0xFFFF0000,表示设置存储空间为64 kB。
寄存器LASIBA[31:0]:PCI-to-Local 地址空间1 的本地基地址寄存器设为0x7FFF0001,表示空间1 的本地端基地址为0x7FFF0000。寄存器的最低位为1,表示使能地址映射有效。
上述4 个寄存器值可以通过EEPROM 设置,在实际操作时,PCI 驱动程序还需要设置PCIBAR0和PCIBAR1 的PCI 端基地址寄存器。假设PCIBAR1 设置为0x12300000,那么在PCI9054 芯片的PCI 端实际地址(AD[31:0])为0x12300000 +offset(偏移地址),而在PCI9054 芯片的本地端地址(LA[31:2],LBE1,LBE0)则为0x0x7FFF0000 +offset。
PCI_DCIC 板卡通过CPLD 的可编程逻辑编程来实现PCI 接口与外部并行接口之间信号变换。根据功能采用顶层原理图方式将CPLD 内部逻辑程序进行模块化划分,结合Veilog HDL 语言[8]进行各子程序设计。
CPLD 内部逻辑主要由PCI 地址解码、PCI 数据通道、SRAM 地址模块、SRAM 数据模块、状态寄存器、控制寄存器和中断寄存器等构成。其中,实现PCI 地址解码的Veilog HDL 程序如下:
通过PCI9054 配置寄存器本地端基地址最高两位LA31 和LA30 的设置来区分bar2 空间和bar3 空间的地址。由于PCI9054 设置为16 位本地端模式,故LBE1 信号为地址LA1。对bar2 低位地址进行解码用来片选内部状态寄存器,控制寄存器和中断寄存器(cs0,cs1,cs2)。当访问bar3 空间时,LA[16:2]和LBE1 构成本地端有效的16 位地址。从而实现PCI 地址解码功能。
设备驱动程序设计采用的是Windows 下的WDM(windows driver model)驱动程序模型[9-10]。使用Windows DDK 开发工具,代码简洁清晰,效率高,具体的开发在VS2008 环境中进行。
驱动程序主要包括初始化子程序、清理子程序、派遣子程序、中断服务子程序和DPC 子程序等。
接口卡采用中断方式进行数据传输,PCI 接口的中断处理流程为:应用程序通过DeviceIo-Control 程序将事件对象传入驱动程序中,然后通过ObReferenceObjectByHandle 程序来将驱动中的事件和应用程序中的事件关联起来。当有中断到来时,KeSetEvent(pdx->pEvent,IO_NO_INCREMENT,FALSE)程序将事件对象置为有效,则此时应用程序中就会执行相应的读写操作。
PCI 驱动程序完成应用程序的读写操作流程:当应用程序需要读/写数据时在应用层调用Readfile/Writefile 函数,该函数会发起一个IRP 传入到驱动程序,驱动程序首先会根据这个IRP 判断发起的请求是读还是写,相应地调用DispatchRead 程序和DispatchWrite 程序,该程序会将读写请求放入到请求队列串行执行。实际上为应用程序完成读写服务的是PCIStartIo 程序。在PCIStartIo 程序中,会根据IRP 中的请求读写字节大小等数据,调用READ_REGISTER_BUFFER_UCHAR/WRITE_REGISTER_BUFFER_UCHAR 程序来对数据缓冲区进行读写操作。
基于PCI9054 的PCI_DCIC 卡较好地完成了PCI 接口到外部并行接口之间的转换。控制逻辑采用Altera 公司的CPLD EPM570 实现,程序采用模块化方式编写,简化了程序设计过程,使程序设计、调试和维护等工作更加方便简单。通过CPLD 内部逻辑编程设计PCI 接口卡的内部功能寄存器,使上位机程序对接口卡状态的查询和逻辑控制更加方便,接口卡更加高效,运行更加稳定。同时,接口卡上设计的SRAM 双向数据缓存确保了数据准确快速地传输。
[1] PLX Technology Inc. PCI9054 data book,Version2.1[R].USA:PLX Technology Inc,2000.
[2] TAN B Z,XU Y J,CHAN T,et al. PCI bus interface technique and application in high speed data acquisition system[J]. Application of Electronic Technique,2002(1):21-23.
[3] 尹勇,李宇.PCI 总线设备开发宝典[M].北京:北京航空航天大学出版社,2005:86-132.
[4] 李贵山,戚得虎.PCI 局部总线开发指南[M].西安:西安电子科技大学出版社,1997:56-98.
[5] 张丽,阔永红,傅丰林.基于PCI9054 的数据采集系统的实现[J].总线与网络,2007(6):144-146.
[6] 景志,马琰森. 基于PCI9054 的数据转换模块设计[J].电子设计工程,2011,19(1):29-31.
[7] 安冬冬,刘文怡,郅银周.基于PCI9054 从模式的数据卡设计与应用[J].计算机测量与控制,2010,18(10):2439-2440.
[8] 王金明.Verilog HDL 程序设计教程[M].北京:人民邮电出版社,2004:45-98.
[9] 武安河. Windows 2000/XP WDM 设备驱动程序开发[M].北京:电子工业出版社,2005:32-65.
[10]司玉梅,申会民.基于PCI 总线数据通信卡WDM 驱动程序设计[J].计算机测量与控制,2006,14(2):259-260.