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端的数据 ...
随机推荐
- PG数据库运维工具要覆盖哪些能力
目前的国产数据库中,很多产品都是以PG社区版代码作为研发起点的,还有一些产品是基于openGauss开源项目的.这些数据库的基础特性都和社区版的PG数据库类似,不过也做了一定的拓展.不过从使用与运维上 ...
- opc ua与opc da区别
opc ua与opc da区别_OPC,OPCDA,OPCUA傻傻搞不清楚,走过路过不妨看一看 转自:https://blog.csdn.net/weixin_39624774/article/det ...
- TCP协议之四次挥手
参考文章 这里 四次挥手过程 四次挥手的过程是全双工的,因此每个方向都必须要进行单独的关闭,这样原则是当一方完成数据发送后发送一个FIN信号给对方,对方收到FIN后就知道这个方向不会再有数据发送过来了 ...
- linux 替换csv的换行符(Linux 替换^M字符 方法)
sed -i 's/^M//g' a.csv 注意:这里的"^M"要使用"CTRL-V CTRL-M"生成,而不是直接键入"^M". 实验: ...
- 布尔类型:boolean
布尔类型 基本介绍 布尔类型也叫boolean类型,其数据只允许取值true和false,无null boolean类型占1个字节 boolean类型适于逻辑运算,一般用于程序流程控制: if条件控制 ...
- 浅谈spark
spark spark是一个开源分布式计算框架,在于让计算更加快速,通常使用资源调度器yarn和spark自带的资源调度器standalond进行调度,spark相对于Hadoop更加快速,基于它是内 ...
- docker 二进制安装
首先所属环境为内网并且服务器拥有的开发环境不确定,需要跑当前服务所需代码,所以优先选择使用docker docker 文档地址 https://docs.docker.com 在 install 中存 ...
- 【Frida】调试js代码
方法一attach启动 js代码动态注入app,app需要保持运行状态 # coding: utf-8 import sys import frida app_name = "猿人学APP& ...
- 【解决办法】安装Boost 提示'cl'不是内部或外部命令
VisualStudio 2022 Community 亲测可用. 1. 检查下载版本是否是最新版,我开始下的1.66.0会报错,后来换成1.79.0就没问题.官网https://www.boost. ...
- pg9.6使用索引
使用索引 索引是用于快速数据检索操作的结构.在数据库世界中,索引与表相关联并用于有效定位数据,而无需查询数据库表中的每一行.如果表没有索引,则需要全表扫描才能找到记录,这在磁盘 I/O 和 CPU 利 ...