///tx 极性0 (sclk信号线空闲时为低电平)
/// 相位0 (在sclk信号线第一个跳变沿进行采样)
`timescale 1ns / 1ps
//两个从机 8'd01 8'd02
module top(
input clk ,
input rst_n,
input [7:0] addr ,
input valid,
input [15:0]data ,
output reg mosi ,
output reg [1:0]cs , //相当于是有2个从机 引脚约束的话是有2个
output reg sclk
);
parameter CLK_DIV=100;
parameter IDEL = 2'b01;
parameter BUSY = 2'b10;
parameter cong1= 2'b01;
parameter cong2= 2'b10;
reg [1:0] state;
reg fin ;
reg d ;
reg [10:0]cunt1;
reg [9:0] cunt ;
reg [4:0] cunt_b;
//将valid信号延长
always @(posedge clk or negedge rst_n) begin
if(state==IDEL)begin
if(valid==1)
d<=1;
else
d<=d;
end
else
d<=0;
end
always @(posedge clk or negedge rst_n) begin
if(state==IDEL)begin
if(d==1)
cunt1<=cunt1+1;
else
cunt1<=cunt1;
end
else
cunt1<=0;
end
//状态的转移
always @(posedge clk ) begin
if(!rst_n)
state<=IDEL;
else if(state==IDEL&&cunt1==200)
state<=BUSY;
else if(state==BUSY&&fin==1)
state<=IDEL;
else
state<=state;
end
//产生一个计数器对时钟周期计数
always @(posedge clk ) begin
if(state==IDEL)
cunt<=0;
else begin
if(cunt==CLK_DIV-1)
cunt<=0;
else
cunt<=cunt+1;
end
end
//对sclk计数
always @(posedge clk ) begin
if(state==IDEL)
cunt_b<=0;
else begin
if(cunt==CLK_DIV-1)
cunt_b<=cunt_b+1;
else
cunt_b<=cunt_b;
end
end
//sclk的产生
always @(posedge clk ) begin
if(state==IDEL)
sclk<=0;
else if(fin==1)
sclk<=0;
else begin
if(cunt<CLK_DIV/2)
sclk<=1;
else
sclk<=0;
end
end
//fin产生
always @(posedge clk) begin
if(cunt==CLK_DIV-1&&cunt_b==15)
fin<=1;
else
fin<=0;
end
//cs的产生
always @(posedge clk ) begin
if(addr==8'd01)
cs<=2'b01;
else if(addr==8'd02) //(state==BUSY||d==1)这个条件也可以不要 相当于只要选中一直拉高
cs<=2'b10;
else
cs<=0;
end
//对mosi的输出
always @(posedge clk ) begin
if(state==IDEL)
mosi<=0;
else case (cunt_b)
0:mosi <=data[0] ;
1:mosi <=data[1] ;
2:mosi <=data[2] ;
3:mosi <=data[3] ;
4:mosi <=data[4] ;
5:mosi <=data[5] ;
6:mosi <=data[6] ;
7:mosi <=data[7] ;
8:mosi <=data[8] ;
9:mosi <=data[9] ;
10:mosi<=data[10] ;
11:mosi<=data[11] ;
12:mosi<=data[12] ;
13:mosi<=data[13] ;
14:mosi<=data[14] ;
15:mosi<=data[15] ;
default:mosi<=0;
endcase
end
endmodule
///rx
`timescale 1ns / 1ps
module rx_spi(
input clk ,
input rst_n,
input mosi ,
input sclk ,
input cs , //一位宽 例化的时候比如这个是从机连线就是cs[1]
output reg [15:0]data ,
output valid
);
reg [1:0] sclk_t;
reg [7:0] cunt_b;
//对sclk_t缓存
always @(posedge clk or negedge rst_n) begin
if(cs==1)
sclk_t<={sclk_t[0],sclk};
else
sclk_t<=2'b00;
end
//对2'b10 这个下降沿计数
always @(posedge clk ) begin
if(!rst_n)
cunt_b<=0;
else if(cs==1&&sclk_t==2'b10)
cunt_b<=cunt_b+1;
else
cunt_b<=cunt_b;
end
//valid的产生
assign valid=(cs==1&&cunt_b==15);
//data的补充
always @(posedge clk ) begin
if(cs==1) begin
if(sclk_t==2'b10)
case (cunt_b)
0:data[0]<=mosi;
1:data[1]<=mosi;
2:data[2]<=mosi;
3:data[3]<=mosi;
4:data[4]<=mosi;
5:data[5]<=mosi;
6:data[6]<=mosi;
7:data[7]<=mosi;
8:data[8]<=mosi;
9:data[9]<=mosi;
10:data[10]<=mosi;
11:data[11]<=mosi;
12:data[12]<=mosi;
13:data[13]<=mosi;
14:data[14]<=mosi;
15:data[15]<=mosi;
default: data=data;
endcase
else
data<=data;
end
else
data<=0;
end
endmodule
//tb仿真激励文件
`timescale 1ns / 1ps
module tb(
);
reg clk ;///
reg rst_n;///
reg [7:0] addr ;///
reg valid;///
reg [15:0] data ;///
wire mosi ;
wire [1:0] cs ;
wire sclk ;
initial begin
clk=1 ;
rst_n<=0 ;
#100
rst_n<=1 ;
#100
addr<=8'd02;
valid<=1;
data<=16'h1234;
#20
valid<=0;
end
always #10 clk=~clk ;
top u_top(
/*input */.clk (clk ),
/*input */.rst_n(rst_n),
/*input [7:0] */.addr (addr ),
/*input */.valid(valid),
/*input [15:0]*/.data (data ),
/*output reg */.mosi (mosi ),
/*output reg [1:0]*/.cs (cs ),
/*output reg */.sclk (sclk )
);
rx_spi u_rx1(
/*input */.clk (clk ),
/*input */.rst_n(rst_n),
/*input */.mosi (mosi ),
/*input */.sclk (sclk ),
/*input */.cs (cs[1]), //一位宽 例化的时候比如这个是从机连线就是cs[1]
/*output [7:0]*/.data ( ),
/*output */.valid( )
);
endmodule
仿真波形图
采样跳变沿笔记