一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。3 f) A4 D" I8 C- C- j* O" O( j
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拉低使能情况下。
5 P* w2 `0 ?& J4 j二.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发送数据与接收数据。 & e, O/ |1 D' _0 [, C& K, i+ S
- /***********************************************************************6 N2 A8 E+ ^7 h ~) b' w1 D
- ****************** name:SPI_Slaver_Driver **************
& w& K3 @6 q% g1 q7 R - ********** author:made by zzuxzt **********
2 ~ s+ {4 P) x$ t @ - ****************** time:2014.4.29 **********************
2 p( C/ z! C) Y; Y! s: J3 h2 o - ***********************************************************************/' X/ W5 K! d5 p
- //use SPI 3 mode,CHOL = 1,CHAL = 1
' n2 H$ Z% P( v5 Y1 l - module spi(input clk,
5 i3 t r) N. h) Y; \ - input rst_n,. v4 R5 \+ V/ m) G. h( ]/ X
- input CS_N,
) j6 q& V+ o) J) ^/ z0 M6 D' Q: n5 H - input SCK,! k4 i- H, g2 z5 l. a6 O" H
- input MOSI,: r' f3 G' ^: {- v* R6 D
- input [7:0] txd_data,# H8 y! q8 D2 p- H
- output reg MISO,
# A/ U1 z' L3 T1 b6 q - output reg [7:0] rxd_data,8 C+ I. \/ e* k! \% }( L" B* X% ~
- output rxd_flag); //recieve done,please transmit data
2 y5 \) G" M9 \8 {' l - & G: u4 H" r& j, o# x6 t
- //-------------------------capture the sck------------------------------ `' h0 ?9 _# e8 P+ @( Y
- reg sck_r0,sck_r1;
: {7 w; B' ]- h, L) B9 V& B - wire sck_n,sck_p;
8 \2 M) _, l' J% j, \, }2 q - always@(posedge clk or negedge rst_n); H( I1 y5 o" ?1 @- E8 V
- begin
, _: e1 C5 `+ u/ f, t0 h" \" f - if(!rst_n)5 ]; u4 g2 f( h0 m
- begin
; N- E( H0 ] ^, i- u - sck_r0 <= 1'b1; //sck of the idle state is high
% ~' b2 K5 j/ x6 V" w - sck_r1 <= 1'b1;, x$ R9 _* x/ H! p' ~! `
- end3 K4 R* Q' G( @9 K9 j s, f% s
- else, Z6 |$ K0 V* F) ?9 j
- begin
/ ~5 D2 I( H% [ - sck_r0 <= SCK;! ?6 u" P$ ^* q3 T2 Z% N, B
- sck_r1 <= sck_r0;
% U1 E* r4 o- b/ ~ - end6 Z' T; R/ d, D+ m3 v! a
- end
, w' y! k" _; Q5 j - / V/ d2 a! N. p6 W6 U
- assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0; //capture the sck negedge8 S0 }% G% ], `# v2 S- R2 I- F
- assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0; //capture the sck posedge9 C# y1 |4 P1 }
- # q6 e( j5 l5 A+ n; z
- //-----------------------spi_slaver read data-------------------------------
! b% U" F* c3 N# F: ~' w5 \ i - reg rxd_flag_r;
1 J3 `1 P' \2 ?# G4 G0 ?, G7 X - reg [2:0] rxd_state;
; t7 m7 W% w) [) J8 P4 D- ~% w - always@(posedge clk or negedge rst_n)5 ~* a, X1 f/ {- I, l# ~% P
- begin
) o B& G/ I& M$ f% a, }' r6 S - if(!rst_n): D* Z3 d0 Q* _1 s
- begin
) c: J0 _2 J% T" F( ] - rxd_data <= 1'b0;2 U8 i v1 t6 \7 W2 R
- rxd_flag_r <= 1'b0;: T( ~' l$ \0 @4 W1 T V/ b
- rxd_state <= 1'b0;
: S# F) \. j( J - end
. `+ ~0 M0 @$ G4 r! W2 _ - else if(sck_p && !CS_N)! t) y# Z: N; U3 Y. A
- begin
0 Q2 j- z/ U6 ^% S% S/ F* k4 F4 Y - case(rxd_state)- y( n! J! s" H: C+ u4 t# R
- 3'd0:begin9 a) C9 c) Q5 f, x& A
- rxd_data[7] <= MOSI;5 B3 T" t3 M( \5 ~
- rxd_flag_r <= 1'b0; //reset rxd_flag. a; a' f; x7 R) L5 S
- rxd_state <= 3'd1;
* Z; `- L3 J$ J, P - end
3 W) D( p! v# Y - 3'd1:begin% n: u# T( ^3 `
- rxd_data[6] <= MOSI;1 B- O" R _+ t. M: q8 \. `# Q
- rxd_state <= 3'd2;
, A) C1 q5 C4 }7 z n/ y - end, a; `! x* X2 Q2 I& j
- 3'd2:begin
L; S6 `* {' J2 T - rxd_data[5] <= MOSI;
4 H0 g" Y' _ h8 v* P( {3 A - rxd_state <= 3'd3;% p* s, i# Z' j2 K4 g
- end. b: }) b- }$ ^1 D
- 3'd3:begin9 @. b5 ~0 ]9 M5 T
- rxd_data[4] <= MOSI;9 V, r" I8 F* L, H8 U
- rxd_state <= 3'd4;
. v( S7 z2 L9 Q9 @! h% |$ f - end3 c3 L$ D9 r. A& J) S5 i8 ~
- 3'd4:begin: L7 Y- W) S0 l6 o9 e4 @$ x
- rxd_data[3] <= MOSI;* H1 w4 r! O$ o, F
- rxd_state <= 3'd5;& ?# S" J( X' Q! h0 l4 ]% D5 v
- end8 a7 v7 B3 ~+ Q# } }" U
- 3'd5:begin
+ D0 N8 y/ y5 E) p% b - rxd_data[2] <= MOSI;
1 \8 m6 ]( U3 t z- a - rxd_state <= 3'd6;6 O! e: |! v, ]( M3 a4 M0 v4 p0 g: T
- end
' j0 w- N) F. Q1 o% r' g/ i( J - 3'd6:begin) v( _2 t: B% Y
- rxd_data[1] <= MOSI;
( j, o0 _. e9 u6 W7 G8 I0 Q - rxd_state <= 3'd7;
% g- o# a: t9 z; \5 y% v - end
9 g- i3 C S, O! Z9 Y - 3'd7:begin
' A5 F8 y% A, h, F# `- B O - rxd_data[0] <= MOSI;
5 g; T- ~7 \ E. r- @ - rxd_flag_r <= 1'b1; //set rxd_flag {, }5 U, V2 [" `% h
- rxd_state <= 3'd0;+ q" {- X# }: m! C3 ]
- end2 D& }: h5 R0 u- c1 J
- default: ;
5 b! l' o: U- ] - endcase) U: x e/ f& }1 _+ N
- end ^. D( r* H1 Q- w; x& K2 i' z
- end, E* g: ]' `# A' `2 W, F7 f ]3 r
( {0 p+ o: T+ f* M- % a* A1 q" h& h! b, `; i& k
- //--------------------capture spi_flag posedge--------------------------------+ G& U) ^8 h; g* O& m; D) L d. I
- reg rxd_flag_r0,rxd_flag_r1;; I+ Q6 [7 Z; b: g
- always@(posedge clk or negedge rst_n)
5 Z3 E5 D, m9 r1 W4 K" d$ ~. ] - begin d" R' s& K& R7 b( Z
- if(!rst_n)
# `2 \; h/ C0 X, F5 C% k - begin
3 p# h, O W u5 l* I8 n& X$ _( F, B- Z - rxd_flag_r0 <= 1'b0;
/ T+ g- A! j) K. s* D: U - rxd_flag_r1 <= 1'b0;
% L5 q) X1 M3 |1 @) ?# H6 Z - end
o1 ?- T- q' b Q+ T - else
/ e) V' H; s* g' u# i( M - begin
; J. Q. G) k1 D/ b* P: d - rxd_flag_r0 <= rxd_flag_r;4 x+ E# ^3 B/ q5 y
- rxd_flag_r1 <= rxd_flag_r0;
2 D; N/ Q8 ?8 P+ W - end) d# O5 g( R) |( i B2 b- J% u
- end
# F0 ]# x8 I' p
1 J/ T8 w0 M$ ^# g1 W' J( Z- assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;
1 I7 k8 n! z" g - ! ~( S+ i! x2 g ?, N0 A+ `
- //---------------------spi_slaver send data---------------------------' Q8 V; P6 s8 S9 A$ n
- reg [2:0] txd_state;
. N1 {" }7 R a - always@(posedge clk or negedge rst_n)% n- W! b' J) j$ c
- begin
6 `. r% |6 D) C. P' P - if(!rst_n)" \- M* r3 h6 M* B; X7 D6 Q
- begin
0 K9 @% h! B6 G J- V; Q( d; O - txd_state <= 1'b0;
! w/ A& w/ g/ { m W1 @ - end3 e0 r$ |8 e1 z% L/ g: e
- else if(sck_n && !CS_N)
5 w- D. V- v3 M) D& l5 x8 P - begin* Q& m& i8 ?. j3 B+ ^
- case(txd_state)* v& l' J; v6 i9 \# D* ?/ g
- 3'd0:begin3 p9 }# }% |& P8 Z1 Y
- MISO <= txd_data[7];
7 ~: P2 q1 Z) N$ f - txd_state <= 3'd1;, m+ B& y, v3 P. ?% k; b0 U$ L
- end- I. ?. f: o/ F8 `0 U- p( {4 t
- 3'd1:begin9 u+ U. z( L, ?7 Q/ _
- MISO <= txd_data[6];
' M: B. d8 }6 x - txd_state <= 3'd2;
! x1 A. K4 u3 R( c3 j - end ]5 m: J7 U! B0 K1 t! W6 Q
- 3'd2:begin: S3 O/ F' v" U% O0 c' s- j2 E
- MISO <= txd_data[5];
) T) Z& B/ b7 K9 C9 { - txd_state <= 3'd3;
' U1 C& c, w' [$ p5 v2 q+ s0 r9 @4 q( T - end+ f5 X; K' s' }% Z5 Q1 e1 d. [* j" l
- 3'd3:begin: g/ y) m! O6 i1 U
- MISO <= txd_data[4];! h9 ~8 p% U8 c7 Z* D5 W& r
- txd_state <= 3'd4;
! }, r% O/ ~7 C; ^6 t/ w- W1 e$ y - end7 R1 p, K9 B. j2 \" ^- C+ q5 p
- 3'd4:begin
# g s0 `; A+ P& I: z" ^; ~2 P - MISO <= txd_data[3];
5 {. e& H1 z. m! L+ P; c2 d2 @& } - txd_state <= 3'd5;2 y% u0 J- V9 q
- end) k5 _: e5 O1 G0 k
- 3'd5:begin
; ^1 f2 x7 u/ b G) a - MISO <= txd_data[2];
, F; O0 ^; [( z - txd_state <= 3'd6;
! Z! h! p) z5 s: r3 _ - end/ k2 b x: U. B' s! n$ s- o6 T
- 3'd6:begin
8 r5 Q. N( K2 @3 C+ s% `8 H$ O0 P - MISO <= txd_data[1];
7 W$ U! C; t4 ~1 K0 {: x- ~( z - txd_state <= 3'd7;# O6 u1 g" C& @" s
- end, I+ S" M9 W8 ^: ~$ b
- 3'd7:begin/ m5 _( q: v/ z3 ?, P# t
- MISO <= txd_data[0];
4 t" P# {2 S5 e' H& I/ @; q - txd_state <= 3'd0;
: V1 R2 V) i( i4 I4 M - end
0 k8 m( U7 p+ i4 d: f: y) n# P - default: ;
4 C$ P$ l5 Y' m3 Q6 U' w - endcase
9 F' ?; E9 X6 S, H7 \- ]7 [9 T, Z - end. Q( C1 V& {4 r M* a
- end9 o7 G8 v7 }) e( K5 l- U# q
: Z0 h/ X8 _2 s- M1 E e- endmodule
复制代码 3 V8 Z+ Q8 B4 E% l
7 u2 h3 x3 \* B" B# k! X7 w0 w/ I& k' N1 z1 D
! ~9 w a* c, J! k: C |