一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。- ~/ j$ C6 b- |5 N Z
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拉低使能情况下。 & z$ W4 }/ h& f
二.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发送数据与接收数据。
% R/ `+ A# r% X% f' x% L- /***********************************************************************0 ]7 r2 r% E1 z4 w1 s9 B& r
- ****************** name:SPI_Slaver_Driver **************. p4 `# P+ C$ j# o) d. ^) h% T
- ********** author:made by zzuxzt **********
8 E4 _2 L. e8 H9 D/ P - ****************** time:2014.4.29 **********************3 n0 W- a: f: H3 m! ~
- ***********************************************************************/( Y6 }/ b9 g, q7 Y l% z* r$ w/ _
- //use SPI 3 mode,CHOL = 1,CHAL = 10 b$ K0 o, c5 M. K
- module spi(input clk, o: V, T9 @& w3 @5 [% m) e
- input rst_n,
" h% [/ C* S6 a( g6 |' q) t5 k2 z - input CS_N,
# j) ?! c, e8 J. r9 Y' ] - input SCK,2 H0 o5 q& v' U# b7 u4 H# z
- input MOSI,0 w3 r5 D) [% a% L. N( V
- input [7:0] txd_data,
V- _4 F. l- L' W9 @1 {3 X - output reg MISO,4 i; B1 i3 S4 @ i- U+ U
- output reg [7:0] rxd_data,
/ E' n# i6 s# E$ b+ N. c/ s9 T - output rxd_flag); //recieve done,please transmit data
+ U3 F7 j5 t w+ I9 R
* v8 Z) d; ` H0 x- //-------------------------capture the sck-----------------------------
$ `# ^) d+ r4 Y2 h: O* n2 L - reg sck_r0,sck_r1;
: \4 i+ k- E- o$ e - wire sck_n,sck_p;
( n0 S2 r' u+ }9 p - always@(posedge clk or negedge rst_n)) }) x+ U q: T8 F5 ~- T
- begin
5 m! O6 l q& a5 z; e4 Q. k - if(!rst_n)
1 E3 G) f g) e" t - begin
$ s- K+ c/ U b" \) @ - sck_r0 <= 1'b1; //sck of the idle state is high' ]) y! A- u; ]; K9 V
- sck_r1 <= 1'b1;/ g" v0 o/ P9 n" d
- end
9 a8 ?. m. O( w& s" s6 W* w - else
$ k- ^" B5 Z3 E5 ~4 `1 w - begin: j/ C2 l( x7 E$ K$ T3 P
- sck_r0 <= SCK;
7 g. e& @# P* q1 n - sck_r1 <= sck_r0;3 c, ? Q ~: c
- end
) P+ l3 F, J4 V6 w4 z3 j3 U" o8 E - end9 {1 [. y: J/ B( G* h& F/ P# J
- ; Y$ h. E- c/ D) s5 H
- assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0; //capture the sck negedge
) o, Y W5 P* X6 D _: g- K - assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0; //capture the sck posedge, a" Y G8 X; Z! \5 m
/ K* w! x4 G; w$ N, j# d- //-----------------------spi_slaver read data-------------------------------
; }% y$ i+ e# Z* r; m2 X - reg rxd_flag_r;! r* K! M8 O- `2 r. U* z8 H8 q
- reg [2:0] rxd_state;+ O3 m2 ~; T3 b* J. M
- always@(posedge clk or negedge rst_n)7 O6 F8 \ i- d6 ^" I; `
- begin m. b; a( I/ g
- if(!rst_n)0 u+ E4 Q# \/ A8 i& |# A
- begin; |% v, f' m4 W: z. v
- rxd_data <= 1'b0;
! b& c- _5 u; Z2 `' x1 P. ` - rxd_flag_r <= 1'b0;" J. O5 g) R0 O5 X8 t' S
- rxd_state <= 1'b0;
" q3 r, I( [2 ?2 N* j$ h6 D/ {& _ - end
" d0 _6 L, ~$ v) Y - else if(sck_p && !CS_N)! D5 {6 ?9 [) ?& J0 a: n
- begin
3 H! v! L- j o7 [: Q1 [# G9 G - case(rxd_state)
6 w! h* ~# S4 F) Y - 3'd0:begin9 I5 D4 e! d) T6 f' o
- rxd_data[7] <= MOSI;
, b1 x9 T3 Q4 N - rxd_flag_r <= 1'b0; //reset rxd_flag
# x1 k1 F" H* _! E - rxd_state <= 3'd1;) W2 h: T" Y/ x
- end
! [3 i6 ^: _" P/ D' J H$ ? - 3'd1:begin
# E5 o4 f, e9 a, i9 c) |$ ~ - rxd_data[6] <= MOSI;, p k. h# {/ D( I3 a
- rxd_state <= 3'd2;
; m( D; Z4 X7 J1 u' N3 o - end
% Q e$ R, I0 @; K3 s* d- p - 3'd2:begin
' {9 b8 F: L# Q - rxd_data[5] <= MOSI;
% C+ }6 u0 L; W3 `3 c* ] - rxd_state <= 3'd3;. B0 [3 j; H9 m* Y9 E) T- g7 j
- end
' |! s/ ^: R, |; B5 F+ s1 l - 3'd3:begin
8 n7 H5 m* @0 J3 ^5 T/ N% h# l2 I' l - rxd_data[4] <= MOSI;
" i. k7 S K: _ - rxd_state <= 3'd4;
! B) O" z5 \, p1 x8 h8 K e' _ - end" v# i2 n7 z& b% Q" {
- 3'd4:begin0 N/ a9 `+ u9 G, r3 i: V5 j; X! ~
- rxd_data[3] <= MOSI;$ ^3 @2 y, f# P/ N% }% r) f
- rxd_state <= 3'd5; J9 ~# t9 E9 |$ l, A$ B' Y
- end; w8 O7 V" A8 \0 a3 c3 o
- 3'd5:begin
, _2 }2 f* u5 o8 z& h: { - rxd_data[2] <= MOSI;2 _" ]9 x1 e6 c$ l# n+ H- ?; b
- rxd_state <= 3'd6;: ^& `; E! d: s4 |0 C* i# y
- end
( g% ]. i; M7 j& A - 3'd6:begin2 u- p$ J( P; g; `
- rxd_data[1] <= MOSI;( `8 R7 o0 Y; C5 J. t) q% p" b0 H
- rxd_state <= 3'd7;4 e) M; s9 ]* p, e
- end' A4 l9 G8 I+ s# ~+ `& W/ n
- 3'd7:begin/ \. Z) l2 B* U" b0 I
- rxd_data[0] <= MOSI;
+ l8 G* S4 X, Z" k - rxd_flag_r <= 1'b1; //set rxd_flag; B1 a9 M3 y, P7 d8 g( q4 B7 _
- rxd_state <= 3'd0;, m' S8 f( @) @) z" X
- end* I. e+ \' @) F& }5 I! o
- default: ;
" ]! b& h, Y# |$ h - endcase3 i* P: j3 I8 z% Z
- end! y" B# M! C4 m5 W
- end/ M; y8 x: x# }/ Y
- , x) l$ o9 s6 ]
- , S+ n- r' O6 X% B5 Z( y* q
- //--------------------capture spi_flag posedge--------------------------------
5 `* e' [. d1 _" Q( A- h - reg rxd_flag_r0,rxd_flag_r1;% Z6 U- M ~5 L# m- y3 i7 ~
- always@(posedge clk or negedge rst_n)4 W9 [" r" J1 `2 p) o
- begin
9 `1 s' j) ^* p& r& _ l - if(!rst_n)
' {. X+ N5 m& Y) ? - begin) W: o k* C- ~% n8 {6 }
- rxd_flag_r0 <= 1'b0;+ j- p1 v0 K1 |% a5 i7 W
- rxd_flag_r1 <= 1'b0;
7 f% h) Z$ H! ^5 Q1 X+ d' j( w: ^ - end$ I+ ]$ e" h) ]: O: M( X! k
- else) _5 A$ W$ G5 |5 N5 `! @' n1 ?
- begin4 j. c7 G: {+ G
- rxd_flag_r0 <= rxd_flag_r;
$ Y* }- ?4 z- y$ P6 b0 B - rxd_flag_r1 <= rxd_flag_r0;& _, s" c+ b# @# W8 i' v+ j* D
- end' N& F* q( x- Z" k* j- @
- end4 l2 I# k6 U& o } ^
0 ]5 y( v' \, Y8 q! m% s5 I8 w% _- assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;& d$ n- ^9 |$ S$ H2 R4 L$ D3 d& Z- a
- % w1 N k+ x1 l. R2 i* q: t& `
- //---------------------spi_slaver send data---------------------------
2 r% d9 I r4 g; U4 Q - reg [2:0] txd_state;! e6 D& M' v6 y2 X3 A3 _- M5 [
- always@(posedge clk or negedge rst_n)
4 t. ~/ J6 }; w7 b - begin( h4 A, R* H6 p; |6 V
- if(!rst_n)% F1 p! [) ~5 V0 |
- begin* `8 d* L* t1 T/ o& z
- txd_state <= 1'b0;0 r2 j5 e# ~9 k- e
- end
4 o0 D/ v! ^2 g0 y y! q4 A - else if(sck_n && !CS_N)' l* v. O& Q1 E% V! `& l, K; r
- begin& |4 y8 I1 u& |0 E
- case(txd_state)
( n Q: Z4 @! v - 3'd0:begin
* |& E* D# I; H5 _( d3 P# ~ l) G - MISO <= txd_data[7];4 y6 Y( m" Q: N. l( Z: C9 \
- txd_state <= 3'd1;; r# ?9 d8 Z! Y. ~. x- A0 i
- end+ Q+ O6 S, H8 y d; |7 j- R
- 3'd1:begin$ K8 y5 M7 z- E% ~
- MISO <= txd_data[6];
8 Z. }# |9 I9 k* Z/ m4 b - txd_state <= 3'd2;2 J* _. {# E0 H* O4 b
- end
6 o# n9 v7 l6 J - 3'd2:begin% ~& T/ X! K) k! W
- MISO <= txd_data[5];
6 W4 f" q" R) r2 J - txd_state <= 3'd3;
. t! U2 x) M1 Q6 R; F6 [0 | - end
- R* ]$ `- ~, G4 A i - 3'd3:begin
8 Q. {) J. o9 {9 o# q q# G - MISO <= txd_data[4];
5 Q4 ~5 g1 V3 F) } - txd_state <= 3'd4;1 B4 O- \* ?2 K3 \
- end5 }: `' f W5 R6 m9 p3 z
- 3'd4:begin* t' \' |0 q g0 _3 ` [
- MISO <= txd_data[3];7 n% C$ `+ d$ R: }9 }! T; `
- txd_state <= 3'd5;& c9 E& X. P/ o) m
- end
. g2 g( K6 u! ?1 {1 ~# @1 g - 3'd5:begin
9 J0 r/ |, T; k0 Q7 s - MISO <= txd_data[2];$ b V! K$ ~6 J8 @7 _2 J! F
- txd_state <= 3'd6;
7 I2 G) N6 Y7 |* C6 Z - end+ I8 f Y' Q @* C8 P0 d
- 3'd6:begin
' [( G# u8 |1 i6 s( n: U - MISO <= txd_data[1];) `' O5 P( r1 V+ L2 \) e' u
- txd_state <= 3'd7;: |& o N% f8 ]% d+ z
- end
: Y5 A8 J) B; H, e6 x& c - 3'd7:begin
! K1 p/ w: n! u/ o( O$ E9 t - MISO <= txd_data[0];9 a% S u2 F( R# j Q7 ^1 I
- txd_state <= 3'd0;
4 g2 f" T- e l! B/ Z - end
1 O" @, G* ]. l - default: ;
1 V1 ]: ~0 L, l' r/ o8 c+ N - endcase6 W5 @ j8 |4 M9 V: K
- end
0 A" Y) {" q& b2 k; s - end
* W/ N8 p% a+ v( [5 N
* N0 M) H# ~( X7 R- endmodule
复制代码 W# d5 ]5 q: t" k& f/ Q) m
! ?) [6 ~$ f( D+ }$ h
5 e* T- Q2 a# s
, W! x+ y i: X1 m) p
|