一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
; a3 b/ j$ E7 H3 c 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拉低使能情况下。 6 P& T$ N" K% l$ d! B0 F, Z7 C
二.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发送数据与接收数据。 $ l! X! f) B% n: _
- /***********************************************************************
: w) n- t( q, a - ****************** name:SPI_Slaver_Driver **************
3 ^0 P7 r6 E& h- r - ********** author:made by zzuxzt **********# Y7 A3 i' a. R
- ****************** time:2014.4.29 **********************
4 U7 k0 y/ Q2 E5 j. p - ***********************************************************************/
/ ?+ v1 v6 u6 H; w6 k - //use SPI 3 mode,CHOL = 1,CHAL = 13 M6 A( S [( Z" E
- module spi(input clk,, T3 G: B% g9 f W1 e
- input rst_n,
; z; w5 _2 y* g5 } - input CS_N,- u5 | _( o' L/ X! K2 f& @3 ?
- input SCK,
2 j9 h" e3 V- U& E+ H - input MOSI,
/ g. w) V% K2 X# Y - input [7:0] txd_data,+ I: ?8 l9 N, w
- output reg MISO,
: N7 v- [2 O! G: W# S5 l - output reg [7:0] rxd_data,
0 s ~8 ~0 `0 y: T- X" Z8 N - output rxd_flag); //recieve done,please transmit data
* J5 A/ O2 w) Z6 t* H - + s* C- ^; A' h
- //-------------------------capture the sck-----------------------------6 z3 x; h$ O) Q5 |4 s; g
- reg sck_r0,sck_r1;
% A7 i1 S. M/ B ^: T( K3 a" V4 x - wire sck_n,sck_p;
2 q/ S5 F# M- g+ ~7 Z- U - always@(posedge clk or negedge rst_n)
7 K% L" S ~: [" s2 b; x0 i - begin) V; b' [+ K0 _) _' r% v/ p% a; i5 \
- if(!rst_n)
! Z# q- ]$ K6 r% o+ ~ - begin
/ _! t: w/ g0 s c; P5 j& h - sck_r0 <= 1'b1; //sck of the idle state is high6 {* \5 V S# g1 E( W0 z; C
- sck_r1 <= 1'b1;$ q& e1 l! k4 H2 }! {) {3 {7 c
- end
6 s) h: t+ {# ?: n) \$ J - else
$ s' P0 U+ ?# [: u; a - begin& r" v/ K/ Z& |- T& L3 k
- sck_r0 <= SCK;
; ~; V3 ]3 m$ K$ e: b/ U o: J& W - sck_r1 <= sck_r0; r; _" k. p7 o& t6 ?3 G
- end
- K/ P, x4 G3 g5 X4 y G - end
0 k3 @4 E( d4 t: P n4 B5 d
0 J1 ]+ A# u2 z5 R/ ]7 G1 N, \5 D- assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0; //capture the sck negedge: I+ l5 ]# I8 P6 A0 R! i& p2 o. o
- assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0; //capture the sck posedge+ X# F4 @7 `# `9 ], g
- 7 U0 v$ G0 T0 B6 O0 A+ [
- //-----------------------spi_slaver read data-------------------------------
/ Z$ R2 u$ y4 @8 h3 m* f& ?9 j - reg rxd_flag_r;6 B& I: [$ b; c
- reg [2:0] rxd_state;, t1 ?7 t' q6 F0 i
- always@(posedge clk or negedge rst_n), J2 I x, I0 e, D! M1 D. j
- begin
9 X+ R, w: l5 _( N+ i - if(!rst_n)
: I( p2 {/ r9 s1 ? - begin
9 r4 W7 I) u9 V# I - rxd_data <= 1'b0;# B1 g* B$ Z# F' T4 d) D& E R
- rxd_flag_r <= 1'b0;
' y2 l) q# D7 G5 b. P6 @! u: e$ i - rxd_state <= 1'b0;
; J3 L5 M9 q9 S y( G! N1 @ - end; O# N) N$ S1 h/ @
- else if(sck_p && !CS_N) ?+ b$ ~' d* s
- begin
8 R5 z; f! o9 J( d - case(rxd_state)4 U6 B) @' Y4 f+ ~4 A: ~5 W" F
- 3'd0:begin
2 j. C% }) z: h$ n3 j7 `) P. ^ - rxd_data[7] <= MOSI;
! L; e$ D6 b, @, @ - rxd_flag_r <= 1'b0; //reset rxd_flag
+ ]8 @6 ^- q+ ^' K* g - rxd_state <= 3'd1;
2 z9 V/ B1 a0 D5 M) v+ K - end
Q, U* `5 j( L) ~1 J7 R5 G' I - 3'd1:begin7 Y1 X. |; t5 q0 z# R1 l: A
- rxd_data[6] <= MOSI;" f3 Q4 X& D1 o) Z0 S- |
- rxd_state <= 3'd2;
" o+ n- S" G* o) t% k5 Y, z - end/ q" A3 v. S, z/ I2 n
- 3'd2:begin
4 P$ [* {; O6 E - rxd_data[5] <= MOSI;9 p" }, J7 s# Y
- rxd_state <= 3'd3;: `6 [' x0 _. u2 {
- end* Z2 m) \7 z5 t3 W4 X" Y0 ~! g
- 3'd3:begin
' r$ N" J% F2 B8 g. O. N* q - rxd_data[4] <= MOSI;, ~: l% R! c) Q0 C6 h& n( c
- rxd_state <= 3'd4;
- s# b% M* Q7 R F L$ o' @ - end
& m' d' n* s& b0 B0 s; `" p* w - 3'd4:begin6 K- M; n5 R& A: I- H8 g
- rxd_data[3] <= MOSI;1 k6 S, Q( \3 F6 b( W* ?9 ~2 V
- rxd_state <= 3'd5;7 L0 x% Y# X2 W
- end
1 {' ^9 [4 d' S9 d% B0 X - 3'd5:begin+ y, c4 w# Z2 a
- rxd_data[2] <= MOSI;" X& j& Y6 B. _4 X
- rxd_state <= 3'd6;* @! q% [: |& ^) x
- end
# I6 r$ T" N. p1 Y - 3'd6:begin( y4 G: @3 z- D& P( q8 Q5 u. C: I9 X
- rxd_data[1] <= MOSI;
9 X% _) @1 y. z7 k2 A, C4 i - rxd_state <= 3'd7;. o. _( j/ {8 ~! q8 s
- end
4 ]9 ]& q% h! F7 ]7 G# @, D - 3'd7:begin
" s4 a+ h" y: }$ u4 | - rxd_data[0] <= MOSI;
- q, {( G' h0 ?! J6 L. j8 H - rxd_flag_r <= 1'b1; //set rxd_flag
9 L3 m& N# l( } - rxd_state <= 3'd0;
/ K- i9 U) P0 Z& A( @2 \& i% C4 f - end q0 Q# Y% C' U
- default: ;
/ n7 o5 u1 E* O \& _7 u - endcase9 X2 t* z( `5 y2 Y7 s4 M
- end
+ e/ N1 R" P1 ~5 e5 F - end
6 c! ]8 y1 q& y8 Q4 U" z
3 B* q E- M2 [8 y
* k3 O g, ?6 y4 C. }2 m' m- //--------------------capture spi_flag posedge--------------------------------0 l f* g2 i$ n0 o+ ]
- reg rxd_flag_r0,rxd_flag_r1;
, E) d# A o5 N; \3 @- [- |4 C - always@(posedge clk or negedge rst_n)
/ h/ ] b3 S# b& Q0 _3 I8 t: }( ^ - begin
) {# C' {5 F% i9 R* n! D - if(!rst_n)
7 c: p5 O* s5 \ C - begin
9 [/ C0 S0 {% m+ o$ q - rxd_flag_r0 <= 1'b0;0 M) q/ g( M6 n& ]( b0 j2 a2 H
- rxd_flag_r1 <= 1'b0;
0 x$ }3 G0 Q0 ~ Q - end" N5 k! T. ]4 G, g
- else
- p( E) T: T1 w$ J) a - begin
$ d$ b- A8 f! J - rxd_flag_r0 <= rxd_flag_r;
, {3 N2 E) x8 X9 Q, g a1 Z* v) Q ~ - rxd_flag_r1 <= rxd_flag_r0;- J8 j+ _: a; G- h) x" v
- end
' b: s4 M( b' A! w8 @& M7 n5 r - end
0 ?, }# M# {2 I/ G9 J# h/ I
' M+ \8 g: F0 v9 d1 ]+ `' c1 e- assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;( V7 e; Y3 b+ O. c
* M1 @1 A3 @: ^- L. v+ d3 \1 }0 W- Y- //---------------------spi_slaver send data---------------------------
3 g2 c/ f% g/ [# Y; s - reg [2:0] txd_state;
4 W K% V4 ?0 H1 S/ @2 @/ c: z - always@(posedge clk or negedge rst_n)3 _" A3 A) v7 d6 x2 ?3 k
- begin
2 o3 G2 p b: |+ u* G: m* X - if(!rst_n)' t* r: C4 b" I
- begin- J: P7 e q0 m) m% t
- txd_state <= 1'b0;
7 h7 c, W# N* j% d1 K* c; B$ L - end2 e6 ]1 f; r6 b) [
- else if(sck_n && !CS_N)
- E6 u" L% m7 I( z" J - begin
5 N: q3 W f( W6 P7 Y: K - case(txd_state)) `- }. A+ s+ I
- 3'd0:begin5 a0 F) R1 @# X! s- b0 [1 z: o, Y
- MISO <= txd_data[7];& y, C1 [; ]: ~) z. X. V1 m
- txd_state <= 3'd1;) S6 p0 W. }7 A
- end
2 q8 y' X. {" K. t8 ] ]; z - 3'd1:begin
3 v% k% i |- E$ \4 L: Q - MISO <= txd_data[6];
/ X0 n" R( E" O7 y+ z, o6 M$ o9 c1 _ - txd_state <= 3'd2;
. s( i" ]- A1 F/ K - end N$ t t$ e! o7 X/ v% A
- 3'd2:begin
( r6 e1 z4 d, a6 K: ]5 A# ~ - MISO <= txd_data[5];
3 }7 h$ o3 Z& |( M9 e - txd_state <= 3'd3;5 s8 e( p2 i# f6 l8 Z
- end
8 B* p* p8 E- L* S) _; t - 3'd3:begin& c0 k+ I( u; w5 T, u
- MISO <= txd_data[4];
2 J5 _- H6 A, t% Y5 T/ V* Y - txd_state <= 3'd4;
$ P. L* w& J" d6 t: m! H - end) b4 g( [0 p* W' i; `
- 3'd4:begin
7 j2 F2 ?' |; v: P3 ]: I* p$ a - MISO <= txd_data[3];& [+ m7 f& o+ H0 |3 w
- txd_state <= 3'd5;1 @' x2 `2 s3 m8 o4 T4 s v
- end
3 j7 g- n% @0 @# x- b - 3'd5:begin6 }7 p7 {! N- e9 ~+ |4 E
- MISO <= txd_data[2];
' J0 Z4 ^- @ W0 T, V: G0 K+ ]$ n - txd_state <= 3'd6;6 Z; z9 u/ {; c. a
- end/ X, |8 J2 `" X9 m
- 3'd6:begin: s# @! }' X: z, M# Q$ Q
- MISO <= txd_data[1];
1 a, r: O) ^( A' M2 R- S - txd_state <= 3'd7;
" @' x% C1 w" K! s" \) b% |+ \! Q - end
6 p# k$ `3 d) Q. h8 A2 @ - 3'd7:begin+ m$ Z: p6 \$ k5 o6 o. D2 [
- MISO <= txd_data[0];
- `% U( D; i; n; \+ L8 n% r+ ` - txd_state <= 3'd0;
; i" K- D5 w6 Z0 d2 \, c T - end
0 K1 I" d: o! {* V3 o, a - default: ;
0 `7 \! I6 ?$ w! e- s$ ^2 _ - endcase" K7 h& f+ l3 [
- end
% X' Q$ |: O) p4 | - end V+ ^. d; M: b% C
% k$ i; E. I- }# c/ {; d) Z4 w- endmodule
复制代码
' ?$ W, T" w- T; Q
6 R6 Q6 t/ m9 U `- J
6 S0 x4 U, @# x. s" i- x+ r* z" h6 E6 q: o
|