|
一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。* U& m' R, E* k3 G5 M
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拉低使能情况下。
0 x* X! o9 W& j2 V6 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发送数据与接收数据。
1 u+ v+ c. r1 w, R0 u- /***********************************************************************
7 h7 E9 ]/ S9 _+ F' ^) p9 X$ | - ****************** name:SPI_Slaver_Driver **************1 x9 x8 ^& O- G1 w
- ********** author:made by zzuxzt **********
. b6 c+ K$ x* |8 E V8 o5 b, E. i - ****************** time:2014.4.29 **********************3 X# R- g# z/ L+ e- u4 _8 G* b/ z
- ***********************************************************************/
& B v, C9 E9 V - //use SPI 3 mode,CHOL = 1,CHAL = 18 t6 ~+ U/ G$ |# B& V# D+ B
- module spi(input clk,
8 v! p; g, S; ? h - input rst_n,. e' ?5 B" q+ S6 Y4 i% f( V
- input CS_N,, I, O3 m% F6 v4 Y" ^
- input SCK,7 ?3 Z+ E! \& F: Q; a
- input MOSI,
1 U) w/ ]5 N' E9 H - input [7:0] txd_data,1 T2 b7 n+ E7 Y v& h, }
- output reg MISO,
@0 W" i6 V; u - output reg [7:0] rxd_data,
: l' u* o5 ?$ I1 r3 ~. g2 s - output rxd_flag); //recieve done,please transmit data
7 ]& \5 S7 m& j7 g) } U1 U9 d
( }. h! I) b- T) X: t% j; v- //-------------------------capture the sck-----------------------------
4 G r% h+ N. R6 Y3 B- U - reg sck_r0,sck_r1;
, n6 C' {/ E; ^! B a& h" R - wire sck_n,sck_p;1 e" @- ]' i: W( k
- always@(posedge clk or negedge rst_n)
$ ?$ d0 @; I* M: c( ]- y" V - begin
) W; S1 {# D/ e0 m+ E! D* g" g - if(!rst_n)$ A- ]6 [9 t4 V j4 ]! y
- begin
+ L& B) R' s( h n+ C - sck_r0 <= 1'b1; //sck of the idle state is high. q: H: y1 p* b# h1 N( l
- sck_r1 <= 1'b1;
# l( z2 x: @- o; O1 Y4 l2 w" Z - end
7 B% _( c, U& p( O6 k, N1 H - else
}/ @' B' y* a- \) D* j8 X) s - begin
2 `% j* V2 Q7 @3 j5 w - sck_r0 <= SCK;& U2 H" s- v8 }# q9 s' r+ U! m( O9 j
- sck_r1 <= sck_r0;
$ S, S5 A9 N6 k% C - end1 o3 p3 V3 q* b
- end
# w$ W4 x3 s2 Q, M! k& e
' V5 B# N1 N$ n- R, q8 f+ C! @" Z- assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0; //capture the sck negedge
% x. |8 }" q; Z$ ~" S5 A/ T - assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0; //capture the sck posedge% q. ?: h7 }& h1 H8 ]
, A# E( b7 I% }- //-----------------------spi_slaver read data-------------------------------" _0 s" H! M R6 L' @7 D3 I
- reg rxd_flag_r;; I+ m$ o% T3 Q7 q1 }# v# y! ]# c
- reg [2:0] rxd_state;
2 I# T3 V% y5 U/ h$ Q - always@(posedge clk or negedge rst_n)
. k7 `" n/ j. d; K5 A0 O9 {( i - begin
% Q q$ D; `* j+ i. }6 ` P1 V - if(!rst_n)
- p/ F* I2 n, W8 b( P - begin" g5 F+ V/ N) E% Y" z( l
- rxd_data <= 1'b0;
5 W& n. c* t: B+ {* I! Y( o% j - rxd_flag_r <= 1'b0;! {$ r1 _8 c1 Y9 B
- rxd_state <= 1'b0;' N/ L* r, i6 d5 v# J4 d
- end
1 e1 s" N! v8 } v - else if(sck_p && !CS_N)
# T% ~; e" J( l4 a/ U - begin
/ Y0 ]0 X; D, j! g! Z4 A6 K) x - case(rxd_state)2 h9 J9 L+ j+ W6 e
- 3'd0:begin1 {3 g7 S6 \2 \+ S% r
- rxd_data[7] <= MOSI;5 _0 S0 z" g2 h" N8 h4 j, n1 T6 G
- rxd_flag_r <= 1'b0; //reset rxd_flag# C7 X5 q7 g+ z- Y. U* k# _
- rxd_state <= 3'd1;; {; b% v6 S+ H' U
- end
( J" \* u. R) ^$ C( I3 ]- e - 3'd1:begin2 N. _! L: b: F( X- a/ R) D3 b
- rxd_data[6] <= MOSI;$ E+ T& V$ l* o
- rxd_state <= 3'd2;0 x) d) r5 T3 o# @4 n8 A; m
- end, h9 Q P9 Y& P; ?9 j
- 3'd2:begin
1 M! }7 q5 [! k - rxd_data[5] <= MOSI;1 Y9 u+ u' Y3 N7 b2 s9 Z Z T
- rxd_state <= 3'd3;1 q( j% q# D+ L' ~' w7 p% U) C
- end
8 i/ i7 D* u$ @9 a - 3'd3:begin' J- L# o( ~6 T6 k0 H5 t$ g
- rxd_data[4] <= MOSI;
! J% l$ V3 Q- k6 B! g5 F - rxd_state <= 3'd4;
& h/ i( V! P6 f3 _# {/ ^+ V [ - end. o" X$ W- e' O; }1 P7 |
- 3'd4:begin
0 Y' h% x6 R9 n( I) f - rxd_data[3] <= MOSI;; \) r {. V; D) R0 _0 h6 Q
- rxd_state <= 3'd5; D! p+ g. ~8 {
- end7 F8 u" ~2 d c9 L
- 3'd5:begin
- m+ O" h& p" _4 n6 T9 r - rxd_data[2] <= MOSI;
' k8 U5 K) x( Z: T - rxd_state <= 3'd6;
8 ^# y' A s0 d - end$ i3 L6 i8 |: o( B S
- 3'd6:begin
, G' f# D$ w( Y/ \% c - rxd_data[1] <= MOSI;
' o, g/ q; e1 a7 k* H2 v+ `" F - rxd_state <= 3'd7;
# l6 D2 T5 ~) l - end
; Y* D: ]" L4 C - 3'd7:begin
6 K% e" s1 ]! l6 s$ j - rxd_data[0] <= MOSI;; {0 Z/ w8 Q' z9 t s Z
- rxd_flag_r <= 1'b1; //set rxd_flag. _- H$ D O2 M7 _$ M/ [
- rxd_state <= 3'd0;
7 \5 a, M. y* _7 d# R. k4 W - end
$ z" V! V% f3 z+ M2 A - default: ;
4 g- w. I: R0 H. Z$ ^) l9 r - endcase6 D$ M, c' R( T/ ?" n
- end
7 S5 `: c0 _2 b y) @% n - end# _; U! ^1 Y. h0 C b
- / E8 k6 }& [; k
- ) J: F" l) F5 q* g$ B
- //--------------------capture spi_flag posedge--------------------------------% C$ ^8 K4 L# P' ^/ n
- reg rxd_flag_r0,rxd_flag_r1;
* x. F8 V0 i. d2 V3 e4 E - always@(posedge clk or negedge rst_n)/ o" H* o6 ~. ~$ ?4 r9 e5 q. g
- begin
; ^2 R; d l# C, h, i) O. O - if(!rst_n)& i. e+ m5 Q" z; _% u6 I
- begin
1 w- C* y0 Z! w' r' ~. T! ]# E - rxd_flag_r0 <= 1'b0;. c3 ^$ j8 G& f, C7 n1 ?4 T# _
- rxd_flag_r1 <= 1'b0;
$ ]) U' T( z& e, z - end& K7 N1 D4 H. d: M7 d* y8 Y
- else
: a/ _& J$ L% ^5 S; Q' r - begin9 Y( E) v- h% H3 n
- rxd_flag_r0 <= rxd_flag_r;
; j) M" M- g" \; V, _ - rxd_flag_r1 <= rxd_flag_r0;
4 Q$ Z3 k' @( d. _/ E# t/ U, P - end
' |( @% L1 ?4 _6 Z! a - end7 N$ O$ U! R! W1 d! E F( x9 N
$ d* S# ? y' Y7 y- assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;" @$ b9 z- k& b$ j
9 h6 M7 L) ]. m( w- //---------------------spi_slaver send data---------------------------
) ~6 W$ z9 P5 A% I9 [ - reg [2:0] txd_state;
u( }- ?, `* v8 `4 ? - always@(posedge clk or negedge rst_n)
, D$ x# n1 M( c: [. M - begin$ _: {: ^- D, H7 D1 c
- if(!rst_n)
" @ V8 v/ j/ }& J - begin) D* ]" g& R3 V- D1 \! \
- txd_state <= 1'b0;
- s' D9 g6 Z C2 D, m7 W - end
, @- {% e3 E- k2 c9 b% g - else if(sck_n && !CS_N)/ t4 J4 c! e) p( k. t0 Y
- begin
8 k4 X! w% F7 m: E4 V/ ~ - case(txd_state)
- I) o/ @3 @" i - 3'd0:begin
2 A8 a' F; T% x& a/ c - MISO <= txd_data[7];9 R. H/ w2 X$ v6 H* J2 Y+ n% V
- txd_state <= 3'd1;- b3 _0 s7 z+ }4 I/ F z1 W
- end
! S7 ?$ m/ i9 L6 v0 \ M - 3'd1:begin
6 z* k8 n! n6 [' D. T& l1 B3 L - MISO <= txd_data[6];2 o9 [ g1 U" L2 P5 J0 W- [
- txd_state <= 3'd2;& B" k- {2 }9 X' }/ `
- end
) L+ B' D" A9 } - 3'd2:begin
6 A# W5 l! d0 s6 _- h) T - MISO <= txd_data[5];! O4 Z0 c5 Y& a. T9 b
- txd_state <= 3'd3;
8 P3 F9 N. @$ {: n9 U0 E5 ^ ? - end3 j6 D8 \, f+ M7 J4 Y. N) p
- 3'd3:begin
: d+ O9 l% x3 h5 F - MISO <= txd_data[4];8 s) ?$ [. J+ c9 r3 Y6 Y
- txd_state <= 3'd4;
1 _- O* Q( Q6 q8 a - end
" M2 M- c# l$ W - 3'd4:begin1 q) k1 m9 _. O9 _: P) T* [& F
- MISO <= txd_data[3];: w' ~( Z5 i% }* l
- txd_state <= 3'd5;. u# Q: I+ u2 z. A" I
- end& o; }- d' J+ {2 ]% c7 `
- 3'd5:begin
+ h- N; V. Z+ w Z - MISO <= txd_data[2];
1 N- H# @2 t$ L: k - txd_state <= 3'd6;) P- e0 t; O9 g* O& ~- T
- end6 Z% x$ |9 M2 i1 T5 \& [
- 3'd6:begin
7 x2 ^, _! s. c' t - MISO <= txd_data[1];
( w$ I$ ^% l) |' K4 \ - txd_state <= 3'd7;( Q' y X) `! ?6 E' n% X0 q6 E9 a
- end
$ O0 x9 e9 \3 D, W7 S0 F8 F e - 3'd7:begin. L4 K3 M$ N- m2 t
- MISO <= txd_data[0];' @8 \: \% `# c! T. v# H0 A4 f
- txd_state <= 3'd0;; h9 V% M* P% I9 D4 O
- end
! W. }* X7 N2 o9 }3 t - default: ;
% W# A! T& A9 p) N) y1 J( Z* }5 M" x - endcase. A: m' _, Q5 G* \# b
- end
' F d$ W* y) s9 B) ? - end1 N3 e. }- u d) b0 ]! u! e
- 4 k* H, Q K/ X( |5 e' q
- endmodule
复制代码
' Z9 C \. s) R* |: {8 d; Z4 ~9 S# E
/ P% o# h. ]1 Y8 T" z+ u) W' o" w) s1 y% ]. @6 @* R3 H/ c7 t% u5 a" `( n
* A9 M3 @( ]' P4 O& { |