前言
当你器件的引脚贼少的时候,需要主机和从机通信,spi就派上了用场,它可以一对多,但只是片选到的从机能和主机通信,其他的挂机。
spi:serial peripheral interface 串行外围接口
大致了解:

spi是个同步协议,数据在master和slaver间交换通过时钟sck,由于它是同步协议,时钟速率就可以各种变换。
sck:主机提供,从机不能操控,从器件由主机产生的时钟控制。数据只有在sck来了的上升沿或者下降沿才传输。
高级一点的spi芯片有配置寄存器,高级一点的工作有四种模式,采样相位和sck空闲电平可配置。
当然在这里我们主要实现简单的spi协议:sck是系统时钟的四分频,wr请求信号有效时,主机开始工作,数据位8bit,sck空闲时低电平,工作时第一个沿数据传输。只有一个从机,cs低电平片选。

看下结构:

接口定义:

编码实现:(版权所有,请勿用于商业用途,仅供学习使用)

1 //************************************************
2 // Filename : spi_ms_test1.v
3 // Author : Kingstacker
4 // Company : School
5 // Email : kingstacker_work@163.com
6 // Device : Altera cyclone4 ep4ce6f17c8
7 // Description : spi master module;data 8bit;sck is 4 div of the clk;
8 //************************************************
9 module spi_ms #(parameter WIDTH = 8)(
10 //input;
11 input wire clk,
12 input wire rst_n,
13 input wire wr, //send request;
14 input wire [WIDTH-1:0] master_din, //the data you want send;
15 input wire miso, //the data form slave;
16 //output;
17 output reg cs, //slave select;
18 output reg sck, //data exchange clock;
19 output reg mosi, //master out;
20 output reg [WIDTH-1:0] master_dout //the data you received;
21 );
22 localparam CLK_HZ = 50_000_000; //clk frequency;
23 localparam SCK_HZ = 12_500_000; //sck frequency;
24 localparam DIV_NUMBER = CLK_HZ / SCK_HZ;
25 localparam CNT_MAX = (DIV_NUMBER >>1) - 1'b1;
26 localparam DATA_CNT_MAX = 5'd31;
27 localparam MOSI_CNT_MAX = 3'd7;
28 localparam IDEL = 2'b00;
29 localparam SEND = 2'b01;
30 localparam FINISH = 2'b10;
31 reg cnt; //sck cnt;
32 reg sck_en; //enable sck;
33 reg data_cnt_en;
34 reg sck_reg1;
35 reg sck_reg2;
36 wire sck_p; //posedge sck;
37 wire sck_n; //negedge sck;
38 wire send_over;
39 reg [1:0] cstate;
40 reg [4:0] data_cnt; //cnt the send data;
41 reg [2:0] mosi_cnt;
42 reg [WIDTH-1:0] master_din_reg;
43 reg [WIDTH-1:0] master_dout_reg;
44 //produce sck;
45 always @(posedge clk or negedge rst_n) begin
46 if (~rst_n) begin
47 cnt <= 0;
48 sck <= 1'b0;
49 end //if
50 else begin
51 if (sck_en == 1'b1) begin
52 if (cnt == CNT_MAX) begin
53 cnt <= 0;
54 sck <= ~sck;
55 end
56 else begin
57 cnt <= cnt + 1'b1;
58 sck <= sck;
59 end
60 end
61 else begin
62 cnt <= 0;
63 sck <= 1'b0;
64 end
65 end //else
66 end //always
67 //produce sck_p and sck_n;
68 always @(posedge clk or negedge rst_n) begin
69 if (~rst_n) begin
70 sck_reg1 <= 1'b0;
71 sck_reg2 <= 1'b0;
72 end //if
73 else begin
74 sck_reg1 <= sck;
75 sck_reg2 <= sck_reg1;
76 end //else
77 end //always
78 assign sck_p = (sck_reg1 & (~sck_reg2)); //sck posedge;
79 assign sck_n = ((~sck_reg1) & sck_reg2); //sck negedge;
80 //fsm;hot code;
81 always @(posedge clk or negedge rst_n) begin
82 if (~rst_n) begin
83 cstate <= IDEL;
84 end
85 else begin
86 case (cstate)
87 IDEL: cstate <= (wr)? SEND : IDEL;
88 SEND: cstate <= (send_over) ? FINISH : SEND;
89 FINISH: cstate <= IDEL;
90 default: cstate <= IDEL;
91 endcase //case
92 end
93 end
94 always @(posedge clk or negedge rst_n) begin
95 if (~rst_n) begin
96 cs <= 1'b1;
97 data_cnt_en <= 1'b0;
98 sck_en <= 1'b0;
99 master_din_reg <= 0;
100 master_dout <= 0;
101 end
102 else begin
103 case (cstate)
104 IDEL: begin
105 data_cnt_en <= 1'b0;
106 master_din_reg <= (wr) ? master_din : master_din_reg; //load the data you want send to slaver;
107 end
108 SEND: begin
109 data_cnt_en <= 1'b1;
110 cs <= 1'b0;
111 sck_en <= 1'b1;
112 master_dout <= (send_over) ? master_dout_reg : master_dout; //master receiverd data;
113 end
114 FINISH: begin //send and load ok;
115 sck_en <= 1'b0;
116 cs <= 1'b1;
117 data_cnt_en <= 1'b0;
118 end
119 default: begin
120 cs <= 1'b1;
121 sck_en <= 1'b0;
122 data_cnt_en <= 1'b0;
123 end
124 endcase //case
125 end
126 end
127 always @(posedge clk or negedge rst_n) begin
128 if (~rst_n) begin
129 data_cnt <= 0;
130 end
131 else begin
132 data_cnt <= (data_cnt_en) ? (data_cnt + 1'b1) : 5'd0; //4 div * 8bit = 32 cnt;
133 end
134 end
135 assign send_over = (data_cnt == DATA_CNT_MAX) ? 1'b1 : 1'b0;
136 //rising edge miso;
137 always @(posedge clk or negedge rst_n) begin
138 if (~rst_n) begin
139 master_dout_reg <= 0;
140 end
141 else begin
142 master_dout_reg <= (sck_p) ? {master_dout_reg[6:0],miso} : master_dout_reg;
143 end
144 end
145 //mosi;
146 always @(posedge clk or negedge rst_n) begin
147 if (~rst_n) begin
148 mosi_cnt <= 0;
149 end
150 else begin
151 if (sck_n) begin
152 if (mosi_cnt == MOSI_CNT_MAX) begin
153 mosi_cnt <= 0;
154 end
155 else begin
156 mosi_cnt <= mosi_cnt + 1'b1;
157 end
158 end
159 else begin
160 mosi_cnt <= mosi_cnt;
161 end
162 end
163 end
164 always @(posedge clk or negedge rst_n) begin
165 if (~rst_n) begin
166 mosi <= 1'b0;
167 end
168 else begin
169 mosi <= (sck_n) ? master_din_reg[MOSI_CNT_MAX-mosi_cnt] : mosi;
170 end
171 end
172 endmodule

仿真:

综合资源使用:

Fmax:

以上。
全部0条评论
快来发表一下你的评论吧 !