|
一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
4 E; q; N# g) J1 G! 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拉低使能情况下。
2 I6 [% E: d( ]0 g二.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发送数据与接收数据。 % @7 M( z1 {+ t0 H6 q
- /***********************************************************************
# c) a% j0 G6 ?' n1 d7 e$ p6 @ - ****************** name:SPI_Slaver_Driver **************
* _9 D& F) f$ U7 C: l7 W U - ********** author:made by zzuxzt **********
6 B) e1 t' D4 Z: y2 O6 } - ****************** time:2014.4.29 **********************( F: D$ m6 _) |
- ***********************************************************************/
; _' V5 Z6 C: y$ c& y - //use SPI 3 mode,CHOL = 1,CHAL = 12 p0 F$ r0 c1 `7 P5 n
- module spi(input clk,* B0 L; e/ [/ m* s4 b! v( P
- input rst_n,
2 R6 T/ }" i2 Z; c" } - input CS_N,
7 P' m/ r7 }9 U! l" Z4 L - input SCK,! ]5 t4 C4 f, k0 @% Q/ r
- input MOSI,
- T" q9 b4 d; K8 ~ - input [7:0] txd_data,
% n" c+ R( A; N8 G7 y. N7 Z5 U - output reg MISO, X% D# J5 B1 u
- output reg [7:0] rxd_data,% e W, f+ c8 |, z8 S
- output rxd_flag); //recieve done,please transmit data
" L* V6 t7 n/ y6 Q- C" x5 ?* o
* L+ T# I6 T# O j: u2 ?4 t, Q- //-------------------------capture the sck-----------------------------, G* ?/ W, p I: m
- reg sck_r0,sck_r1;
# E! t7 K; `$ X8 G9 Y4 M _ - wire sck_n,sck_p;1 F" L/ I% x: Z' b* B9 t
- always@(posedge clk or negedge rst_n), i" Y1 P; q2 h# L( T
- begin
b* r7 k9 R1 i* F# g7 b - if(!rst_n). r2 c4 A# v E$ p; ]
- begin
, _- |1 d8 i5 H | - sck_r0 <= 1'b1; //sck of the idle state is high
" ?* \- ^6 g' M4 M - sck_r1 <= 1'b1;% j2 R" A6 E. i& O4 L: \, w
- end& Q6 N7 w4 [( z, q% o
- else
5 J" y( a7 F3 k( A7 d! }3 E - begin
, ~) x1 W3 y8 d; d! W! n - sck_r0 <= SCK;- ]. o" n3 I7 @8 U
- sck_r1 <= sck_r0;4 t5 h9 n+ m7 H- n
- end# o6 R, Y+ k4 ]2 V1 E2 R
- end- E% S# |( L$ N( s1 k2 r' F# D/ \$ L: ~4 Z
9 X N+ K9 R9 o; x; B- assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0; //capture the sck negedge9 M1 Y7 ?8 _5 @8 u7 \8 |5 ~
- assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0; //capture the sck posedge
o& S" c3 d3 N: L2 `
" i( S B" Z/ L/ Q' E/ z1 k- //-----------------------spi_slaver read data-------------------------------
7 C5 B. }5 A w+ |7 `: D m - reg rxd_flag_r;
0 s8 a( N9 }, w u% O# e - reg [2:0] rxd_state;
7 o# z* O t4 b; M6 ^0 ]! q" T - always@(posedge clk or negedge rst_n)
/ J. [" W# }6 l- A8 L% u6 [# a - begin
5 E E. C( D0 A: Z7 L - if(!rst_n)6 _4 h6 c% a% e! y5 _" [( H. P" R1 T7 T
- begin6 `5 i f* F1 r* C" ^- W C
- rxd_data <= 1'b0;
2 U- g ^& @7 O; y" q/ O O5 W, Y1 s - rxd_flag_r <= 1'b0;5 @/ F$ Z! ?$ T- _; T3 V
- rxd_state <= 1'b0;
+ h5 ]7 t9 Q$ q8 e- i/ \, [8 N1 r - end$ ]; V5 u/ y9 U/ I2 F3 n6 C. s; G
- else if(sck_p && !CS_N)2 M; H* X$ i' t8 j
- begin5 h- B5 N. z. \" m6 S1 {
- case(rxd_state)$ D# o" E% m) i& L
- 3'd0:begin- I8 w5 A2 f/ G' z' z, ~
- rxd_data[7] <= MOSI;, n7 Y7 d* j: g- X, v
- rxd_flag_r <= 1'b0; //reset rxd_flag
2 F9 b1 p3 s% A1 t - rxd_state <= 3'd1;6 K% R. y7 e% Y1 O" }% |0 F
- end
0 ~5 p" f8 J1 O) @' I - 3'd1:begin |5 \ r1 r, E; o* a" Q
- rxd_data[6] <= MOSI;+ G) l3 t1 h) s" ]& G/ q9 L1 E2 S
- rxd_state <= 3'd2;
6 U }8 T% E0 b! }4 G' H4 A - end5 [: o( u) m9 ~2 E4 p$ H
- 3'd2:begin
. N7 ]+ v+ _) G" o - rxd_data[5] <= MOSI;
$ r+ o3 Z& ]( \7 i6 h - rxd_state <= 3'd3;! g& ^0 g* j/ l5 z/ w, G
- end! A; }; n8 j5 c) ?7 L; y! T! D
- 3'd3:begin
7 k" e, R3 K8 P' ^, N - rxd_data[4] <= MOSI;
% c( V5 p5 i; e& A - rxd_state <= 3'd4;
) ~& }5 t, {- F - end
% `" N/ X& Y/ p: }2 e1 I - 3'd4:begin2 F% }9 p, a& v3 ~! G9 k
- rxd_data[3] <= MOSI;; \% \7 p" g8 M; F" y. Y! p! i
- rxd_state <= 3'd5;
- n- R; A: c0 N9 f - end
) P8 t+ {, Q9 a9 W0 e/ o5 w) _ - 3'd5:begin
6 P4 B; n0 {; F4 Z" D( U" @ - rxd_data[2] <= MOSI;6 C# V" u6 e( N. s
- rxd_state <= 3'd6;5 {- c, j# z) [" Q2 L
- end
! Z# Q" g" }/ |" B - 3'd6:begin& e2 x7 N& n* d
- rxd_data[1] <= MOSI;
/ Z. j7 B; T* q; y! N" a, [- V - rxd_state <= 3'd7;
+ ~& d* c" p$ G8 e8 N# J- ?4 s - end
( C( O3 D+ v, J$ ]% R - 3'd7:begin
9 [6 z- L( I+ _7 P - rxd_data[0] <= MOSI;
6 I' t2 x7 A+ @* }) n - rxd_flag_r <= 1'b1; //set rxd_flag
8 N1 a1 i9 B9 v$ \. v, _8 f' ` - rxd_state <= 3'd0;. W' \6 ?6 p4 ?: F; Q( B
- end
8 Z v# t- B- |, c o" V - default: ;
7 E& b* x/ @' r% ~1 o; ^7 _# E6 m - endcase
6 m; t+ q1 X+ Q. S+ |2 Q - end
4 d6 }3 ^% ^6 V - end- [! ]8 I0 e, I
- ( E8 N# W; x% d& l: A- {4 L" x
- 5 k5 _) K2 l5 v* I8 V: O
- //--------------------capture spi_flag posedge--------------------------------
. X; g. w' s. K* n8 B - reg rxd_flag_r0,rxd_flag_r1;
$ L# |' b4 d5 R$ L - always@(posedge clk or negedge rst_n)3 W1 n% u, l% @8 m. S$ i
- begin0 A3 y- ?6 E* _0 n3 Q4 Z' |. |! y
- if(!rst_n)1 Q- G( x# \" B8 F9 {
- begin
% O3 l* ~$ w( W0 t h4 Z; b% C% S - rxd_flag_r0 <= 1'b0;
2 R/ e5 { Z. U) @ - rxd_flag_r1 <= 1'b0;0 {/ C' a5 Z% w5 j; J, R g( ^9 ]' C1 h
- end
) K7 X I4 i; ^1 N - else
: r9 I0 Q, F' E - begin
, Q* n0 q5 c2 Y" S+ o - rxd_flag_r0 <= rxd_flag_r;
) f; t7 F( b+ s/ |4 k: P - rxd_flag_r1 <= rxd_flag_r0;; k5 Z- C. |+ s. g
- end, u! @, L# Q& @0 m' U
- end
# g5 |) _( T3 \1 U6 U g5 p1 k
1 h1 p: ^* F2 m$ I# M1 R, O- assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;" H* [5 K% N: ]7 t
7 Q, u7 R; I8 T5 N* P5 Y- //---------------------spi_slaver send data---------------------------
2 {2 l9 f3 e' H( U Z - reg [2:0] txd_state;
4 c+ z1 J, L ] - always@(posedge clk or negedge rst_n) B3 ? K* Z4 X4 j4 I0 L6 b, \5 G
- begin. O# u) O6 S% m- V: h; b0 P8 Q
- if(!rst_n)
; h0 N+ A% S( ?: o# @ - begin% j0 R4 C/ x; L
- txd_state <= 1'b0;2 d7 b7 Q8 ]2 \: F0 \
- end
4 T0 A V: ~1 \7 }+ n2 r; ~2 r& d - else if(sck_n && !CS_N)
$ j8 d0 ]/ z3 l O" h* d7 k - begin
* i2 U* C$ B- B1 w9 g2 u - case(txd_state)
: s! M6 k2 U7 b - 3'd0:begin
% I- v1 |" o& M! v! d' e- z; H6 R - MISO <= txd_data[7];2 @) j8 P1 |, U7 T& M8 I4 ?: Y
- txd_state <= 3'd1;/ C! A) a5 `" T. v$ f
- end3 m& W6 z( l7 T
- 3'd1:begin# k8 H ^& W5 {
- MISO <= txd_data[6];6 `0 H% u1 Z- p7 M Z- v
- txd_state <= 3'd2;
0 Q8 }* n7 t8 ^/ x: r - end
( l: r0 c$ Q3 U9 k: T* h- g/ H - 3'd2:begin- G& ]: D( X2 J5 z. ~7 Z
- MISO <= txd_data[5];
" i6 Y! I* G' d1 x2 R6 S - txd_state <= 3'd3;
, a7 O4 D& q& I; R - end0 O6 n" Q: W9 M* g5 @& q
- 3'd3:begin5 Q6 Q4 Q2 t$ L7 c6 }
- MISO <= txd_data[4]; m1 u+ S$ T; `6 G- L- ]" [% e
- txd_state <= 3'd4;
2 D+ \: J1 h( S1 {. n0 f1 m% y( G* i& w - end
3 Q3 U' n/ v( T0 C1 K* N$ X - 3'd4:begin
3 `$ |# O/ j" a" h, j; q - MISO <= txd_data[3];
- O9 ?) I; ?0 L$ }; w+ P1 s- v9 P - txd_state <= 3'd5;
D! X# U2 s' w - end
4 b' e# ]% c9 J$ d" E' |% O - 3'd5:begin) _1 {# |* x, ?
- MISO <= txd_data[2];
* c6 {$ V3 e; q - txd_state <= 3'd6;
) S+ e% h/ U# ` - end
4 p) O4 ?/ D, a4 b& Z! \ - 3'd6:begin3 ~) x$ P) @, X( \
- MISO <= txd_data[1];
! W1 _/ E/ X4 Q% \- G - txd_state <= 3'd7;
" R% Y7 s) r% {5 E6 n - end
. P: P5 \% x: Q7 q9 _. K! k' V' d - 3'd7:begin
( \. O. l; i+ @# s% | - MISO <= txd_data[0];
! ]# g0 ] Z: I5 a% d' R - txd_state <= 3'd0;1 `8 H% h% I1 b! a6 G4 ]0 }, I- ?
- end
# [6 P6 A8 m5 d/ b9 U( B - default: ;
) P5 h5 e6 @5 e' M' H1 Y$ U) \ - endcase
8 J* s% w5 q- s* i! ^, ^) |0 d - end. b f0 z. O. k# {) F
- end
l1 g: _6 D4 `( p) K( Z0 ] - $ u$ _7 A8 n2 r) n
- endmodule
复制代码 3 I+ }2 u% Q: Z4 Y+ k7 q
# B2 {# S9 d) \. a+ v. _. \. j
; e3 l* w$ C9 N
. z' B; }( i5 j& |% l# S, ? |