一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。- n$ R; _$ b* t/ N" T6 \
SPI总线是Motorola公司推出的三线同步接口,同步串行3线方式进行通信:一条时钟线SCK,一条数据输入线MOSI,一条数据输出线MISO;用于 CPU与各种外围器件进行全双工、同步串行通讯。SPI主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。 SPI总线有四种工作方式(SP0, SP1, SP2, SP3),其中使用的最为广泛的是SPI0和SPI3方式。SPI模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果 CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。 SPI主模块和与之通信的外设时钟相位和极性应该一致。 以下是SPI时序图: 主要讲解一下广泛使用的两种方式设置: SPI0方式:CPOL=0,CPHA=0;SCK空闲状态为低电平,第一个跳变沿(上升沿)采样数据,无论对Master还是Slaver都是如此。 SPI3方式:CPOL=1,CPHA=1;SCK空闲状态为高电平,第二个跳变沿(上升沿采样数据,无论对Master还是Slaver都是如此。 其实对于SPI0和SPI1发送与接收数据,可以总结为一句话:上升沿采样数据,下降沿发送数据。全双工同时进行,当然,必须在CS拉低使能情况下。 6 B/ \9 ~: v+ c" Z* G/ c
二.FPGA作为Slaver实现SPI3方式与STM32通信 1.STM32方面:用库函数配置SPI1,设置CPOL=1,CPHA=1. 2.FPGA方面: (1)通过边沿检测技术得出SCK上升沿与下降沿标志,用于下面状态机中的数据采样及发送。 (2)根据时序图,采用2个状态机分别在SCK上升沿实现数据采样,下降沿实现数据发送。无论是采样还是发送,都是高位在前,从Bit[7]到Bit[0],共8位数据。 (3)最后通过边沿检测技术得出数据采样完成标志,用于用户操作。 以下是SPI3的时序图: 三.Verilog代码部分 测试工程代码:实现了STM32每隔200ms发送流水灯数据给FPGA,使FPGA系统板上的4个LED灯实现流水操作;同时,FPGA每隔1s发送计数数据给STM32,并在STM32系统板上的LCD屏出来,即:显示0-9循环计数。 但下面的代码只是SPI作为从机的驱动部分,包括SPI发送数据与接收数据。
: `& M8 @1 P; l+ J7 m5 y1 |- /***********************************************************************9 u" l5 R& d( V, j
- ****************** name:SPI_Slaver_Driver **************
( W6 `1 i7 C2 H" w+ }- O - ********** author:made by zzuxzt **********
8 F% n* z7 [$ y. G ` - ****************** time:2014.4.29 **********************
6 ~8 L( m6 G7 E0 i4 ~% I( ~6 {3 x I - ***********************************************************************/9 ]4 O$ L7 v) T C4 o7 B
- //use SPI 3 mode,CHOL = 1,CHAL = 1
; x4 w% ]" _; d6 e& j$ r - module spi(input clk,# [3 X$ Q3 F% c) H- M! E% [3 [2 r
- input rst_n,
( s+ o6 H+ u" {/ u) F9 x) e - input CS_N,& t( |' o' r1 r f( ~
- input SCK,7 h0 f8 U0 H+ S0 }
- input MOSI,! O% ^1 ~6 B8 M
- input [7:0] txd_data,* J5 m4 b. A k3 A6 i& `
- output reg MISO," S. X( X- [/ f7 [9 C3 t3 q
- output reg [7:0] rxd_data,
. J( z" r S8 ?) y; a) D7 h9 } - output rxd_flag); //recieve done,please transmit data2 k: i6 a7 ~3 Z2 p4 m
6 v! T4 \$ ], d- //-------------------------capture the sck-----------------------------
" A+ @2 [, ~, d4 R4 ~; q. p - reg sck_r0,sck_r1;; k$ [; j+ H" k, H
- wire sck_n,sck_p;0 d. l c; r% K- J0 P
- always@(posedge clk or negedge rst_n)
4 [* |& J' r0 `- K8 R; G - begin
* L. }1 I, P( v ` - if(!rst_n)2 R8 U2 p9 T' p1 q) l! J
- begin
. {9 H6 u. o+ y6 ]) {" Q+ O# |2 J - sck_r0 <= 1'b1; //sck of the idle state is high
: Q3 d9 I" a. E$ `( T/ V5 s8 n% G - sck_r1 <= 1'b1;9 B- Q% f! ~ S0 l" V; _& A9 y
- end
9 K) j# z; w6 F. `" ^& |8 b - else
0 {* L4 u# Z9 C/ X8 Q8 U - begin
# V3 c: G. t. D/ r3 y3 \+ J) B - sck_r0 <= SCK;; J. c7 \ o$ m1 M) d3 {' H9 Z
- sck_r1 <= sck_r0;
) \ a! M0 j# P( ] J - end. m1 g6 b6 n' _3 D4 x! j) L
- end
; `: G9 x, X }+ |" d, f' E - ; x+ i! S: j6 R6 x
- assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0; //capture the sck negedge3 n& |+ ], u) f
- assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0; //capture the sck posedge. ~8 j: w- ^. W3 a" M- g
1 U% Q' I8 V$ V0 B9 k. X- //-----------------------spi_slaver read data-------------------------------: A2 x; M2 ~: i* m( B7 m
- reg rxd_flag_r;
' h$ p7 ]7 N7 J" ] r( P - reg [2:0] rxd_state;
2 ^" e2 k+ M% Z - always@(posedge clk or negedge rst_n)$ E' ~8 Z0 \3 m
- begin
) d R4 d$ m8 T - if(!rst_n)
, e6 l# ?6 u" d+ A3 ?" T - begin
j1 C. x" R( `; s, v1 q0 m% G - rxd_data <= 1'b0;: d* G7 d S0 O) I7 d2 p- l
- rxd_flag_r <= 1'b0;7 D1 D: W) ~, l
- rxd_state <= 1'b0;/ _4 ^' x' J: v0 K, a; k/ |
- end4 o; a7 B: Y2 q. ^( }# v( b8 P, \; r- M
- else if(sck_p && !CS_N)
/ \3 E5 T, o: a% j6 c. Z" E/ O - begin- ^$ B' \# Y! w: Z. X4 w1 E
- case(rxd_state) h5 b2 W+ @* @( g0 M1 r: S, V
- 3'd0:begin
3 Q. L6 e& ^/ P - rxd_data[7] <= MOSI;
8 Y. W- t& W( ~( z+ i& | - rxd_flag_r <= 1'b0; //reset rxd_flag
4 w0 D5 Y0 [7 r - rxd_state <= 3'd1;
5 S! V, [3 f, M# H7 m) i - end) f* Y. P4 u; Y- x+ y
- 3'd1:begin" I8 D* [- C5 \8 Z4 W% ^
- rxd_data[6] <= MOSI;
4 l. Z& w6 L5 {, q+ F4 a5 n - rxd_state <= 3'd2;- H: p& f( k3 [2 @0 [ R0 J x a
- end
0 ^* V- x6 V' A: u# u - 3'd2:begin1 D0 s" l* t" K9 y7 d
- rxd_data[5] <= MOSI;
/ a$ `6 w% }& D8 o% F - rxd_state <= 3'd3;5 _, l4 f, W k% G+ l+ {
- end
7 X+ W/ {) Y. _ - 3'd3:begin
8 i$ P; j8 u8 t% z3 y - rxd_data[4] <= MOSI;
* @/ w! ]; `1 Y' C+ J; g - rxd_state <= 3'd4;" u6 @: |0 ~1 t1 f
- end6 [! z4 t: q* w
- 3'd4:begin1 R8 K, Y3 D+ V. a! Q) c- b
- rxd_data[3] <= MOSI;8 j3 M( K& m. k3 H) |% O' W. Y
- rxd_state <= 3'd5;) w, g# \5 k1 ~/ @- }9 ~
- end
) x* n: W, ^, t. G - 3'd5:begin
6 `7 v' Y5 K1 E3 P& A0 o7 z - rxd_data[2] <= MOSI;
/ e, ^6 {: Q C7 M: \& x - rxd_state <= 3'd6;& q0 [6 v4 e, R2 F- K$ a
- end5 W( j' \% J [& R) z
- 3'd6:begin u, G( `* C- t3 u2 A
- rxd_data[1] <= MOSI;
& O1 o, k6 G. d8 g( r \$ ? - rxd_state <= 3'd7;
4 b& _# h/ I1 ^6 M - end
# m9 \3 q8 I$ S( z1 k/ {8 s - 3'd7:begin
% N' {. Z# R, c - rxd_data[0] <= MOSI;
& I5 B' E5 V& |% l3 f - rxd_flag_r <= 1'b1; //set rxd_flag
% z$ ~9 G$ G& z# ^6 |. \( s1 u/ Q - rxd_state <= 3'd0;
. v' }% [. G& {2 j( |' F& L - end' D X+ ^; D' M/ F
- default: ;
- ^( }5 M. v. z; S' u" ^ - endcase
. P5 u: E; O: R4 i! t. ]- o/ v; U - end# u9 G( l& @* D# u6 d2 R) i( ]
- end
* ] f/ @7 Q; g% k7 _' j - . ?1 ?$ @* k! r
- 2 ]3 }( E# Q1 _* U
- //--------------------capture spi_flag posedge--------------------------------4 ~5 J: W- O- V) o3 V" P& [) d
- reg rxd_flag_r0,rxd_flag_r1;% U& _4 ~: k. O+ i, j
- always@(posedge clk or negedge rst_n)
7 X0 r6 Q7 A, C - begin
. I5 ~& v5 z! u1 i! X - if(!rst_n)
! f F' s' p1 H# G2 f: A# X8 N- H - begin
) F7 M- g9 ?6 L2 t) P$ v - rxd_flag_r0 <= 1'b0;1 c- l: ^2 _9 c9 K' }' \. t
- rxd_flag_r1 <= 1'b0;
8 c4 }0 E i& R - end$ [9 G% L& f2 t/ D- C4 T
- else& D& j! D+ H ~- F6 X( N1 q
- begin
8 x# j+ @) G6 Y# B8 l1 r - rxd_flag_r0 <= rxd_flag_r;: c5 Q8 s/ d' b' F: C E
- rxd_flag_r1 <= rxd_flag_r0;
6 ~3 K- c ]/ E# O; ~ - end
; P+ Q- R9 X ~* B& @; S - end6 s% q! B! }' T2 z+ o
. W9 G; Y: r5 I- assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;5 J# k4 Q5 P( [+ v/ X" r7 H6 }
- `& s; ~2 E& F. u5 u2 {- //---------------------spi_slaver send data---------------------------
6 r2 n& N2 l, b - reg [2:0] txd_state;; A) N9 U9 t- a9 N, N7 e
- always@(posedge clk or negedge rst_n)
& E' z( u) C& p' G% s0 C - begin
1 u! t- ]1 U* U8 c% C' U - if(!rst_n)
- ]2 y9 g! }5 n% h - begin" n" M6 s8 {) Y2 {" v1 ~3 B
- txd_state <= 1'b0;
7 Z7 I: T# [- e. O6 a' d' E - end
J8 j. q0 q- ?$ D' v" c - else if(sck_n && !CS_N)
% x- D; ~7 l7 { - begin" I/ @2 R2 @* _0 {* |) N, X! i8 N
- case(txd_state)
: K: r$ f! }; ]0 @0 f% L* o - 3'd0:begin3 B& M1 D( N8 v$ ?
- MISO <= txd_data[7];0 {9 n1 r+ w( [! I2 {! S* F6 \
- txd_state <= 3'd1;% ? Y! {' w m2 J$ j( i
- end' o# K6 {8 }5 j2 B- E9 Y2 u
- 3'd1:begin
# t7 E* x) [" W/ X; E+ a - MISO <= txd_data[6];
/ v7 Q% D& G# X, B - txd_state <= 3'd2;" C, S4 h# }, r1 \/ i
- end
7 e, ^6 V& J! L7 C+ b - 3'd2:begin+ z: u5 B2 W! [
- MISO <= txd_data[5];
" H Q; |+ u0 y, e4 z - txd_state <= 3'd3;
: {( u6 Z$ V6 v2 ?( t4 Y. y - end
" x2 L7 U( N- L% D& ]# m7 H - 3'd3:begin; L0 } K# p _/ j# t# Y& |* ~
- MISO <= txd_data[4];6 T7 G' P5 N* h% g: R
- txd_state <= 3'd4;( a) @ S. Z$ S) h# |$ i. {( Y
- end7 L$ R& g& {8 t; y- n
- 3'd4:begin# ~; @. i$ `3 q! S. c
- MISO <= txd_data[3];2 M# }9 N! Y+ ?8 J, {+ F, L: [7 d
- txd_state <= 3'd5;- b# C7 I$ y$ J. A( y/ t* ?
- end
) I/ m$ m% W) U) |% `2 ?( n; l - 3'd5:begin- B" t0 o8 q) R8 K
- MISO <= txd_data[2];5 c% y1 t" Z' M6 W2 v+ G
- txd_state <= 3'd6;
% D8 ?( t+ s: K# X; u# k - end
' ^" K- ?) R1 M- y" b3 D+ E - 3'd6:begin
! F2 I! M* |1 `* g. D - MISO <= txd_data[1];" f" h4 Q6 J5 ]
- txd_state <= 3'd7;
}# U- N9 ^0 X) v/ o6 x, R - end5 {* b3 v3 L1 B" D0 N5 J. G( x5 T
- 3'd7:begin
+ ?' N/ H1 n! @, K( V6 G; a" p - MISO <= txd_data[0];
+ ^$ A6 O+ L' \, M7 c1 Q - txd_state <= 3'd0; r+ J$ @+ H& ]% b7 P* T; v g) b& ?
- end
5 O* r/ Q+ |; s) G0 l: _: W - default: ;2 m" U7 a, v& P
- endcase
* r- _4 Y5 v, \8 J, r7 c2 ?: ~3 R - end, W# d6 z8 R ^. f; J+ Z
- end
3 H/ A' z3 I9 S: a9 f - ! B. j: d1 Z8 T% _
- endmodule
复制代码
/ x4 D- \8 e2 G$ T$ i+ B
8 N3 p7 F+ _9 `- ?. _3 I# j. x& ~
3 H( V; ?9 U; A, [, W/ V4 X# F
8 }: _; a/ X8 ~1 H |