///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) beginif(state==IDEL)beginif(valid==1)d<=1;elsed<=d;endelsed<=0;
end
always @(posedge clk or negedge rst_n) beginif(state==IDEL)beginif(d==1)cunt1<=cunt1+1;elsecunt1<=cunt1;endelsecunt1<=0;
end
//状态的转移
always @(posedge clk ) beginif(!rst_n)state<=IDEL;else if(state==IDEL&&cunt1==200)state<=BUSY;else if(state==BUSY&&fin==1)state<=IDEL;elsestate<=state;
end
//产生一个计数器对时钟周期计数
always @(posedge clk ) beginif(state==IDEL)cunt<=0;else beginif(cunt==CLK_DIV-1)cunt<=0;elsecunt<=cunt+1;end
end
//对sclk计数
always @(posedge clk ) beginif(state==IDEL)cunt_b<=0;else beginif(cunt==CLK_DIV-1)cunt_b<=cunt_b+1;elsecunt_b<=cunt_b;end
end
//sclk的产生
always @(posedge clk ) beginif(state==IDEL)sclk<=0;else if(fin==1)sclk<=0;else beginif(cunt<CLK_DIV/2)sclk<=1;elsesclk<=0;end
end//fin产生
always @(posedge clk) beginif(cunt==CLK_DIV-1&&cunt_b==15)fin<=1;elsefin<=0;
end
//cs的产生
always @(posedge clk ) beginif(addr==8'd01)cs<=2'b01;else if(addr==8'd02) //(state==BUSY||d==1)这个条件也可以不要 相当于只要选中一直拉高cs<=2'b10;elsecs<=0;
end
//对mosi的输出
always @(posedge clk ) beginif(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) beginif(cs==1)sclk_t<={sclk_t[0],sclk};elsesclk_t<=2'b00;
end
//对2'b10 这个下降沿计数
always @(posedge clk ) beginif(!rst_n)cunt_b<=0;else if(cs==1&&sclk_t==2'b10)cunt_b<=cunt_b+1;elsecunt_b<=cunt_b;
end
//valid的产生
assign valid=(cs==1&&cunt_b==15);
//data的补充
always @(posedge clk ) beginif(cs==1) beginif(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;endcaseelse data<=data;endelsedata<=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 beginclk=1 ;rst_n<=0 ;#100rst_n<=1 ;#100addr<=8'd02;valid<=1;data<=16'h1234;#20valid<=0;
endalways #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
仿真波形图
采样跳变沿笔记