|
一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。8 U+ P2 _2 K% u$ ~' p
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拉低使能情况下。 : h* x) R! w6 d8 d; a
二.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发送数据与接收数据。 M5 s3 B% |% e/ ]1 o3 z
- /***********************************************************************
3 h, v3 j+ B; l6 {9 r6 y) c - ****************** name:SPI_Slaver_Driver **************
$ e6 o7 {3 o K7 O7 z - ********** author:made by zzuxzt **********
2 r. M8 ?/ n# \3 }5 H+ O0 ^! [6 v - ****************** time:2014.4.29 **********************8 r% e% v- S- w9 y& N8 D$ r3 s+ ^
- ***********************************************************************/
- i4 s1 u6 s1 M0 W - //use SPI 3 mode,CHOL = 1,CHAL = 1
- V; [+ N/ B1 m1 i" o( j k3 q - module spi(input clk,
9 Y3 t0 {# ?2 x" x. u/ i1 e: v" G: N - input rst_n,9 N G! Y( b C) c
- input CS_N,
2 i; n7 G" Z) B3 F8 e - input SCK,
' k1 z* y2 {# ^ - input MOSI,8 i# q6 a% A8 Q* n* p5 m1 J5 L! o3 f1 i. L
- input [7:0] txd_data,/ b- z u& C* u4 J2 x# O
- output reg MISO,
5 Z( A5 U3 n5 _/ [" `; f - output reg [7:0] rxd_data,
8 j3 h" P5 [/ X) L. m' m6 l - output rxd_flag); //recieve done,please transmit data
5 R+ {! w$ d0 a/ b4 t+ u& g# w3 R - 2 F' [" r2 [4 \7 O. f
- //-------------------------capture the sck-----------------------------
) [5 z- c D- ~1 z) { - reg sck_r0,sck_r1;
7 P2 j" O, J" Z6 d+ v3 Y2 t - wire sck_n,sck_p;& ^6 }5 t% a. P& d, C# ^. I* S2 P
- always@(posedge clk or negedge rst_n)
. I/ {: v x2 h/ ? - begin
0 X3 D3 d R( ^8 B2 r' V - if(!rst_n)
: k$ }9 ?0 G. _0 e2 M0 _ - begin
$ ]3 y" G; i- P - sck_r0 <= 1'b1; //sck of the idle state is high3 Q% c$ [/ N g8 W. f9 W$ ]- v) ^
- sck_r1 <= 1'b1;3 R* h. K8 B8 t6 c& w" q+ A) e* \# X
- end
3 f, ?) Z1 U* u% Q - else
/ l' z% a, L4 B4 P9 [2 _# G - begin: _& _, |7 E3 i( ~7 ~
- sck_r0 <= SCK;
" F! F- R# R2 Z. F' a0 y - sck_r1 <= sck_r0;
! y( [' R# ?% [1 Q8 e# b3 @ - end
, i( `6 O7 v" a) m- F - end7 z, k% v) ~2 K/ i/ f% X4 t. R
8 z4 C1 h7 b' Q5 r- assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0; //capture the sck negedge! F8 U. A$ B# \! ^
- assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0; //capture the sck posedge4 J* ^9 e$ [% ^- d% |( [- z
, q. S9 ]/ w1 k w- //-----------------------spi_slaver read data-------------------------------
( b4 A5 |% {% \/ t0 S+ x9 e, Q - reg rxd_flag_r;
; |! l& a; F0 h1 [ - reg [2:0] rxd_state;
2 n; |" _. K5 {. c - always@(posedge clk or negedge rst_n)0 i9 s1 K& ^% f* X# U
- begin j8 P6 B+ Y) k( H; U" k4 B
- if(!rst_n)
6 l, O7 P5 W+ B$ ]1 n/ I. W - begin3 I: f; z, k9 V3 r
- rxd_data <= 1'b0;
6 |4 P/ i* Q- I# }, d - rxd_flag_r <= 1'b0;% _* M% ^5 x6 C! x6 M k x9 r
- rxd_state <= 1'b0;
4 _8 F; d8 l1 p6 O) z# F* X - end
7 Z1 L" B0 b& L+ q/ `6 Z - else if(sck_p && !CS_N)( B" a: e, q( R- ~4 Z! i
- begin J; x) Q2 f( ~
- case(rxd_state)
1 o, J# B) j0 D# h. B* K: ` - 3'd0:begin
8 V9 K* h! i C3 m2 |5 M6 v. m% ` - rxd_data[7] <= MOSI;
' M6 w4 L8 `/ |& O# G- f - rxd_flag_r <= 1'b0; //reset rxd_flag
+ c- \$ q6 Q, _) k - rxd_state <= 3'd1; A% i' |2 E4 Z9 h; ?1 c8 } \
- end
5 C' p# F! \- J" ]( w' P - 3'd1:begin
Q; d W( p1 x) T0 c: r& f0 d - rxd_data[6] <= MOSI;
6 m. h9 y. u0 B, t- R) B - rxd_state <= 3'd2;: C6 C' D! u" J
- end. Y1 u# v+ ] i; ^8 |) I' c
- 3'd2:begin
+ O7 E, r" {) |6 n& Z/ Z( g - rxd_data[5] <= MOSI;
% ~& Y. `8 P7 q- t) `' ? - rxd_state <= 3'd3;% n! [ _. t% P, P
- end7 f+ u {3 |: J
- 3'd3:begin, j) @% y) |# K, c
- rxd_data[4] <= MOSI;, R3 R' k: t0 Y9 O
- rxd_state <= 3'd4;
Z4 F7 ]9 X, a& E# d - end
( u# s( s. j7 `$ J! g. J& | - 3'd4:begin+ c1 L( b* n$ N! F, J5 p0 x
- rxd_data[3] <= MOSI;
2 A/ Q" a4 Q. T$ z% t) Q: n) j! W5 @ - rxd_state <= 3'd5;7 y+ l% C- P$ {/ w& U$ k
- end
3 O8 C! f# d+ Y; ? \ - 3'd5:begin$ @- d- S, t) f# h5 N/ Y
- rxd_data[2] <= MOSI;* ^+ Q5 b2 ]5 @- |
- rxd_state <= 3'd6;
4 B+ v# Q8 O: F. J I7 m' y - end
& E1 w+ ?7 l% ?6 \5 x - 3'd6:begin
# ?) {% [9 M. J) D; g& ? - rxd_data[1] <= MOSI;" G" _9 ~" t! E D- r1 W7 `
- rxd_state <= 3'd7;
. ]" r, z$ d8 t% F( S7 F6 H8 k, h - end
) {. ~8 b. k# ~9 } - 3'd7:begin, ]$ H2 C! ~% D' L6 E' p! b" Y
- rxd_data[0] <= MOSI;- a* P* o& N7 k0 d- F
- rxd_flag_r <= 1'b1; //set rxd_flag3 }3 C3 x2 @. P B
- rxd_state <= 3'd0;
' _6 v8 I2 G6 Y) [) z- |/ [ - end
0 b) y$ A9 d$ \6 g) ^/ ~7 x( l2 n - default: ;+ d6 [! G4 [' k3 F
- endcase
* i% n/ J, M' S& s ?0 l - end6 U4 D3 }" p( D
- end$ j6 y/ Y( `! H) I5 H: F
0 @( Z7 @1 `& O7 E) g- 8 b/ w5 a/ Z& h+ D5 R7 E; r
- //--------------------capture spi_flag posedge-------------------------------- c& ^0 @" L, A- T! N% h
- reg rxd_flag_r0,rxd_flag_r1;' f, H7 w5 b5 C! c6 E+ o
- always@(posedge clk or negedge rst_n)
& a) S/ A& x8 l- Q; D9 E - begin
B8 u, `9 K& s5 t$ h/ ]5 _' s# w - if(!rst_n)
[5 g$ P/ ^* }, K$ m* K( W! P) q - begin
0 W" e* G, _/ N1 `0 X - rxd_flag_r0 <= 1'b0;( X$ H; n9 [/ v* r4 Q
- rxd_flag_r1 <= 1'b0;
# `3 `2 S* A* [5 Z( h - end% {8 B# M2 B% I9 ^) c
- else- _" Q1 Q$ D% M1 I i) d6 `9 B
- begin" p# t# M; r7 m7 a
- rxd_flag_r0 <= rxd_flag_r;
+ u) t! k1 a/ X4 l' U# o) ? - rxd_flag_r1 <= rxd_flag_r0;$ [& }' Y5 @5 ]' w' { W% q
- end/ V, U" h3 W5 B9 R: b* g O/ |
- end& J: h: _7 u7 m) p, X0 s
- 1 ^* r! z5 Y( z# w+ `+ s8 t5 b2 t
- assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;
: Q5 t8 c" E' ?. a7 @5 \& F$ l+ y - * h7 H0 g* w8 T$ x8 I# q h
- //---------------------spi_slaver send data---------------------------7 s8 K5 N1 c4 P* W
- reg [2:0] txd_state;* R/ B# c) |7 X% c! c
- always@(posedge clk or negedge rst_n)& w5 U4 x" X1 a+ j3 i+ k" q" B: A
- begin1 u) P1 i. Y5 f$ o) B6 Q6 K- M3 N
- if(!rst_n)
7 f( \; w* `9 S; x; ~ - begin
- {* D2 m0 u2 |3 Z5 R - txd_state <= 1'b0;
& i, I5 y2 n: _7 J \7 i - end
0 \. h" C7 S$ ` - else if(sck_n && !CS_N)% C( h. B3 X1 b: A# Y
- begin. ^9 [& {5 D8 q' V8 K7 Y
- case(txd_state)' d+ s, _# i: r
- 3'd0:begin- \, Z# r1 W/ G6 g* M2 G
- MISO <= txd_data[7];
) p- U5 D0 _7 K, e9 f/ q0 Z - txd_state <= 3'd1;& T( f1 m- L, s1 V
- end
2 d$ d7 I" Z, m* K - 3'd1:begin R: Y X+ A z9 ^& w
- MISO <= txd_data[6];# F8 M. b0 D& \
- txd_state <= 3'd2;
- o% T. X! s" v( C) a$ [: O - end
! T- n! F$ s5 A0 [/ R2 L/ _2 { - 3'd2:begin8 ^9 t4 `1 _- r8 i) F7 `
- MISO <= txd_data[5];
. F: x$ x) R% F - txd_state <= 3'd3;
' ~1 m. S3 v' S! r& G7 O - end1 T0 h6 ^4 K8 V! R9 B6 {
- 3'd3:begin# i+ V5 I. e. ^4 n5 V" |/ q; b$ \5 g
- MISO <= txd_data[4];% j0 Q/ a/ v9 L3 {1 e
- txd_state <= 3'd4;
5 ]0 ~7 W0 P. }7 f1 R - end8 Q9 I5 b( P* T( R1 R
- 3'd4:begin
0 Z& w l/ f8 J. M - MISO <= txd_data[3];
9 \" g1 Q9 z4 v8 f1 S- z - txd_state <= 3'd5;" Q0 ^/ a! {3 c; `1 o( V! M7 ], n
- end
. c& f! i- f5 f' S7 A6 r - 3'd5:begin
+ i/ b1 S9 k# k/ a: ~ - MISO <= txd_data[2];4 ]" `, I) A; h- m9 ~
- txd_state <= 3'd6;
& T$ s: ~+ W. D, p& z6 C - end
3 F+ Y3 l! K: g( ? - 3'd6:begin T$ B- ?+ ~0 R
- MISO <= txd_data[1];
- x; j7 I6 O% X0 e0 N, } - txd_state <= 3'd7;" B6 s" ?$ W2 V& a( Q
- end. @" ^5 G' ?7 ~! Q0 V7 |
- 3'd7:begin, \# d6 k: u7 N$ L) ?6 q
- MISO <= txd_data[0];' N& \$ n/ V; Z6 G
- txd_state <= 3'd0;
% k& j+ D1 ^2 e9 g( [4 R; F - end
' X! x+ m+ u: i+ t - default: ;
3 e; h' T, T* C - endcase" F: j# v( r" @
- end' k$ x- Y. Y+ a( t9 E2 j; e, z$ v
- end/ g/ h6 O5 \4 I, d. K) ]
/ e& R7 E* N. G1 @ b+ X1 l- endmodule
复制代码 7 f8 d) r5 h% V3 p; z) Z
6 t @# y! T/ D( f0 s% p( C
) C! f' l. ]& L9 u* i, n
9 j; x( ^) Y) h. w" s8 F( s, y |