SPI主机Verilog代码实现
前面已经提到过了SPI,在SPI从机的设计中已经讲过SPI的基本原理,这里就不再赘述。对于SPI的主机可以参考百度百科或则笔者前面写的SPI从机介绍的相关知识。
下面是SPI_master的代码
SPI_master.v
1 //**************************************************************************
2 // *** file name : SPI_master.v
3 // *** version : 1.0
4 // *** Description : SPI master timing generation, supports four SPI modes
5 // *** Blogs :
6 // *** Author : Galois_V
7 // *** Date : 2022.02.14
8 // *** Changes : Initial
9 //**************************************************************************
10 `timescale 1ns/1ps
11 module SPI_master
12 #(
13 parameter TX_WIDTH = 16 ,
14 parameter RX_WIDTH = 16
15 )
16 (
17 input i_sys_clk ,
18 input i_sys_rstn ,
19 output reg o_spi_cs ,
20 output reg o_spi_sclk ,
21 output o_spi_mosi ,
22 input i_spi_miso ,
23 input i_spi_cpol ,
24 input i_spi_cpha ,
25 input i_spi_start ,
26 output o_spi_state ,
27 input [15:0] i_spi_rate ,
28 input [1:0] i_spi_ctrl ,
29 input i_spi_tx_valid ,
30 input [TX_WIDTH-1:0] i_spi_tx_data ,
31 output o_spi_tx_req ,
32 output o_spi_rx_valid ,
33 output [RX_WIDTH-1:0] o_spi_rx_data
34 );
35 wire w_sclk_edge_over ;
36 wire w_spi_read_en ;
37 wire w_spi_write_en ;
38 wire w_spi_sclk_reverse_en;
39 wire w_spi_rx_valid ;
40 reg r_spi_over ;
41 reg r_spi_state_en ;
42 reg r_spi_start ;
43 reg [15:0] r_sclk_edge_cnt ;
44 reg r_spi_get_state ;
45 reg r_spi_over_dly ;
46 reg [15:0] r_spi_sclk_cnt ;
47 reg [3:0] r_spi_sclk_bit_cnt;
48 reg [TX_WIDTH-1:0] r_spi_tx_data ;
49 reg [2:0] r_spi_rx_en ;
50 reg [RX_WIDTH-1:0] r_spi_rx_data ;
51 reg [2:0] r_spi_miso ;
52 reg [3:0] r_spi_rx_valid ;
53 localparam EDGE_CNT = TX_WIDTH * 2 - 1;
54 assign w_spi_read_en = i_spi_ctrl[0];
55 assign w_spi_write_en = i_spi_ctrl[1];
56 always@(posedge i_sys_clk)
57 begin
58 if(~i_sys_rstn)
59 begin
60 r_spi_start <= 'd0;
61 end
62 else
63 begin
64 r_spi_start <= i_spi_start;
65 end
66 end
67 always@(posedge i_sys_clk)
68 begin
69 if(~i_sys_rstn)
70 begin
71 r_spi_state_en <= 'd0;
72 end
73 else if(r_spi_over)
74 begin
75 r_spi_state_en <= 'd0;
76 end
77 else if(r_spi_start)
78 begin
79 r_spi_state_en <= 1'b1;
80 end
81 end
82 assign o_spi_state = ~r_spi_state_en;
83 /******************************************************************************\
84 sclk edge count
85 \******************************************************************************/
86 always@(posedge i_sys_clk)
87 begin
88 if(~i_sys_rstn)
89 begin
90 r_sclk_edge_cnt <= 'd0;
91 end
92 else if(r_spi_start)
93 begin
94 r_sclk_edge_cnt <= 'd0
95 end
96 else if(r_spi_over)
97 begin
98 r_sclk_edge_cnt <= r_sclk_edge_cnt;
99 end
100 else if(w_sclk_edge_over)
101 begin
102 r_sclk_edge_cnt <= r_sclk_edge_cnt + 1'b1;
103 end
104 end
105 always@(posedge i_sys_clk)
106 begin
107 if(~i_sys_rstn)
108 begin
109 r_spi_over <= 'd0;
110 end
111 else if (w_sclk_edge_over & (r_sclk_edge_cnt == EDGE_CNT))
112 begin
113 r_spi_over <= 1'b1;
114 end
115 else
116 begin
117 r_spi_over <= 'd0;
118 end
119 end
120 always@(posedge i_sys_clk)
121 begin
122 if(~i_sys_rstn)
123 begin
124 r_spi_get_state <= 'd0;
125 end
126 else if(r_spi_get_state & i_spi_tx_valid | r_spi_over)
127 begin
128 r_spi_get_state <= 'd0;
129 end
130 else if(w_spi_write_en & r_spi_start)
131 begin
132 r_spi_get_state <= 1'b1;
133 end
134 end
135 assign o_spi_tx_req = (~r_spi_over & r_spi_get_state & i_spi_valid) & w_spi_write_en;
136 /******************************************************************************\
137 Generate SPI CS
138 \******************************************************************************/
139 always@(posedge i_sys_clk)
140 begin
141 if(~i_sys_rstn)
142 begin
143 r_spi_over_dly <= 'd0;
144 end
145 else
146 begin
147 r_spi_over_dly <= r_spi_over;
148 end
149 end
150 always@(posedge i_sys_clk)
151 begin
152 if(~i_sys_rstn)
153 begin
154 o_spi_cs <= 'd1;
155 end
156 else if(r_spi_over_dly)
157 begin
158 o_spi_cs <= 1'b1;
159 end
160 else if(i_spi_start)
161 begin
162 o_spi_cs <= 'd0;
163 end
164 end
165 /******************************************************************************\
166 Generatte SPI sclk
167 \******************************************************************************/
168 always@(posedge i_sys_clk)
169 begin
170 if(~i_sys_rstn)
171 begin
172 r_spi_sclk_cnt <= 'd0;
173 end
174 else if(r_spi_start | w_spi_sclk_reverse_en)
175 begin
176 r_spi_sclk_cnt <= 'd0;
177 end
178 else
179 begin
180 r_spi_sclk_cnt <= r_spi_sclk_cnt + 1'b1;
181 end
182 end
183 assign w_spi_sclk_reverse_en = (r_spi_sclk_cnt == i_spi_rate);
184 always@(posedge i_sys_clk)
185 begin
186 if(~i_sys_rstn)
187 begin
188 r_spi_sclk_bit_cnt <= 'd0;
189 end
190 else if(r_spi_start | r_spi_over)
191 begin
192 r_spi_sclk_bit_cnt <= 'd0;
193 end
194 else if(w_spi_sclk_reverse_en)
195 begin
196 r_spi_sclk_bit_cnt <= r_spi_sclk_bit_cnt + 1'b1;
197 end
198 end
199 assign w_sclk_edge_over = w_spi_sclk_reverse_en & r_spi_state_en;
200 /******************************************************************************\
201 SPI MODE
202 \******************************************************************************/
203 always@(posedge i_sys_clk)
204 begin
205 if(~i_sys_rstn)
206 begin
207 o_spi_sclk <= 'd0;
208 end
209 else if(r_spi_start)
210 begin
211 o_spi_sclk <= i_spi_cpol ^ i_spi_cpha;
212 end
213 else if(~r_spi_state_en | ((r_sclk_edge_cnt== EDGE_CNT) & w_sclk_edge_over))
214 begin
215 o_spi_sclk <= i_spi_cpol;
216 end
217 else if(w_spi_sclk_reverse_en)
218 begin
219 o_spi_sclk <= ~o_spi_sclk;
220 end
221 end
222 /******************************************************************************\
223 Generate SPI MOSI
224 \******************************************************************************/
225 always@(posedge i_sys_clk)
226 begin
227 if(~i_sys_rstn)
228 begin
229 r_spi_tx_data <= 'd0;
230 end
231 else if(o_spi_tx_req)
232 begin
233 r_spi_tx_data <= i_spi_tx_data;
234 end
235 else if(r_spi_state_en & r_spi_sclk_bit_cnt[0] & w_spi_sclk_reverse_en)
236 begin
237 r_spi_tx_data <= r_spi_tx_data << 1;
238 end
239 end
240 assign o_spi_mosi = r_spi_tx_data[TX_WIDTH-1];
241 /******************************************************************************\
242 Generate SPI MISO
243 \******************************************************************************/
244 always@(posedge i_sys_clk)
245 begin
246 if(~i_sys_rstn)
247 begin
248 r_spi_miso <= 'd0;
249 end
250 else
251 begin
252 r_spi_miso <= {r_spi_miso[1:0],i_spi_miso};
253 end
254 end
255 always@(posedge i_sys_clk)
256 begin
257 if(~i_sys_rstn)
258 begin
259 r_spi_rx_en <= 'd0;
260 end
261 else
262 begin
263 r_spi_rx_en <= {r_spi_rx_en[1:0],(r_spi_state_en & (~r_spi_sclk_bit_cnt[0]) & w_spi_sclk_reverse_en)};
264 end
265 end
266 always@(posedge i_sys_clk)
267 begin
268 if(~i_sys_rstn)
269 begin
270 r_spi_rx_data <= 'd0;
271 end
272 else if(r_spi_rx_en[2])
273 begin
274 r_spi_rx_data <= {r_spi_rx_data[RX_WIDTH-2:0],r_spi_miso[2]};
275 end
276 end
277 assign o_spi_rx_data = r_spi_rx_data;
278 /******************************************************************************\
279 SPI valid delay 4clock ensure data stability
280 \******************************************************************************/
281 always@(posedge i_sys_clk)
282 begin
283 if(~i_sys_rstn)
284 begin
285 r_spi_rx_valid <= 'd0;
286 end
287 else
288 begin
289 r_spi_rx_valid <= {r_spi_rx_valid[2:0],w_spi_rx_valid};
290 end
291 end
292 assign w_spi_rx_valid = w_sclk_edge_over & (r_sclk_edge_cnt == EDGE_CNT) & w_spi_read_en;
293 assign o_spi_rx_valid = r_spi_rx_valid[3];
294 endmodule
这里提下,笔者写代码比较喜欢写通用点的代码,这里速率是可以控制,不过最大只能是系统时钟的1/4,SPI的模式也支持4种模式,start信号在这里是占一个系统时钟的脉冲信号。至于代码是否没问题,笔者不能保证,笔者在仿真测试中还未曾发现有太大问题,也仅供参考。这里可以用AXI4_lite总线来对该模块代码进行按需控制,可以把例化的参数CLK_EDGE也用总线配置。
SPI主机Verilog代码实现的更多相关文章
- Verilog代码规范I
Verilog代码规范I "规范"这问题 "规范"这个富含专业气息的词汇(个人感觉),其实规范这种东西,就是大家都约定熟成的东西,一旦你不遵守这个东西,专业人士 ...
- HD,3G视频数据中行号的插入方法---Verilog代码实现
HD,3G视频数据中行号的插入方法---Verilog代码实现 行号的生成: `timescale 1ns / 1ps //////////////////////////////////////// ...
- 串口接收端verilog代码分析
串口接收端verilog代码分析 `timescale 1ns / 1ps ////////////////////////////////////////////////////////////// ...
- 串口发送端verilog代码分析
串口发送端verilog代码分析 `timescale 1ns / 1ps ////////////////////////////////////////////////////////////// ...
- verilog 代码分析与仿真
verilog 代码分析与仿真 注意:使用vivado 自带的仿真工具, reg和wire等信号需要赋予初始值 边沿检测 module signal_test( input wire cmos_pcl ...
- 总线读写---verilog代码
总线读写---verilog代码 `timescale 1ns / 1ps ////////////////////////////////////////////////////////////// ...
- FIFO 的控制逻辑---verilog代码
FIFO 的控制逻辑---verilog代码 //fifo的例化 wire fifo_full; wire fifo_empty; : ] fifo_dout; :]rd_data_count; :] ...
- 信号滤波模块verilog代码---UNLOCK,LOCK状态机方式
信号滤波模块verilog代码 `timescale 1ns / 1ps /////////////////////////////////////////////////////////////// ...
- verilog代码 想法验证---与寄存器输出有关
verilog代码 想法验证---与寄存器输出有关 1. module test_mind( input wire clk, input wire reset, input wire i, outpu ...
- 时钟分频方法---verilog代码
时钟分频方法---verilog代码 本文以SDI播出部分的工程为例,来说明一种时钟分频的写法.SD-SDI工程中播出时钟tx_usrclk为148.5MHz,但tx_video_a_y_in端的数据 ...
随机推荐
- 【SDOI2015】排序
#include<cstdio> #include<iostream> using namespace std; typedef long long LL; const int ...
- Jquery 点击弹窗,将弹窗内容赋值到各个项demo
<div class="qb"> <div class="box"> <div class="qtt f_16 fbd& ...
- Integer使用==比较的问题
Integer使用==比较的问题 new一个对象 public Integer(int value) { this.value = value; } 自动装箱 public static Intege ...
- 开发者进阶必备的9个Tips & Tricks!
优秀的开发人员市场前景是十分广阔的,但想找到一份理想的工作,仅有代码知识是不够的.优秀的工程师应该是一个终身学习者.问题的创造性解决者,着迷于整个软件世界.要成为一名优秀的开发者,应该具备哪些品质并做 ...
- OpenAI Chat completion API 入门指南
Chat completion API 入门指南 ChatGPT 由 OpenAI 最先进的语言模型 gpt-3.5-turbo 提供支持. 使用 OpenAI API,您可以使用 GPT-3.5-t ...
- Anaconda 使用教程
Anaconda介绍 Anaconda指的是一个开源的Python发行版本,其包含了conda.Python等180多个科学包及其依赖项. 因为包含了大量的科学包,Anaconda 的下载文件比较大( ...
- 13.OpenFeign测试远程调用
以会员服务调用优惠券服务为例 引入依赖 在之前创建微服务模块时已经引入了这个依赖,就不需要重复引入了 添加要被member微服务调用的coupon微服务的coupon的方法 在member微服务添加一 ...
- ubutu22.04开启ssh配置
1.查看ubuntu版本信息 lsb_release -a 2.更新系统 sudo apt update && sudo apt upgrade -y 如果出现Ign:1 ...InR ...
- cisco ios 密码恢复
如果没有break键,使用仿真软件模仿一个break 密码恢复请执行以下步骤 1. 关闭或断开路由器电源 2.开启路由器.在通电后的前30秒内按下break键(或通过仿真程序发送一个间断序列),来中断 ...
- css小技巧【让背景最少是屏幕高度】【让三个字和四个字左右对齐】
怎么让背景最少是屏幕高度 min-height: 100vh; 怎么让三个字和四个字左右对齐 text-align-last: justify;