一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
2 C+ n) W; [' h$ d" c' Q! ^# H 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拉低使能情况下。
3 e3 H. O* Z- M X9 T) 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发送数据与接收数据。
! Q' Q L5 ?$ ?! w, O- e- /***********************************************************************
, V7 N4 L0 ? }; u2 k1 v ^ - ****************** name:SPI_Slaver_Driver **************' p3 b4 V" `/ l5 n+ D% P
- ********** author:made by zzuxzt **********
0 L) L* z% v$ u0 D - ****************** time:2014.4.29 **********************
3 d" F0 L. L6 H o9 Y6 u4 ^ z - ***********************************************************************/
1 r. T$ ?; N/ @; t$ y+ m( I - //use SPI 3 mode,CHOL = 1,CHAL = 1
- G- M8 i) J1 _8 p3 w, d0 L - module spi(input clk,1 M! J% ~9 J; u
- input rst_n,
' n# N) F1 e- M# x2 D2 k- t - input CS_N,
% r& y2 G+ h& k" M- E7 P) @ - input SCK,2 }8 v) V X5 M6 q' z3 o4 b
- input MOSI,8 O/ y% r2 U0 Z( T3 [5 `( i
- input [7:0] txd_data,! v0 @( p% t( ^
- output reg MISO,0 K, {) |8 y# D* W$ I; D6 J
- output reg [7:0] rxd_data,! Z1 U$ w9 V5 W* u8 I' s* S
- output rxd_flag); //recieve done,please transmit data
9 V0 K% W% w4 @2 {4 j+ @% t Z7 E! A* h
) O, V( c6 P9 i- //-------------------------capture the sck-----------------------------
) m6 r5 }; H# x0 x5 M3 N - reg sck_r0,sck_r1;* e" s% S0 Z6 j5 Y/ ]7 q! J; n$ v0 R
- wire sck_n,sck_p;5 x* C4 c3 H4 G2 f! b
- always@(posedge clk or negedge rst_n)8 X3 p* n: L6 }2 g+ j
- begin
" |7 a$ f0 S- n8 s6 s# p% G6 K' U' } - if(!rst_n); f' T5 ?6 J7 s) F
- begin) S; [9 f9 G% N8 A- H
- sck_r0 <= 1'b1; //sck of the idle state is high1 ~7 Q7 F9 I" q; Q' g+ v0 o/ j0 G
- sck_r1 <= 1'b1;; w+ V1 H9 d" {5 S0 F$ I4 z
- end
7 z" `! ~3 H9 U& y6 F - else
- l5 M- I4 }) p% \0 [ Y - begin* H- K7 C6 Z- R/ g
- sck_r0 <= SCK;
0 J3 Q" B; f" p6 C2 T+ D7 Q - sck_r1 <= sck_r0;2 x# d! H# c( k0 a4 l4 i
- end: D" D% S& _0 m) p& j V
- end9 i L& _; N, e; e& X
- 5 H/ K" x4 E# k3 C3 c( h6 D6 t h3 _
- assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0; //capture the sck negedge
9 V5 l2 X7 {- D, a; {6 x6 j - assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0; //capture the sck posedge8 ]: w' d* A$ x$ {
- 8 I. {( `; M5 O& r: j
- //-----------------------spi_slaver read data-------------------------------8 k5 R7 d+ T& p/ }1 u& B# Q4 F
- reg rxd_flag_r; _7 y, x. f# i, w6 s6 `& q o
- reg [2:0] rxd_state;0 L9 p' I/ V' B9 d' F/ b
- always@(posedge clk or negedge rst_n)+ J7 @' d4 w1 u6 a8 p4 V
- begin, l- s" i! `6 T9 |. n/ O
- if(!rst_n)8 J; t# @3 `, n7 @, M5 i+ _- m' h% }
- begin+ C6 [+ m6 P# H
- rxd_data <= 1'b0;" |6 b2 ?$ a. \- _( Q! `
- rxd_flag_r <= 1'b0;& D* B; w; o0 S
- rxd_state <= 1'b0;
- R9 X8 x/ F9 V) S% c3 U' E - end
3 m2 ~( J& h& m1 t: L - else if(sck_p && !CS_N)2 T, q9 U7 i; V4 s) p9 B+ c
- begin
' V) R& U. v. d5 @% W# T4 O - case(rxd_state)
. H S/ A! h, R1 o# O - 3'd0:begin+ L) q' |: `% o( s; b
- rxd_data[7] <= MOSI;
9 x" k- R' B( n' w$ J* B3 @ - rxd_flag_r <= 1'b0; //reset rxd_flag
6 c/ W0 V+ h8 `% ^& N7 d - rxd_state <= 3'd1;0 M5 C% V& |# }% z: C
- end- B$ y$ Y; P- [3 q/ A k
- 3'd1:begin
* j# G6 ^- t1 a. Y0 E/ d - rxd_data[6] <= MOSI;
0 T3 @- w- h* e9 e: R - rxd_state <= 3'd2;
: Z+ Z2 U$ A4 a- ]. Q1 { - end9 \+ B2 K1 M6 ?6 H1 f R# O9 Y
- 3'd2:begin: ]" V9 O Y9 l4 ?! j' U+ Y( x
- rxd_data[5] <= MOSI;* n# O3 s2 f2 s8 z/ j8 W4 s) } E
- rxd_state <= 3'd3;6 q* F- }* a9 A8 L9 A
- end
9 c( j2 L) z1 _1 G% u/ H+ b - 3'd3:begin
, F d" c2 W5 s. e - rxd_data[4] <= MOSI;2 ~ L. ~7 b2 L; E4 r
- rxd_state <= 3'd4;
. j% I6 M3 ^* l, d/ S - end
7 a! n: y C2 q: U$ e0 H# X - 3'd4:begin2 U9 i& j' u4 x, a X
- rxd_data[3] <= MOSI;
. z+ O5 F% H- @8 E9 Q - rxd_state <= 3'd5;& u" W! a# ]4 H+ p5 d- D6 a
- end p) ]% e+ M; H+ p
- 3'd5:begin
_' w2 H: B& [7 R2 \' X4 h7 Q. K$ Z - rxd_data[2] <= MOSI;- E- Z/ }8 i4 F3 @( a5 }
- rxd_state <= 3'd6;, l% X/ l& [5 [8 i. e2 \
- end
D- c# Y3 j) \/ \ - 3'd6:begin/ d- l6 l" m9 c) R4 g" ~) P
- rxd_data[1] <= MOSI;
- V& S- C3 I0 | - rxd_state <= 3'd7;$ |3 n+ J/ k$ {% ]# p& A
- end
8 ~" w; b* @. x/ S: B! d+ R( I1 c - 3'd7:begin
& R3 Q, \$ x; I( L0 l - rxd_data[0] <= MOSI;0 n* ^& B! S3 U" ^* d9 Y
- rxd_flag_r <= 1'b1; //set rxd_flag- ?3 x9 a7 ~# i* X# U
- rxd_state <= 3'd0;6 z7 d2 M' ^! y) J* b7 j5 ]
- end( L0 W% Y& ~. q$ F2 z
- default: ;
4 L7 L9 d3 g: T. [' v - endcase
5 ?$ |8 t) [3 Z' w - end( _% z( f& G! e5 G
- end
2 l2 g' j" ^6 z - : x8 e& D; L% I% f
- 9 H- ?( Q9 W7 g1 @
- //--------------------capture spi_flag posedge--------------------------------
8 Y' K# c( v I3 L - reg rxd_flag_r0,rxd_flag_r1;, S5 j @: b8 q% x5 E. S- ]7 b
- always@(posedge clk or negedge rst_n)
, M! |- q' W- c9 s H' n - begin
- s5 D) ]& s' |& L - if(!rst_n)
0 W5 v) L& Y3 V1 O, h, [% y - begin6 s% X* h/ {$ c; T* G' i) j
- rxd_flag_r0 <= 1'b0;; d- Q+ f; P7 }
- rxd_flag_r1 <= 1'b0;
& I3 W1 w1 ^+ X+ }: f/ ~9 m9 \: r* Z - end4 _2 f2 F# N3 t: o5 B
- else
4 Y" |4 S0 Y- A" H - begin% y+ H! P0 j, ^8 n) J6 \
- rxd_flag_r0 <= rxd_flag_r;1 ^! l4 ^4 ^* G& R* o1 ~$ j
- rxd_flag_r1 <= rxd_flag_r0;
/ V. f% q8 h; X& J/ g2 [) p - end7 U$ D% t4 L2 N: w7 U8 H2 {
- end+ P6 i' ?: U5 J& N3 C7 c$ {( b
4 B7 ?8 [ p3 P, J. w# v* l. m4 E- assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;0 U! r0 L3 l) {
- 1 ?! l1 t2 T3 h' ]6 m' G, g
- //---------------------spi_slaver send data---------------------------
! J/ |# n7 b+ Z8 e o p6 w - reg [2:0] txd_state;
& L; g9 K" m$ o: Z) m/ B - always@(posedge clk or negedge rst_n)
( z4 |# n, F% p1 d$ _ b+ R - begin. s' c# E, A, f: B8 E
- if(!rst_n)
6 R8 p2 l' r8 @) R; ?; @, r - begin
, w3 @' i2 |' ]6 f2 T - txd_state <= 1'b0;
6 @7 s3 ?+ s6 W4 k# W; `% |! t - end
3 ^ U( H+ q7 | - else if(sck_n && !CS_N)
( h$ W5 k" g/ O/ R: e! H - begin! q- T+ n5 {+ a3 d, y3 U
- case(txd_state)
2 f. j$ O6 f& ]6 g) b- x7 ^, U - 3'd0:begin0 {' x/ t( }5 q' K; }
- MISO <= txd_data[7];2 _( d- f K( l! [% K5 w: A3 h
- txd_state <= 3'd1;
# j$ E8 e) J; l - end G$ ^+ R( J, L$ P! P! s" Q
- 3'd1:begin
7 }0 f- |4 ?% N# P5 m$ V - MISO <= txd_data[6];) E- M* S: x+ r# Q6 F3 @8 l* a/ l
- txd_state <= 3'd2;
. i8 g: W0 ]" H' V, B - end; r/ f2 @$ ] Y; y' F/ ?$ W! P. O) q
- 3'd2:begin1 p X) h. n; |: T
- MISO <= txd_data[5];; u: p& Y* d7 A5 [% C$ E' O5 H
- txd_state <= 3'd3;5 L8 J5 a3 z+ i
- end
8 U) W- b7 z, c- k' @' V - 3'd3:begin, r& j. I& I" e3 P4 W3 C8 y; P. L
- MISO <= txd_data[4];
, U5 Z2 d S& ~' l1 F - txd_state <= 3'd4;
8 M$ n2 P; J0 S) L, o; M. | - end i/ e0 R0 O# S& z l
- 3'd4:begin4 P7 p$ m- f! J1 u" ^ |* h
- MISO <= txd_data[3];
' r" M; ]5 d/ B8 k - txd_state <= 3'd5;
' M+ p" T$ H( D: s8 Z - end' P. s; v/ Y8 ]
- 3'd5:begin
5 \2 h1 v) T- I$ U6 k - MISO <= txd_data[2];$ k+ Q( W: ?$ m4 P, D& r
- txd_state <= 3'd6;" E6 Y4 g9 z& F" `' Y3 O
- end
) e4 u5 \7 o' _( L0 o - 3'd6:begin5 y8 N. f1 p% b6 {5 H f8 d5 _
- MISO <= txd_data[1];
/ e3 u: K9 X7 J - txd_state <= 3'd7;
m7 ? Z ]) C! D" e1 z - end
2 u0 P7 F; Z/ y/ S5 n" w1 w - 3'd7:begin. E2 \ D6 C5 E. L, B
- MISO <= txd_data[0];. g N' L1 a- u5 C
- txd_state <= 3'd0;
% u/ ~! E' n2 x( g: J - end
4 \& p2 b# ], g% O; a3 U4 R' V - default: ;9 A W+ G1 I4 d' W
- endcase, ~; ?1 ~0 G( o7 H1 ?5 G
- end
; ^2 p% _8 z" q8 p/ h8 v! C - end
+ k' b5 F- o# j |' F. _8 ^ - ' j2 k+ q) N! ?( n6 V& M
- endmodule
复制代码 * u! D a O5 W
" H/ L* p2 B2 `
' Z3 d/ e' [, T- `9 u4 c( ]
3 |1 ]. C& ~" |* n9 W, S |