FPGA作为从机与STM32进行SPI协议通信---Verilog实现 [转]
一.SPI协议简要介绍
SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
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拉低使能情况下。 二.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 /***********************************************************************
2 ****************** name:SPI_Slaver_Driver **************
3 ********** author:made by zzuxzt **********
4 ****************** time:2014.4.29 **********************
5 ***********************************************************************/
6 //use SPI 3 mode,CHOL = 1,CHAL = 1
7 module spi(
input clk,
8 input rst_n,
9 input CS_N,
10 input SCK,
11 input MOSI,
12 input [
7:
0] txd_data,
13 output reg MISO,
14 output reg [
7:
0] rxd_data,
15 output rxd_flag); //recieve done,please transmit data
16
17 //-------------------------capture the sck-----------------------------
18 reg sck_r0,sck_r1;
19 wire sck_n,sck_p;
20 always@(
posedge clk
or negedge rst_n)
21 begin
22 if(!
rst_n)
23 begin
24 sck_r0 <=
1'b1; //sck of the idle state is high
25 sck_r1 <=
1'b1;
26 end
27 else
28 begin
29 sck_r0 <=
SCK;
30 sck_r1 <=
sck_r0;
31 end
32 end
33
34 assign sck_n = (~sck_r0 & sck_r1)?
1'b1:1'b0;
//capture the sck negedge
35 assign sck_p = (~sck_r1 & sck_r0)?
1'b1:1'b0;
//capture the sck posedge
36
37 //-----------------------spi_slaver read data-------------------------------
38 reg rxd_flag_r;
39 reg [
2:
0] rxd_state;
40 always@(
posedge clk
or negedge rst_n)
41 begin
42 if(!
rst_n)
43 begin
44 rxd_data <=
1'b0;
45 rxd_flag_r <=
1'b0;
46 rxd_state <=
1'b0;
47 end
48 else if(sck_p && !
CS_N)
49 begin
50 case(rxd_state)
51 3'd0:begin
52 rxd_data[
7] <=
MOSI;
53 rxd_flag_r <=
1'b0; //reset rxd_flag
54 rxd_state <=
3'd1;
55 end
56 3'd1:begin
57 rxd_data[
6] <=
MOSI;
58 rxd_state <=
3'd2;
59 end
60 3'd2:begin
61 rxd_data[
5] <=
MOSI;
62 rxd_state <=
3'd3;
63 end
64 3'd3:begin
65 rxd_data[
4] <=
MOSI;
66 rxd_state <=
3'd4;
67 end
68 3'd4:begin
69 rxd_data[
3] <=
MOSI;
70 rxd_state <=
3'd5;
71 end
72 3'd5:begin
73 rxd_data[
2] <=
MOSI;
74 rxd_state <=
3'd6;
75 end
76 3'd6:begin
77 rxd_data[
1] <=
MOSI;
78 rxd_state <=
3'd7;
79 end
80 3'd7:begin
81 rxd_data[
0] <=
MOSI;
82 rxd_flag_r <=
1'b1; //set rxd_flag
83 rxd_state <=
3'd0;
84 end
85 default: ;
86 endcase
87 end
88 end
89
90
91 //--------------------capture spi_flag posedge--------------------------------
92 reg rxd_flag_r0,rxd_flag_r1;
93 always@(
posedge clk
or negedge rst_n)
94 begin
95 if(!
rst_n)
96 begin
97 rxd_flag_r0 <=
1'b0;
98 rxd_flag_r1 <=
1'b0;
99 end
100 else
101 begin
102 rxd_flag_r0 <=
rxd_flag_r;
103 rxd_flag_r1 <=
rxd_flag_r0;
104 end
105 end
106
107 assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)?
1'b1:1'b0;
108
109 //---------------------spi_slaver send data---------------------------
110 reg [
2:
0] txd_state;
111 always@(
posedge clk
or negedge rst_n)
112 begin
113 if(!
rst_n)
114 begin
115 txd_state <=
1'b0;
116 end
117 else if(sck_n && !
CS_N)
118 begin
119 case(txd_state)
120 3'd0:begin
121 MISO <= txd_data[
7];
122 txd_state <=
3'd1;
123 end
124 3'd1:begin
125 MISO <= txd_data[
6];
126 txd_state <=
3'd2;
127 end
128 3'd2:begin
129 MISO <= txd_data[
5];
130 txd_state <=
3'd3;
131 end
132 3'd3:begin
133 MISO <= txd_data[
4];
134 txd_state <=
3'd4;
135 end
136 3'd4:begin
137 MISO <= txd_data[
3];
138 txd_state <=
3'd5;
139 end
140 3'd5:begin
141 MISO <= txd_data[
2];
142 txd_state <=
3'd6;
143 end
144 3'd6:begin
145 MISO <= txd_data[
1];
146 txd_state <=
3'd7;
147 end
148 3'd7:begin
149 MISO <= txd_data[
0];
150 txd_state <=
3'd0;
151 end
152 default: ;
153 endcase
154 end
155 end
156
157 endmodule 六.Modelsim仿真图