TA的每日心情 | 开心 2019-11-20 15:05 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
2 j0 |0 h6 w4 r$ A$ l
/ x+ G1 d1 B5 P
& [& {0 _* P8 v- r
引言
! q) p1 C6 K- q& v) D3 ~ O, m
1 o0 `' Z5 M; |( @0 Z4 Q 8位单片机在嵌入式系统中应用广泛,然而让它直接与PCI总线设备打交道却有其固有缺陷。8位单片机只有16位地址线,8位数据端口,而PCI总线2.0规范中,除了有32位地址数据复用AD[3~0]外,还有FRAME、IRDY、TRDY等重要的信号线。让单片机有限的I/O端口来直接控制如此众多的信号线是不可能的。一种可行的方案就是利用CPLD作为沟通单片机与PCI设备间的桥梁,充分利用CPLD中I/O资源丰富、用户可自定制逻辑的优势,来帮助单片机完成与PCI设备间的通信任务。
% }, w# K6 ^$ R q9 e, K* @) T& d# r4 @# ?
1 PCI接口设计原理/ s; s; g% M; n# l" o7 O2 w' t
) D6 f/ ^4 ^, Z0 A7 V/ m W# W 1.1 PCI总线协议简介8 [% g) Z7 ^% \- Q7 ]7 D# V
3 c9 o; S' A6 a' g/ b" r 这里只讨论PCI总线2.0协议,其它协议仅仅是在2.0的基础上作了一些扩展,仅就单片机与PCI设备间的通信来说,意义不大。PCI总线是高性能局部总线,工作频率0~33MHz,可同时支持多组外围设备。在这里,我们只关心单片机与一个PCI设备间通信的情况,而且是以单片机与CPLD一方作为主控方,另一方作为PCI从设备。这样做的目的是为了简化问题,降低系统造价。7 r6 V, G0 V6 B& g9 _
3 K' e6 `. m4 a0 A t; ?1 I
PCI总线上信号线虽然多,但并不是每个信号都要用到。实际上PCI设备也并不会支持所有的信号线,比如错误报告信号PERR与SERR在网卡中就不支持。我们可以针对具体的应用选择支持其中部分信号线,还有一些信号线可以直接连电源或接地。下面简单介绍一下常用信号线的功能。1 T! [2 f8 y# o. [/ o/ J& r5 V. ]. H
7 U1 K2 w+ B3 Y5 y
AD[31~0]:地址数据多路复用信号。在FRAME有效的第一个周期为地址,在IRDY与TRDY同时有效的时候为数据。
7 Y* j9 N6 m+ T0 L; ?4 w
R( v: G6 J* X; w4 N5 ? C/BE[3~0]:总线命令与字节使能控制信号。在地址中传输的是总线命令;在数据期内是字节使能控制信号,表示AD[31~0]中哪些字节是有效数据。以下是总线命令编码的说明:8 q# p& F1 \4 R
( `3 P. ~2 A1 U6 ]3 W3 J2 x# x
C/BE[30]# 命令类型说明C/BE[30]# 命令类型说明+ a" b) } X( F$ B. c3 {
1 |2 @! f8 Y- ?- j+ F+ m 0 0 0 0 中断应答 1 0 0 0 保留
/ A9 F5 v! E, p) i1 N
! a& s! J' a/ s' R# a8 f 0 0 0 1 特殊周期 1 0 0 1 保留
* p3 U0 W6 ~% a/ H5 m
/ h8 m9 C2 N9 |, K" I 0 0 1 0 I/O读 1 0 1 0 配置读
4 e+ b r+ g$ w; k6 \6 D
; y! l( l% E& e1 h 0 0 1 1 I/O写 1 0 1 1 配置写" U* m j. P- n9 q
! b8 F) e. z. P# ~! C. K5 \6 E
0 1 0 0 保留 1 1 0 0 存储器多行读3 o9 S/ p# t, d" D
, S; |7 g! F+ v1 x5 P8 I! s
0 1 0 1 保留 1 1 0 1 双地址周期
! k0 b$ h* `9 A* l. W9 ?6 C/ Z% a& ]& S% x0 ?; [
0 1 1 0 存储器读 1 1 1 0 存储器一行读7 P0 E9 [$ I% @9 j9 I
5 k: e% g+ K! m9 r$ e
0 1 1 1 存储器写 1 1 1 1 存储器写并无效: M: D' }' L) F4 U
7 W: p# ?. t% |, C PCI总线上所有的数据传输基本上都由以下三条信号线控制。* s5 V& |2 Y0 g& [! k
4 w2 E& `" W r1 y) z# k1 W4 `3 v. p& | FRAME:帧周期信号。由主设备驱动,表示一次访问的开始和持续时间,FRAME有效时(0为有效,下同),表示数据传输进行中,失效后,为数据传输最后一个周期。' Y F% _. E% G8 q8 Q4 ? v h
% o& y. F* @( d, X! }- j
IRD:主设备准备好信号。由主设备驱动,表示主设备已经准备好进行数据传输。
' C, I- q2 G5 _' u
" h6 g: L' \. R1 u3 Y; S4 y, ] TRDY:从设备准备好信号。由从设备驱动,表示从设备已经准备好进行数据传输。当IRDY与TRDY同时有效时,数据传输才会真正发生.
" ]% x, h; R/ E
7 h6 W: k8 N9 c% B2 q另外,还有IDSEL信号用来在配置空间读写期间作为片选信号。对于只有一个PCI从设备的情况,它总可以接高电平。IDSEL信号由从设备驱动,表示该设备已成为当前访问的从设备,可以不理会。
: `- v! Y9 o* e
" l* m% ^* X7 z$ n ~4 K 在PCI总线上进行读写操作时,PCI总线上的各种信号除了RST、IRQ、IRQC、IRQ之外,只有时钟的下降沿信号会发生变化,而在时钟上升沿信号必须保持稳定。7 X+ c1 w2 Z5 M, J. Z. x
- v# c7 _ S7 e3 [6 G 1.2 CPLD设计规划
, V6 \9 ?4 L$ ^" |6 m) l6 k' S- d+ K. E, N
出于对单片机和CPLD处理能力和系统成本的考虑,下面的规划不支持PCI总线的线性突传输等需要连续几个数据周期的读写方式,而仅支持一个址周期加一个数据周期的读写方式。对于大部分应用而言,这种方式已经足够了。图1是经过简化后的PCI总线读写操作时序。
* [1 i5 f4 ~7 T: { X3 p' M3 X3 D3 V! q: Q4 x s
在CPLD内设有13个8位寄存器用来保存进行一次PCI总线读写时所需要的数据,其中pci_address0~pci_address3是读写时的地址数据;
& q! _0 ]" r+ p/ z: W4 A( d; n# d3 n. F( p
6 B! N. }" d/ I8 L
& |4 y1 C3 u2 _* @" ~图1 简化的PCI写操作时序
: O3 t" I1 O) a. J: g8 \$ P1 D+ @3 R
* p+ `* Y* m2 a$ Y+ c, z" c7 e: y pcidatas0~pci_datas3是要往PCI设备写的数据;pci_cbe[3~0]保存地址周期时的总线命令;pci_cbe[7~4]保存数据周期时的字节使能命令;pci_data0~pci_data3保存从PCI设备返回的数据;pci_request是PCI总线读写操作状态寄存器,用于向单片机返回一些信息。当单片机往pci_cbe寄存器写入一个字节的时候,会复位CPLD中的状态机,触发CPLD进行PCI总线的读写操作;单片机则通过查询pci_request寄存器得知读写操作完成,再从pci_data寄存器读出PCI设备返回的数据。& a, A& K# M- J/ s0 \: K; k
9 M. g- r) G) N5 p0 }" |2 i
CPLD中状态机的状态转移图如图2所示。每一个状态对应FRAME与IRD信号的一种输出,而其它输入输出信号线可由这两个信号线和pci_cbe的值及TRDY的状态决定。当FRAME为有效时,AD[31~0]由pci_address驱动,而C/BE[3~0]由pci_cbe低4位驱动;当IRDY有效时,C/BE[3~0]视总线命令,要么由pci_cbe高4位驱动,要么设为高阻态,而AD[31~0]在pci_cbe[0]为“0” (PCI读命令)时,设为高阻态,而在pci_cbe[0]为“1” (PCI写命令)时由pci_datas驱动。另外一方面,一旦TRDY信号线变为低电平,AD[31~0]线上的数据被送入pci_data寄存器,而C/BE[3~0]线上的数据被送入pci_request寄存器的低4位。 9 a" Q E, K0 q' B0 Y5 @, O1 ]
* S: k; ^; w# |' \; p
5 W" f U! L" [" t. R9 f; Q& P3 J6 M: v0 O7 | N2 t8 J
图2 状态转移图
- ^2 `% O1 P2 |/ i* k% r% E0 A! B/ Q6 ^
考虑到在不正常情况下,PCI设备不会对PCI总线作出响应,即TRDY不会有效,为了不使状态机陷入状态S2的僵持局面,另外增设了一个移位计数器mycounter。当IRD信号有效时,计数器开始计数。计数溢出之后,不论PCI总线操作是否完成,状态机都会从状态S2转移到状态S3,即结束PCI总线操作。当TRDY有效时,会立即置位mycounter.cout。& q3 t) _9 d' @" |
: ~" x* N9 r, o' {5 L PCI总线操作是否正确完成,可查询pci_request的最高位是否为“1”,而IRDY与FRAME的值可分别查询pci_request的第4位和第5位。这两位反映了PCI总线操作所处的状态,两位都为“1”时可以认为PCI总线操作已经完成。在实践中,如果单片机的速度不是足够快的话,可以认为PCI总线操作总是即时完成的。
. e" X( a% K2 k2 Y
+ o3 O7 c, Q) |1 o4 _. Q 2 PCI设计接口实现; [. {& G( j# N5 z2 T( a: u8 P
9 w9 C* S' D0 v1 z7 e& f
2.1 CPLD VHDL程序设计1 n, Q; F' U- B* H0 u. \
3 |' J8 E- ]5 _6 ~! V
我们针对8位单片机控制PCI以太网卡进行了程序设计,CPLD器件选用Xilinx的XC95216系列。针对以太网卡的特点在逻辑上进行了再次简化,最终程序将适配进XC95261芯片中,并在实践中检验通过。
9 _/ Y, Y: Y5 s5 `( V, S
, l" ^# K+ m" j% O 以太网卡仅支持对配置空间和I/O空间的读写操作,而且这两个空间的地址都可以设置在0xFF以内,所以可以只用一个pci_address0寄存器,其它地址都直接设为“0”;如果再限制,每次只往网卡写入一个字节数据,则可以只用一个pci_datas0寄存器,其它数值在具体操作时设成与pci_datas0寄存器的一样即可.
. y) O/ R7 L, g* H; D, ]# }0 k$ C3 L: E7 j4 S) c5 f5 e: k2 L
2.2 单片机PCI读写C语言程序设计
4 a8 i, O1 q5 r0 W7 G9 J7 I
6 G3 O1 F! a9 `3 h6 a8 x; d 在CPLD在帮助下,单片机读写PCI设备就变得相当简单。首先,将pci_cbe等寄存器都声明为外部存储器变量,并根据CPLD的设计指定地址。然后,传递适当的参数给以下两个读写子函数,即可完成对PCI设备配置空间、I/O空间、存储器空间的读写操作。从PCI设备的返回数据存放在全局变量savEDAta中。
$ v$ c/ p# S8 s5 D X4 y2 s! l0 i8 g6 p- K& J; a
实际上在写PCI设备时,也可以从pci_data中得到返回数据。这个数据必须等于往PCI设备写的数据。利用这一点可以进行差错检验和故障判断,视具体应用而定。8 J, f8 o- g$ v' l2 W6 Y) {
5 T: E# E5 r9 ~* Q2 f, N! } bdate unigned char request;
$ ^- M1 `. m7 b: j0 _: K" y+ K X4 H: H. {% {# A
sbit IRDY0=request^4;& I2 c( V% h4 O& {' X' ~; o2 \
* n9 T! a% |* P/ `' l5 Q7 _
sbit FRAME0=request^5;7 W. r' x. y+ N- c+ z+ c6 X
. O7 N0 z; z! I' P2 L& T3 Z( r; @7 \- ` sbit VALID=request^7;
9 _, X0 X- L; {% a# P4 r8 J' x& p3 h
void readpci(unsigned char addr,unsigned char cbe){8 E( @6 F, N9 n# F1 l
+ l+ h, H7 s9 O6 y4 U
pci_address0=addr;8 E5 Z6 q+ H' Q
8 m+ W& d7 h- x4 B; z1 F. a: m pci_cbe=cbe;
) o: d# f) q O( U" M, \; O0 H
; c$ X1 e; Y2 g& [% u* O request=pci_request;" H" u9 B6 g. [- Q5 q8 N" B
4 @! h# s/ A" J7 C3 e% H: K( {2 G
while(!IRDY0 & FRAME0)) request=pci_request;2 H' X0 S, \5 v) s$ y" T/ w. K
- C* r8 ? l9 ?3 t1 |! f3 u savedata0=pci_data0;5 E4 k5 ]9 p" |/ b- n
( f7 g- n% n& {. P3 ^/ B) E: } C6 ~ savedata1=pci_data1;2 k+ ^/ B% M0 Z0 v2 \& {5 B3 v
' S) L1 N" M- A0 Z savedata2=pci_data2;
. d0 a( ^5 ?' J4 ~6 j' w# J& X- P
8 q' I9 d7 g; m( q savedata3=pci_data3;
! |; e$ x% U3 w& j# o9 \# }% V
if(!VALID)printf("Data read is invalid! ");8 z( h: A$ a+ _/ _& _
8 c$ W! b1 H+ }, S: E+ X7 v+ h } f4 r6 {0 d R+ i" h
& ]4 L- r" q, \# h, a: e4 l
void writepci(uchar addr,uchar value0,uchar cbe){: Q4 Y: v2 a4 z) h" x7 Z f
/ P# q4 \; o4 j: r% o3 Y9 F U data uchar temp;; [. e: t; a9 T( L+ m ?
2 E' _& x' L+ w* r8 d$ |+ ^
pci_address0=addr;
' Z* L' g1 K! }5 F9 y( z- i
) p3 e4 [0 E- {! ?2 L pci_datas0=value0;
8 {4 z# ?% d* c5 X3 Y" {* b2 G9 w; z8 _6 B. S
pci_cbe=cbe;
: e; l- M, ]' b. t$ r9 E6 _. W: S
6 v. W. h2 e! [4 B* s0 a% c3 p request=pci_request;
- [3 F1 s0 p2 k1 `* ~& ?! C0 p8 {( s) n+ k
while(!(IRDY0 & FRAME0)) request=pci_request;
3 l C& B8 @- \$ v
+ R1 G1 J+ E( q3 X+ l2 s) Z if(!VALID)printf("Data write is invalid!");( v \% E4 h9 @$ j" E* o
, G# m. k; ~! Z# b! e: m }
* w/ y9 j9 s" s, z
0 a; [# g6 J2 s$ w3 c( c; o 3 结论: S/ _ \* N! D& |9 W! {
1 z+ w. F3 \* n: _" O 用CPLD实现单片机与PCI总线接口的并行通信,电路结构简单、体积小,1片CPLD芯片足够,并且控制方便,实时性强,通信效率高。本设计方法已成功地应用于作者开发的各种数据采集系统中,用作单片机与PC104之间的并行数据通信,效果非常理想.
@( e: r4 n/ m5 B' J( O7 e
4 H* h/ ~3 v# O# n1 q. S% \$ G7 C/ _9 s
|
|