|
一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
" ~/ F9 L+ G7 A' L 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拉低使能情况下。 & @, F( Y/ E6 I: f9 J" 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发送数据与接收数据。 ' Y8 b6 `$ j2 u" g/ T- a, T
- /*********************************************************************** a; V# g% c* |' F
- ****************** name:SPI_Slaver_Driver **************1 l3 I8 g* }! S% V
- ********** author:made by zzuxzt **********8 V- L0 A/ ~) t- h
- ****************** time:2014.4.29 **********************
7 v. l. A0 O. N9 D- `3 V @ - ***********************************************************************/' U( m4 I6 ^0 s8 @; L$ @0 `
- //use SPI 3 mode,CHOL = 1,CHAL = 1
3 T6 z* S' W; e+ a0 a( u; k& T7 Q' I - module spi(input clk,
/ J5 `* y4 w; T8 x - input rst_n,
; l6 ^0 ]2 z1 E6 w5 ~( P! H - input CS_N,
6 C3 {1 V$ `7 E8 ]( n, H - input SCK,
" i* H+ F: f1 z& t% V8 P; x* H( B x - input MOSI,' E( D2 g. @0 G5 m
- input [7:0] txd_data,
0 O4 x; q' {3 k$ m - output reg MISO,
7 o- P# w( b' X- n+ g2 ~6 ~$ Z - output reg [7:0] rxd_data,0 c$ z& g7 P& A/ t. B
- output rxd_flag); //recieve done,please transmit data6 q4 ~* w. I$ l, W. @
- 9 x2 X0 i1 z' E# p" ]8 s/ x: `
- //-------------------------capture the sck-----------------------------
6 \8 x# d% o+ F/ ^ - reg sck_r0,sck_r1;& z( u2 l" Z, @; k$ k
- wire sck_n,sck_p;
6 z- V* M" ]- m6 q0 ?$ e) k - always@(posedge clk or negedge rst_n)5 w. B( J8 \/ S9 E; I% x# g, C
- begin
C u1 ?8 k: X1 C% S% Z5 E. C% ^ - if(!rst_n)8 I2 A5 t" R/ `+ v: A
- begin
3 T5 F* U3 c4 w H- z' ~. g - sck_r0 <= 1'b1; //sck of the idle state is high
4 A" f' S3 p/ c$ P - sck_r1 <= 1'b1;
4 H f+ }5 M* v% r+ b - end! v6 A% r( d, @
- else& D$ |. J6 [ `/ ^5 j2 U1 Y
- begin
: \5 V9 L7 m# q8 p1 V/ ~( g - sck_r0 <= SCK;
|3 f* O* L! ?, V1 j - sck_r1 <= sck_r0;
( ?8 g7 W! U. y& x - end
+ u9 w& z/ H# c' Q" V - end
) \, u! D' V" N$ e- M+ \" u
% n5 _0 S- N7 y% o1 t6 U- assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0; //capture the sck negedge
/ _/ A6 |+ |2 d9 b# G3 O - assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0; //capture the sck posedge
/ C1 j0 ~+ r2 C: ?" d& [* P6 l( C
3 w4 p% ]- a8 L! e: a$ Y- //-----------------------spi_slaver read data-------------------------------
( z) f2 A0 y5 H% \* H - reg rxd_flag_r; Q8 Q; Z. H0 j \$ H. C* k2 C5 @
- reg [2:0] rxd_state;; H# G5 R8 g# S& d
- always@(posedge clk or negedge rst_n)
0 N: ?0 r; R9 T0 C - begin0 A# [2 ^( t/ B' Y; X% b
- if(!rst_n)7 Q' r, B! V! L+ \, ]; ]
- begin* b) }1 n/ ?& n' |* W+ \
- rxd_data <= 1'b0;
8 v$ V- \' A5 n; `: b - rxd_flag_r <= 1'b0;. Y) S& ^8 t0 L1 K2 F' ]! y& T5 G
- rxd_state <= 1'b0;
1 A% r$ y U2 \; V% t - end
8 r5 ]8 a W# L' B/ Z( K1 f - else if(sck_p && !CS_N). s8 m/ J2 [5 g) \0 F, \% l
- begin! y- w' Y3 x/ e7 w9 V
- case(rxd_state)
1 g1 B1 n5 M1 l) }7 b3 E - 3'd0:begin$ |8 s1 t @7 q1 r* k5 f/ U
- rxd_data[7] <= MOSI;
7 u1 |) c, q( Y - rxd_flag_r <= 1'b0; //reset rxd_flag/ t1 }$ \ w1 `4 a8 D
- rxd_state <= 3'd1;4 I T7 J# b; ^( F3 H7 s0 q1 G
- end
3 g* m9 `$ s# F3 f& ~$ @$ o - 3'd1:begin" _0 q5 j( r0 D0 e. ~9 J' e
- rxd_data[6] <= MOSI;# B, t! M, m6 M+ ~+ J) @. B
- rxd_state <= 3'd2;# s' g" y& @8 z8 ^- J3 Z
- end
; M9 P8 P0 v) |# f2 o* S) d - 3'd2:begin
) A v& O& {. R# a/ T( d+ ~ - rxd_data[5] <= MOSI;
+ Q, v. x8 g) n6 s* Q( v1 Z - rxd_state <= 3'd3;
# t4 u1 t% H5 h5 }. i - end
+ j4 Q( l9 e% a5 u8 D - 3'd3:begin
7 A: P& I6 a! i/ d( G+ v. a - rxd_data[4] <= MOSI;0 Z; x2 L# D |. b9 e
- rxd_state <= 3'd4;
2 p& D! s# D6 {$ w: h! x - end
+ d& X- J/ U$ Z( ^ - 3'd4:begin; j6 k& H4 L: G
- rxd_data[3] <= MOSI;
) D2 s- _+ A" j, ] - rxd_state <= 3'd5;
7 {# @5 F$ ?. w" [2 L - end
/ o/ B) X5 P/ }; X - 3'd5:begin
9 c; i: W: K3 a% U3 ~$ [ - rxd_data[2] <= MOSI;* h. {7 v1 ]& v& X8 J$ A" G
- rxd_state <= 3'd6;
; u. p5 ^$ Q+ _- \, ^% Z6 C7 m - end
( S4 u k" } h: B: E" W+ E - 3'd6:begin7 i& X' k/ D e& J1 T
- rxd_data[1] <= MOSI; y$ q* w4 S4 q% l0 N# n: m+ G% s$ W
- rxd_state <= 3'd7;
1 d# o1 v! L, C$ h# m - end7 `4 ?8 { o& p: [
- 3'd7:begin5 J2 A; \3 b6 l5 E% p
- rxd_data[0] <= MOSI;
3 L9 N7 J0 |. v8 @ - rxd_flag_r <= 1'b1; //set rxd_flag
0 G8 Z, K4 F2 A. n# I q - rxd_state <= 3'd0;! V5 k& A+ W! p% A# G) [) ^
- end$ z. \: U Y* v# h1 ?" X. o
- default: ;# _. k& W% g( I7 Z Y" e
- endcase, _( j* t9 P, g0 J, I9 d$ y% {
- end/ J) _; X" z u. L4 T
- end; y' s0 X6 Q. \% U3 V& T0 r3 b8 y
- \, z4 o7 Q$ w- - G+ S S/ U V6 p
- //--------------------capture spi_flag posedge--------------------------------
- K3 G3 B- R( Q9 k8 F - reg rxd_flag_r0,rxd_flag_r1;
: y5 c/ |& o9 ?9 F, l% s7 R" r - always@(posedge clk or negedge rst_n)
0 P0 H) e& h) h; } - begin. a. R. N) ?. z$ B6 E' }
- if(!rst_n)) F/ h. A; g; G& m! w0 D- q [
- begin# s$ K* m+ i/ G& ?( P5 \
- rxd_flag_r0 <= 1'b0;" |* b5 D) Z2 x6 ~" ~1 c+ B5 b3 u6 A
- rxd_flag_r1 <= 1'b0;7 i% \. h% ~2 U2 ^7 G4 x) G8 H( {
- end9 `* V$ X* p& ?$ w
- else1 y5 ^: [# }6 c& e4 N
- begin: S3 _+ R1 p) q# s5 G$ k
- rxd_flag_r0 <= rxd_flag_r;, L4 g& d$ g9 s5 N' U6 O/ y7 F0 f
- rxd_flag_r1 <= rxd_flag_r0;
9 D% V' Q* m! q3 D: D, \ - end
& R& _# n6 |3 P - end
2 t. |2 k/ G) {2 _) K8 w
& s% h! K( c, W/ i( I% L, ~- assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;% o3 r% ?; O. d0 r
- - n9 [6 c$ E+ K8 y* |8 @
- //---------------------spi_slaver send data---------------------------
3 l0 h- ?9 L) y" c$ N- r - reg [2:0] txd_state;
0 Q1 f, ]" Y( m' j, U. O - always@(posedge clk or negedge rst_n)+ a) c% X2 C" U! O& s0 G
- begin
4 g- H5 |4 X/ F* o - if(!rst_n)/ N5 D# x$ d6 r* c$ t& G0 n
- begin
: W, L* `$ [2 R+ D1 r - txd_state <= 1'b0;# c6 g0 f6 i T% q/ d4 T* v: B9 n
- end
E* q4 Q* ^$ C% Y8 G - else if(sck_n && !CS_N)) L" ` T9 \6 w) M; G# j; H
- begin/ g+ P( G( C; r7 Q/ q' P% a9 `
- case(txd_state)
1 }* S b3 ^5 W% P& k( o: ] - 3'd0:begin
: ?, ~% L; [1 m* K* m; n - MISO <= txd_data[7];
- w+ ^/ E% [- d! {% i6 i - txd_state <= 3'd1;& r2 {. D' |$ U4 p( S g) R8 r2 M
- end
% {4 I8 \" W H$ v- }/ }) F - 3'd1:begin' _9 P* ]6 V% F7 @, L: d+ x8 w8 ?* i
- MISO <= txd_data[6];: u4 A) f: Z) P5 V* j9 o: V
- txd_state <= 3'd2;7 b9 o! l' U( J& _
- end
4 ]% O, k3 H6 f; t% I; A* e - 3'd2:begin6 Q3 x/ X" Q$ y) D! {& K; X
- MISO <= txd_data[5];* R- \) P8 }: J
- txd_state <= 3'd3;
2 O) g0 H5 X5 |' D" E - end
# ^9 o6 I* C0 H2 O# o* K: Z - 3'd3:begin, M* z* @* t& \ v/ N0 S5 A! N* {( I
- MISO <= txd_data[4];! U; d1 \: D) P# s9 v
- txd_state <= 3'd4;
7 r! v6 s R9 p3 C5 Y - end$ S4 E% u/ A; r) v: p! j
- 3'd4:begin8 p% u* e+ E1 i6 I
- MISO <= txd_data[3];0 q. }/ b* H/ k2 y; U9 @; y
- txd_state <= 3'd5;* @; g6 ]9 c& q, n2 H
- end
- \8 }( W( \ T" f* b: g- _( _ - 3'd5:begin
% p$ S$ S6 a" d* J/ ^' b+ U" @ - MISO <= txd_data[2];+ S! N* B$ ?- n. z; o8 W% F
- txd_state <= 3'd6;
3 M) s5 H' `. L0 b/ X/ v - end9 V$ u& m$ r4 t3 b+ p$ p
- 3'd6:begin1 m8 W; K# t9 c
- MISO <= txd_data[1];
9 w c" `2 T) {, _2 t - txd_state <= 3'd7;
1 g# O/ y3 Q# ?/ N - end6 ~" X) o/ A, w; E4 U! J
- 3'd7:begin- j" i: o- A8 `. a4 i. P/ s
- MISO <= txd_data[0];
# u5 `( ?2 O" ?! _9 O! v - txd_state <= 3'd0;6 U+ h! h% R G; {0 K& K
- end
0 R# Y, }. c$ d - default: ;
6 j1 t: T; y! h3 |1 U% K - endcase- D4 `, I% e5 N8 {3 D0 w z
- end6 T# k8 [6 m8 J: H6 m _$ u
- end
% y, j ~6 X7 F: l( k8 ^ - - y4 e, E4 N8 h# I. w
- endmodule
复制代码 - Z- f1 u) u$ P! H5 Q
3 B' p! q& z: I1 j
& Z$ I3 l8 y+ g* b1 J0 D( |$ N( a: E3 S
|