一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
+ C+ |# k4 E0 _4 N8 l# {! r 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拉低使能情况下。 ' v1 A$ Z4 r" E: Q" y
二.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发送数据与接收数据。
; [3 V. `; l y; S$ C6 \- q K- /***********************************************************************: W9 f' I$ G' k" }1 A: z& y, S
- ****************** name:SPI_Slaver_Driver ************** L; J% t+ B8 t J1 u& i
- ********** author:made by zzuxzt ********** M/ N# S# X: J V
- ****************** time:2014.4.29 **********************
6 I! x& W4 D! q - ***********************************************************************/
' q% p& I6 X% N2 u0 W | - //use SPI 3 mode,CHOL = 1,CHAL = 1& Z ^- K9 J6 Y0 o3 s& a
- module spi(input clk,% X- I$ k; S0 Y2 H0 O
- input rst_n,
; Q: [4 n: h0 L H - input CS_N,) M. D7 ^$ Y/ e3 R
- input SCK,
- L( N; { j/ n+ h$ S, P% N6 y - input MOSI,; U' F! F7 O" F y8 x2 E
- input [7:0] txd_data,
2 z4 C' {# [" \5 J0 C( v - output reg MISO,
: A1 j* J5 y, U: n$ { - output reg [7:0] rxd_data, J& E; y. V" Q& S$ }4 H2 M
- output rxd_flag); //recieve done,please transmit data# `# y5 I! M' _( N
# @; }3 K# t, C! F: H- //-------------------------capture the sck-----------------------------
! X. R' \# f, w - reg sck_r0,sck_r1;
$ I6 @+ Q1 r# ]& G - wire sck_n,sck_p;
) H) ^/ d/ u9 C - always@(posedge clk or negedge rst_n)
4 x" l# u) o) W9 j8 C) y5 x8 Z - begin
, K0 S! ^$ P% [1 h# \% `; ^( V - if(!rst_n)
' } Q% \& z9 S! R - begin
% ^6 l4 a) G# n h - sck_r0 <= 1'b1; //sck of the idle state is high, F5 ]# Y( m8 w8 s
- sck_r1 <= 1'b1;
: G2 J! S3 c4 r0 t2 I* l - end
+ |. \ y/ _2 ?& C - else
0 ?! J2 L6 I9 u+ p+ W3 X3 [ - begin( u- [/ g# x( f$ }% Y, T6 A
- sck_r0 <= SCK;$ Z [1 @% a2 l, l7 V+ G c, i
- sck_r1 <= sck_r0;1 }! U0 o" c, h
- end
3 E$ C# q9 s5 Y) y - end
0 r7 W. e; e/ q
7 \2 y2 e" X" l9 e* R' x- assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0; //capture the sck negedge' a: I) v+ P( u
- assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0; //capture the sck posedge- w- i& _+ I( _& `6 v2 j+ h9 r4 t
- & [* t9 X, q7 m1 g9 a( j7 d
- //-----------------------spi_slaver read data-------------------------------
. c9 ?$ s4 ^0 ]4 \4 V4 n: b - reg rxd_flag_r;, V# z% L8 o' _( w
- reg [2:0] rxd_state;
+ f* b! ]- Y* c1 x7 O - always@(posedge clk or negedge rst_n)7 `6 k4 I" c0 |
- begin
' K* b% x/ D6 E$ _' I ? - if(!rst_n)
) J; ~; c9 D$ s) N* ?/ s - begin+ e; i4 z6 ?( b' H
- rxd_data <= 1'b0;
" `0 V4 B/ I1 `0 S1 g" W* Z7 P# T& h# u - rxd_flag_r <= 1'b0;, @2 I3 U* v6 w6 V
- rxd_state <= 1'b0;" W7 \ @) h3 s5 s: N; d3 r
- end
4 v0 m3 y. W( }5 |5 W - else if(sck_p && !CS_N)
4 {2 W* U$ x: _3 O2 g- W% G* _ K' r - begin: Y0 O5 r/ f/ [9 H: `
- case(rxd_state)4 D; k. Q/ v1 k: N
- 3'd0:begin
- i1 k& x. }0 s" \# y, V8 h - rxd_data[7] <= MOSI;' l" {' O& Z3 T4 Q
- rxd_flag_r <= 1'b0; //reset rxd_flag
! X' v1 s* ^; I! W/ O D - rxd_state <= 3'd1;- T t4 C& Y, S. h
- end9 L$ O! B$ G) |" I
- 3'd1:begin
3 ^' \; p6 @! T( C0 o - rxd_data[6] <= MOSI;
; a) I2 h* E F( \ - rxd_state <= 3'd2;8 t' |# w" }7 s/ B" {* [: k
- end
9 s8 ^) g& W5 _( D% w- A - 3'd2:begin
1 G& c* F/ V7 |/ Z( a7 n - rxd_data[5] <= MOSI;
+ L! S' R$ [: P. q. H' k* O - rxd_state <= 3'd3;9 |* D5 G6 U3 w H0 g
- end
* B8 G$ g* K. p/ ~, ]: U - 3'd3:begin$ f/ M& q3 @; Q5 A$ q
- rxd_data[4] <= MOSI;! p% u s( @9 {3 U4 d
- rxd_state <= 3'd4; \) B( A6 ^+ T/ ?& Q; z% L9 r
- end3 H' f0 a5 I& j1 w( Q
- 3'd4:begin3 }$ G- K/ V0 @
- rxd_data[3] <= MOSI;
/ F8 }2 g& t1 e2 H; Q - rxd_state <= 3'd5;- `0 l/ Z! J" j8 W; H3 g
- end* j d2 x- |- x
- 3'd5:begin
$ Q; m- e# z' G: X. g - rxd_data[2] <= MOSI; @ b" m, e9 G
- rxd_state <= 3'd6;
7 q# O& p) M* q7 v& ]% \3 w - end( t& h9 J: z: E% i3 f3 C
- 3'd6:begin
; r k2 N2 b6 ]+ Z3 X9 d; b1 ` - rxd_data[1] <= MOSI;
5 X1 q* `' W4 k - rxd_state <= 3'd7;
- ` f9 c- y: R- {9 E2 g6 Y' p7 } - end3 D, G J5 y# X5 b* G5 _5 }" z
- 3'd7:begin
# [- f) g- u, L" E$ k. { - rxd_data[0] <= MOSI;5 A/ N% q1 s, k" Y) L6 r/ |
- rxd_flag_r <= 1'b1; //set rxd_flag
' ?& X. c W5 S% |2 @ - rxd_state <= 3'd0;" {6 G' Q# U5 b i& {6 j" B6 ?
- end( R a* M2 E+ l }, x6 z
- default: ;% W9 o7 ?( Z s9 u$ n
- endcase
6 ^4 H( T# V+ W* h - end7 p* a4 T/ P" b2 ^' }8 ~. V/ N8 p
- end
+ ~3 [; Z- h2 {% {5 d+ ^" d - % V$ f$ }7 I$ O" A' C- |4 T3 {
+ b& l& y) ]' b$ G- r& z* }- //--------------------capture spi_flag posedge--------------------------------
. \/ q; s# B- e7 l" Z - reg rxd_flag_r0,rxd_flag_r1;
5 |. `- `( V8 ?- v" A, w) {5 k! M9 v - always@(posedge clk or negedge rst_n)
; j0 P. Z' d5 N- W - begin
# r; ?. n( i( E8 Q" q4 O) u' q - if(!rst_n)
8 N$ J, l1 c. X5 `4 Z# `2 b/ T - begin
) a4 s; P3 s& ^/ @. `* E - rxd_flag_r0 <= 1'b0;' z% _. Y) j1 K0 [- h
- rxd_flag_r1 <= 1'b0;( ^9 h' ~4 ?3 {0 Z) k: J
- end
8 X0 B s7 i; K% u - else
l8 b P2 T& }5 P( E - begin
4 _2 u3 D- t: L2 h+ e0 O* V9 n4 t1 B+ ?' L - rxd_flag_r0 <= rxd_flag_r;
; U. ]6 Y9 S% N2 [; e8 S* N - rxd_flag_r1 <= rxd_flag_r0;
7 `# k" h' _( Y9 V& _3 I1 h8 z - end
4 K1 W3 c/ w8 {2 \2 W. o# N: _4 _ - end8 O* ]$ L) M' T U
% r2 {/ V& R# \, u: W0 ~- assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;/ D7 z3 `% U, K
- $ t0 v/ v+ J* W* o6 Z! L
- //---------------------spi_slaver send data---------------------------
6 E: f( }3 G0 R: Q# m - reg [2:0] txd_state;
1 e! ~5 C3 \8 _0 q# z) Y - always@(posedge clk or negedge rst_n)+ v' C6 k- T# g% I- R9 H( j( c
- begin
3 C( s: n, y, P8 T4 H - if(!rst_n)
/ t9 ?$ s4 ?& M - begin* I# Y, H6 Z/ O4 A2 @4 @" Q s
- txd_state <= 1'b0;
; {) t; x3 ~6 o8 ?4 x - end1 @ ^. k( e! Y/ \0 t, ^7 z) h
- else if(sck_n && !CS_N)
. f% K: Z. D- u. u, L - begin" ]+ r. p" g" @6 q. a
- case(txd_state)
$ o' F: B2 }" U - 3'd0:begin
6 l. A( C* U' m2 F& e! h( y# I - MISO <= txd_data[7];
, l3 H" ~7 h2 s# e) ~$ s7 i; k5 K - txd_state <= 3'd1;1 i% D/ d5 F; W$ a3 p0 Q; X# s
- end
9 r0 x' N' e+ e+ |% A - 3'd1:begin
1 E7 o0 Z0 P! o - MISO <= txd_data[6];
9 B* i( Y+ G- a1 u- R - txd_state <= 3'd2;
/ R9 X9 T5 \* ? K m9 o - end) n; w8 O6 x% ~2 B% h
- 3'd2:begin) X( E2 G0 m8 T1 H
- MISO <= txd_data[5];$ P' s0 c; u$ z6 F& o/ c9 i
- txd_state <= 3'd3;$ v6 l/ B4 F/ P+ h* b! W
- end. _; d3 M) T) D5 ~. \) I0 J5 [
- 3'd3:begin9 F$ e% T: B" x8 ?
- MISO <= txd_data[4];+ H0 X3 g i+ m1 a
- txd_state <= 3'd4;# }# ^ u- H2 x. G! ~
- end: ^( a! x" d4 Y$ F3 H
- 3'd4:begin
, b/ }, Z! e3 K& o& ^( _; S - MISO <= txd_data[3];0 Y& q7 F. [0 a9 {& ^) ~
- txd_state <= 3'd5;& ^/ O8 {' k/ c, U/ s) h
- end, i- _7 v6 c3 f7 i$ u
- 3'd5:begin
: o/ O$ [! z0 `1 ? - MISO <= txd_data[2];( Z Z3 b2 S7 t. ^( \
- txd_state <= 3'd6;
" y9 u" ?2 u% _9 F0 s9 {0 Q - end2 \1 S } m2 ~% X" v- B1 Z& \- b
- 3'd6:begin' Y9 ?3 b& A: b2 B, Q
- MISO <= txd_data[1];; t0 O) I! X3 {4 I# |
- txd_state <= 3'd7;
]! c3 C+ E' @) A% I3 J: D - end8 M# D/ y7 k9 ~" ^
- 3'd7:begin- U$ r+ B, M% S
- MISO <= txd_data[0];% Z5 ]9 ]7 j& j* S& j- p
- txd_state <= 3'd0;
1 p8 u: r1 V6 h) N, X5 B - end
, x- a9 O: @1 G X" }/ \ - default: ;
1 B) l# h# @0 d& c5 Q4 n - endcase, E+ Q( u2 k1 C7 [- B J
- end
/ v4 v5 K5 f$ `) P+ S3 y- b - end6 V9 \9 V8 ~7 [3 [, c& W3 a4 G1 U
0 n; c9 w8 z3 ]/ n- endmodule
复制代码 + i) f: {2 b5 n* i+ U: L: C9 ^9 y
+ X5 m9 Q0 l5 A+ g x
! \4 d- N) M0 }% D
% i' g0 c, n3 F/ y |