前面已经提到过了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代码实现的更多相关文章

  1. Verilog代码规范I

    Verilog代码规范I "规范"这问题 "规范"这个富含专业气息的词汇(个人感觉),其实规范这种东西,就是大家都约定熟成的东西,一旦你不遵守这个东西,专业人士 ...

  2. HD,3G视频数据中行号的插入方法---Verilog代码实现

    HD,3G视频数据中行号的插入方法---Verilog代码实现 行号的生成: `timescale 1ns / 1ps //////////////////////////////////////// ...

  3. 串口接收端verilog代码分析

    串口接收端verilog代码分析 `timescale 1ns / 1ps ////////////////////////////////////////////////////////////// ...

  4. 串口发送端verilog代码分析

    串口发送端verilog代码分析 `timescale 1ns / 1ps ////////////////////////////////////////////////////////////// ...

  5. verilog 代码分析与仿真

    verilog 代码分析与仿真 注意:使用vivado 自带的仿真工具, reg和wire等信号需要赋予初始值 边沿检测 module signal_test( input wire cmos_pcl ...

  6. 总线读写---verilog代码

    总线读写---verilog代码 `timescale 1ns / 1ps ////////////////////////////////////////////////////////////// ...

  7. FIFO 的控制逻辑---verilog代码

    FIFO 的控制逻辑---verilog代码 //fifo的例化 wire fifo_full; wire fifo_empty; : ] fifo_dout; :]rd_data_count; :] ...

  8. 信号滤波模块verilog代码---UNLOCK,LOCK状态机方式

    信号滤波模块verilog代码 `timescale 1ns / 1ps /////////////////////////////////////////////////////////////// ...

  9. verilog代码 想法验证---与寄存器输出有关

    verilog代码 想法验证---与寄存器输出有关 1. module test_mind( input wire clk, input wire reset, input wire i, outpu ...

  10. 时钟分频方法---verilog代码

    时钟分频方法---verilog代码 本文以SDI播出部分的工程为例,来说明一种时钟分频的写法.SD-SDI工程中播出时钟tx_usrclk为148.5MHz,但tx_video_a_y_in端的数据 ...

随机推荐

  1. JZOJ 5352. 【NOIP2017提高A组模拟9.7】计数题

    题目 分析 考虑 \(kruskal\) 的过程 我们选边从高位开始 当前位为 \(0\) 的放一边,为 \(1\) 的放另一边 将 \(0\) 的建一棵字典树, \(1\) 的匹配 因为是异或,那就 ...

  2. Android:遍历视图

    <LinearLayout android:id="@+id/ques2_layout" android:layout_width="match_parent&qu ...

  3. CPU L1,L2,L3多级缓存的基本作用

    基本作用 加快CPU与主内存之间的数据交换. 区别 缓存类型 L1 L2 L3 位置 最靠近CPU核心 次之 再次之 容量 一般几十KB~几百KB 几百KB~几MB 几MB~几十MB 速度 几个时钟周 ...

  4. tinyriscv仿真环境

    环境要求:iverilog gtkwave 在sim目录新建makefile,内容如下. BIN=rv32ui-p-jal all: hexf comp vvp hexf: cp ../tests/i ...

  5. C# datatable group by分组

    DataTable dt = new DataTable(); dt.Columns.Add("A"); dt.Columns.Add("B"); dt.Col ...

  6. WPF使用WindowChrome自定义标题栏

    第一步:基本实现 添加Window的Style定义,并设置WindowChrome.WindowChrome属性: 设置WindowChrome标题栏: CaptionHeight--主要用于拖动有效 ...

  7. golang 中使用mysql报错:“ scannable dest type slice with >1 columns (4) in result”

    query := fmt.Sprintf("SELECT .... infos = make([]*struct, 0, 10) err = s.db.GetContext(ctx, &am ...

  8. Mac提升效率软件推荐

    1.HapiGo 高效启动器 能快速搜索文件.启动程序.打开网页.翻译.截图翻译等  相当于中文版的 Alfred 2.Rectangle 能快速对当前应用窗口进行分屏 3.iTerm2 一款比系统终 ...

  9. Web Socket 长连接

    服务 package com.kinth.basic.timetask.job.donghuan.socket; import java.io.IOException; import java.net ...

  10. CH582m串口透传程序

    目录 参考了沁恒官网22年1月更新的CH583EVT包中的UART1例程 功能:上位机通过串口1发送指令规定串口2和3的波特率,实现串口2和3之间的数据透传 担心串口3的接收中断会被串口2的发送中断打 ...