分别为驱动和tb tb_spi_master0_driver.v spi_master0_driver.v LMK04821的最大SCLK 20MHz 结合tb文件可以实现:
两个24bit 有间隔写入slave
10MHz SCLK
接下来的工作:
把tb文件中的虚拟时钟,改为使用clock ip做一个20MHz clk,那么SCLK 即10MHz
把tb文件中的给tx_data操作,改为使用fifo ip做fifo_buffer,要实现fifo数据的自动发给spi_master0_driver
构造顶层top文件,把spi_master0_driver和fifo_buffer包含
豆包生成的模块图
https://blog.csdn.net/qq_22168673/article/details/104925474
保存modelsim波形和数据,以及再次打开的方法
`timescale 1ns / 1ps
module tb_spi_master0_driver();
reg clk ;
reg rst_n ;
reg tx_en ;
reg tx_de ;
reg [23:0] tx_data ;
wire tx_done ;
wire spi_clk ;
wire spi_cs ;
wire spi_mosi ;
spi_master0_driver u1_spi_master0_driver(
.clk (clk ) ,
.rst_n (rst_n ) ,
.tx_en (tx_en ) ,
.tx_de (tx_de ) ,
.tx_data (tx_data ) ,
.tx_done (tx_done ) ,
.spi_clk (spi_clk ) ,
.spi_cs (spi_cs ) ,
.spi_mosi (spi_mosi )
);
initial clk = 1;
always #25 clk =~clk;
initial begin
rst_n = 0 ;
tx_en = 0 ;
tx_de = 0 ;
tx_data = 0 ;
//释放复位
#100;
rst_n = 1;
#50;
// --- 发送第一个字节:8'hA5 (10100101) ---
// 第一步:锁存数据
@(posedge clk);
tx_data = 24'hA5A5A5;
tx_de = 1; // 给一个周期的锁存脉冲
@(posedge clk);
tx_de = 0;
// 第二步:启动发送
@(posedge clk);
tx_en = 1; // 拉高使能
// 第三步:等待发送完成 (tx_done)
wait(tx_done == 1);
@(posedge clk);
tx_en = 0;
#60;
@(posedge clk);
tx_data = 24'hCDCDCD;
tx_de = 1;
@(posedge clk);
tx_de = 0;
@(posedge clk);
tx_en = 1;
wait(tx_done == 1);
@(posedge clk);
tx_en = 0;
#500;
$display("Simulation Finished!");
$stop;
end
endmodule
`timescale 1ns / 1ps
//master0 模式下 空闲电平为低电平
//spi_master0_driver要负责:
/*
1.数据锁存
2.在开始时拉低片选CS,结束时拉高片选CS
3.数据准备和数据的发收
*/
module spi_master0_driver(
input clk ,
input rst_n ,
input tx_en ,
input tx_de ,
input [23:0] tx_data ,
output reg tx_done ,
// input rx_en ,
// output rx_de ,
// output [7:0] rx_data ,
// output reg rx_done ,
output reg spi_clk ,
output reg spi_cs ,
// input spi_miso ,
output reg spi_mosi
);
reg [23:0] tx_latch ;
reg [23:0] tx_state ;
//数据锁存
always@(posedge clk)
if(!rst_n)
tx_latch <= 0;
else if(tx_de==1'b1)
tx_latch <= tx_data;
else
tx_latch <= tx_latch;
//开始发送 即spi_cs拉低
always@(posedge clk)
if(!rst_n)
spi_cs <= 1'b1;
else if(tx_en==1'b1)
spi_cs <= 1'b0;
else
spi_cs <= 1'b1;
//状态机 24bit数据连续写
always@(posedge clk)
if(!rst_n)
begin
spi_clk <= 0 ;
spi_mosi <= 0 ;
tx_done <= 0 ;
tx_state <= 0 ;
end
else if(tx_en==1'b1)
case(tx_state)
2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46: //制造spi_clk上升沿采样时刻
begin
spi_clk <= 1'b1 ;
tx_state <= tx_state + 1'b1 ;
end
0: //打一拍确保CS第一次拉低时的时序
begin
spi_mosi <= 1'b0 ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
1: //数据放到spi_mosi寄存器,等待clk上升沿总线mosi采样
begin
spi_mosi <= tx_latch[23] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
3: //数据放到spi_mosi寄存器,等待clk上升沿总线mosi采样
begin
spi_mosi <= tx_latch[22] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
5: //数据放到spi_mosi寄存器,等待clk上升沿总线mosi采样
begin
spi_mosi <= tx_latch[21] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
7: //数据放到spi_mosi寄存器,等待clk上升沿总线mosi采样
begin
spi_mosi <= tx_latch[20] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
9: //数据放到spi_mosi寄存器,等待clk上升沿总线mosi采样
begin
spi_mosi <= tx_latch[19] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
11: //数据放到spi_mosi寄存器,等待clk上升沿总线mosi采样
begin
spi_mosi <= tx_latch[18] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
13: //数据放到spi_mosi寄存器,等待clk上升沿总线mosi采样
begin
spi_mosi <= tx_latch[17] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
15: //数据放到spi_mosi寄存器,等待clk上升沿总线mosi采样
begin
spi_mosi <= tx_latch[16] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
17:
begin
spi_mosi <= tx_latch[15] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
19:
begin
spi_mosi <= tx_latch[14] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
21:
begin
spi_mosi <= tx_latch[13] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
23:
begin
spi_mosi <= tx_latch[12] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
25:
begin
spi_mosi <= tx_latch[11] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
27:
begin
spi_mosi <= tx_latch[10] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
29:
begin
spi_mosi <= tx_latch[9] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
31:
begin
spi_mosi <= tx_latch[8] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
33:
begin
spi_mosi <= tx_latch[7] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
35:
begin
spi_mosi <= tx_latch[6] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
37:
begin
spi_mosi <= tx_latch[5] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
39:
begin
spi_mosi <= tx_latch[4] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
41:
begin
spi_mosi <= tx_latch[3] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
43:
begin
spi_mosi <= tx_latch[2] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
45:
begin
spi_mosi <= tx_latch[1] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
47:
begin
spi_mosi <= tx_latch[0] ;
spi_clk <= 1'b0 ;
tx_state <= tx_state + 1'b1 ;
end
48: //3个字节发送完的标志tx_done
begin
spi_clk <= 1'b1 ;
tx_state <= tx_state + 1'b1 ;
tx_done <= 1'b1 ;
end
49: //发送完 回到master0默认的clk mosi 低电平
begin
spi_mosi <= 1'b0 ;
spi_clk <= 1'b0 ;
tx_state <= 0 ;
tx_done <= 1'b0 ;
end
default:
begin
spi_mosi <= 1'b0 ;
spi_clk <= 1'b0 ;
tx_state <= 0 ;
tx_done <= 1'b0 ;
end
endcase
else
begin
tx_state <= 0 ;
tx_done <= 0 ;
spi_clk <= 0 ;
spi_mosi <= 0 ;
end
endmodule

本文章使用limfx的vscode插件快速发布