一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。, ?6 j1 i" \6 ]( R
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/ `% k' N5 d8 q' |" u: }二.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发送数据与接收数据。
. Y- ?( F$ P: Q/ I- P' p- /***********************************************************************
; I( m+ r x' b1 [9 @4 K9 }8 c - ****************** name:SPI_Slaver_Driver ************** ~' Q" T( u7 u
- ********** author:made by zzuxzt **********
$ d2 u+ h3 {* w& N - ****************** time:2014.4.29 **********************
2 R( y0 ]2 B+ c1 S( [ - ***********************************************************************/
; a9 _) r. |8 j+ Q7 O" v/ D5 p* Q - //use SPI 3 mode,CHOL = 1,CHAL = 1' c* W) D0 X( a4 r, k3 v. m5 Q" C+ u
- module spi(input clk,( K: b k2 A% J! a9 H4 \2 m6 W5 }
- input rst_n,
( P- l( j8 q2 H0 ?, B - input CS_N,
. K4 |7 [( o6 L* B1 v - input SCK,1 T% n( M7 K+ q
- input MOSI,7 m6 w5 O# V: v9 n
- input [7:0] txd_data,
* Y2 e, ~# j# o: ]! I6 ? - output reg MISO,
8 K2 X$ o T2 M# y - output reg [7:0] rxd_data,
# ]( k/ W" I: `7 L+ n9 U' ?+ O& q - output rxd_flag); //recieve done,please transmit data
5 }4 l4 L5 c$ j; ]4 a
% V" N A0 d6 f- //-------------------------capture the sck-----------------------------
3 \, d+ u! O7 B( g7 u - reg sck_r0,sck_r1;
3 [& |! N$ B% a6 q6 `# \" d - wire sck_n,sck_p;0 L7 f v( r0 J' _8 d6 g/ {* a# \( C
- always@(posedge clk or negedge rst_n)( a/ U; I; P: [
- begin
9 Z! a8 v7 T/ w: r0 N' B% A - if(!rst_n)' U* v; U9 L5 X/ C4 G
- begin$ k5 O$ ?1 G% D+ {- j7 E F* _
- sck_r0 <= 1'b1; //sck of the idle state is high; n4 `& Z5 S$ Q
- sck_r1 <= 1'b1;
+ V( i' g+ P0 _ - end
( f% W. p! H; b/ r - else: e8 C0 O4 r5 e# w4 T/ f3 v) g, u/ m4 _
- begin6 G4 b+ K$ p6 ` C0 [! t
- sck_r0 <= SCK;! W" L, N3 Q& B2 H
- sck_r1 <= sck_r0;
, S0 t, u# ~+ |1 X, I* o& a; B- { - end" H8 g" A3 E7 }
- end f# c3 G- }. s8 k9 E, t
/ {4 b/ C( X" O4 l" s+ u7 _- assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0; //capture the sck negedge2 I1 x- @6 |% g+ V
- assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0; //capture the sck posedge& `) T' l) j; o6 e* t4 m$ q
- ( I1 D# r$ }9 O$ v$ W0 `; o
- //-----------------------spi_slaver read data-------------------------------4 `! j, H! Y, v1 P
- reg rxd_flag_r;6 Y% |% c, r2 h7 @0 g9 C" Z- f
- reg [2:0] rxd_state;1 h6 `* r7 h7 ^( A
- always@(posedge clk or negedge rst_n)* `6 t1 X/ W" H' P9 l ?- f6 h8 b7 t
- begin
) }. g: J# Z9 F3 L - if(!rst_n)
% s/ ^, E( g* T. s. Q1 o - begin& r8 O+ T9 |# _" p0 H
- rxd_data <= 1'b0;
( l u+ m5 j3 Q2 R - rxd_flag_r <= 1'b0;8 Y1 K" e6 M7 G& B; k8 J
- rxd_state <= 1'b0; c$ a5 J0 o2 j/ `7 f" L* D. r
- end
) H# p, s; t! J9 q# w6 ?; F - else if(sck_p && !CS_N); ?$ t. a6 p7 n& H( `
- begin4 y. x& {. R5 I0 u9 c" e
- case(rxd_state)* [5 s/ P4 p1 `
- 3'd0:begin" n4 h( q, A n& Y6 H. l7 d6 W8 ]" E: e- U; i
- rxd_data[7] <= MOSI;2 g5 U2 M, j, e, u$ G
- rxd_flag_r <= 1'b0; //reset rxd_flag0 u) }1 |4 w- n( C% m
- rxd_state <= 3'd1;+ x8 m# Z: U3 X: G% r. ^
- end, E# [1 n8 o1 g3 y2 M$ _' A
- 3'd1:begin
, v- S7 l! g+ E+ e: S' H# _! | - rxd_data[6] <= MOSI;+ N$ l9 E' G0 _
- rxd_state <= 3'd2;
, U2 v# O4 [6 i6 ^$ y% `6 V - end
! K4 O3 y: i7 n5 f, n5 r0 J' B - 3'd2:begin
% k: y" K' q b9 P - rxd_data[5] <= MOSI;
5 R' ?; o9 Q6 ~2 a4 H: N, j - rxd_state <= 3'd3;" k' w! ~/ [- s7 Z* A1 Q* [
- end
7 F; R* O. {* C0 G1 m" {5 h, J - 3'd3:begin
$ R. X- V8 `9 b! v - rxd_data[4] <= MOSI;. J& q6 b2 Q3 b1 v. S6 s3 J% N. X
- rxd_state <= 3'd4;
" H% }7 D/ H1 w; d- B9 Z - end
# h( X' k# l2 o* M - 3'd4:begin
7 g" O/ d6 D+ F' R+ J. O - rxd_data[3] <= MOSI;
+ F4 ^/ ?2 q" v7 u0 r& ? - rxd_state <= 3'd5;
+ j3 { }5 s7 j2 U - end! h- [1 R% R& y: H' {9 O- y) n# ^
- 3'd5:begin' C8 z( Q4 E' q2 _) ^
- rxd_data[2] <= MOSI;
+ {/ L( |! g" ]! a1 U, f9 v" L - rxd_state <= 3'd6;( X$ l' z0 }, r1 u& ^3 O; e' [
- end
) J/ \5 w: L% B, s4 g - 3'd6:begin
. m; m* O/ X+ Q; D y- r/ O - rxd_data[1] <= MOSI;
( a5 X( Q4 ~9 h' g7 O! ]$ d - rxd_state <= 3'd7;* v; i4 F/ Q2 p6 ]& r
- end0 T1 D" C1 Y3 x
- 3'd7:begin
: i; S" `" ^& t5 D7 v - rxd_data[0] <= MOSI;* g: P' Y2 X$ d3 {
- rxd_flag_r <= 1'b1; //set rxd_flag
/ f0 r s5 G+ ]4 H& h- v$ }, T' \ - rxd_state <= 3'd0;
$ o7 i2 N% V5 H+ M6 S; D( P4 a7 Y) D x6 h - end7 c# s* u4 t$ Z' }6 {$ ]% h1 I3 M& R
- default: ;! t, U8 v' z) d. b* n9 e
- endcase
2 A) M% r4 @ R6 [/ i6 a; O5 E - end9 ~7 y5 C+ ^5 M0 _1 T
- end
: O! f0 A3 s- j% S8 C3 ~" \' h - ( {' t4 t4 Q# k6 b! d, W
- # C: R6 ~# V# w; Q4 M
- //--------------------capture spi_flag posedge--------------------------------
4 \! T* U; J: b; t - reg rxd_flag_r0,rxd_flag_r1;
) U3 V& ^6 ~5 O. w - always@(posedge clk or negedge rst_n)1 E5 e( Y' q, j/ d3 F& P
- begin
4 e- W* N7 _& G3 q& F) W+ X5 } - if(!rst_n)
5 V% L1 W' P1 Z - begin% Z( g: i' E2 j: B/ @
- rxd_flag_r0 <= 1'b0;! \* X0 T7 l$ \' F+ j D; H6 R, n
- rxd_flag_r1 <= 1'b0;
# F7 T7 |" G) n% w4 b+ m& N0 [ - end( ? D/ e6 U8 f( a8 W8 r( y% \2 b
- else2 h8 Q2 K, f4 F
- begin5 [! j( D0 h# |
- rxd_flag_r0 <= rxd_flag_r;
" o9 n# ~) L4 _4 ^. d - rxd_flag_r1 <= rxd_flag_r0;- a1 t3 U" C4 k
- end
- K- s7 ~4 S8 C* [; v8 v# D - end
( {0 Z- p! B2 `0 ^5 D" q - ; D1 V# D6 g. N* r" u6 S' a
- assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;3 @, b. s0 [( C; n( t) x( g Z
- x% @ Y0 m. \* j
- //---------------------spi_slaver send data---------------------------8 \& \% w0 m0 f! N' g
- reg [2:0] txd_state;
" I4 A* t2 C7 E& z) g5 n/ o4 m - always@(posedge clk or negedge rst_n)
2 s5 M% n: k# \7 g: ~ - begin
: x# @: t4 {6 a9 K8 O: C5 J - if(!rst_n)
+ E* u2 k, [, L, h - begin
2 j$ j0 v6 f, j4 O - txd_state <= 1'b0;& ~8 h9 z% X, d3 N
- end; {" [. j2 L4 B+ y6 |. f+ Q
- else if(sck_n && !CS_N)
8 b( J7 D4 n; Q& F& V - begin8 Z1 J# @" Y$ E% m& S, f+ }
- case(txd_state)
# t$ A0 o- h) z# t4 i5 i: L/ o - 3'd0:begin
8 i; Q0 B! n0 X - MISO <= txd_data[7]; U, e6 W' }$ z" w5 c6 [, V
- txd_state <= 3'd1;6 u' q6 V0 ?/ j7 I! M5 N i9 m) s
- end
2 C8 {: s1 x: ]: W( K2 [8 u5 K - 3'd1:begin% V6 k H/ _. t b' W( J% o) V
- MISO <= txd_data[6];
, r, d( b7 F2 R% H& Z8 y4 F - txd_state <= 3'd2;$ k( ?, G t, K6 m; X
- end
% x, w9 E, u: S; d- R; m1 u! a; Q/ D - 3'd2:begin9 ]! J' j @+ y& ^* A/ [7 q% ]0 j, h' m
- MISO <= txd_data[5];
2 y; v+ @1 u* [% @" a - txd_state <= 3'd3;
2 e( v6 L+ ?0 y% N% u/ z - end, L% I9 g3 Y1 D \- x! {
- 3'd3:begin
, ]& t2 Y1 ]1 f3 } - MISO <= txd_data[4];
0 A1 @) @2 P! x7 z - txd_state <= 3'd4; Y/ k4 ?# \0 H S" K$ K$ T
- end
9 W5 M5 B' m1 t" f5 H j - 3'd4:begin
( j( j& S6 J [! |7 B2 L$ | - MISO <= txd_data[3];
& c6 q, x& v+ ]. ]* R - txd_state <= 3'd5;
5 |% {! k6 p7 P/ r4 r$ D - end5 {+ ?( d* o# |) \) ~ _) D
- 3'd5:begin
7 R8 _+ T/ ]; F! d2 m3 z - MISO <= txd_data[2];9 `9 N2 Q; \4 e) C
- txd_state <= 3'd6;
6 u; t9 `, }/ d7 T - end
; s7 z: p' e- T, A+ C- T- }8 x9 I - 3'd6:begin
# j- e. N. M; ~ - MISO <= txd_data[1];
7 Q0 n5 x/ V4 m - txd_state <= 3'd7;
' S& v ~) X6 ~0 x5 i" S" a - end1 K8 K3 X) C$ k) V- B2 c
- 3'd7:begin
/ d. n/ A. b. V/ C) V6 M3 | - MISO <= txd_data[0];
: q8 Z7 ?+ T5 V# E( N" r - txd_state <= 3'd0;
" ?; ]' T/ m" z6 w) X2 e - end
" N$ U0 g1 t; J- s+ w) E6 | - default: ;7 c2 Q7 h5 \4 |7 b# t Z
- endcase0 }& H; n4 A( | g" C
- end0 T. L9 S7 m" w: g8 O& I
- end3 ^ e& ], N, a/ X2 U7 D
$ H9 Q- m8 m. n. [& S5 h9 f- endmodule
复制代码
3 R& Y# t. T: K/ H2 q* z/ q! X( n1 a+ f) f; \
4 u) w! u( q1 T
$ Z8 D0 g8 k# k2 E* \3 B" m |