关于spi slave的代码及注释
module spi_slave
(
input clk_in,
input rst_n,
input sclk,
input mosi,
input cs,
output reg miso,
output [4:0] address_reg,
output rd_wr_mark,//1read 0wr
input [15:0] data_rd,
output reg [15:0] data_wr
);
reg cs_dly1;//延迟一个周期,用来检测上升沿和下降沿
reg sclk_dly1;//延迟一个周期,用来检测spi时钟上升沿和下降沿
reg data_valid;//数据有效
reg [5:0] bit_counter;//计算串行传入数据的比特位
reg [15:0] datain_shift;//写入数据的移位寄存器
reg [15:0] dataout_shift;//读出数据的移位寄存器
reg [15:0] info_reg;//用来存放信息,datain_shift。包括了地址和读写状态
reg [15:0] data_reg;//用来存放传进来的数据
reg [6:0] mode_num;//这个没用到
reg [7:0] address;//这个没用到
wire cs_rising;//检测cs上升沿的标志
wire cs_falling;//检测cs下降沿的标志
wire sclk_rising;//检测sclk上升沿的标志
wire sclk_falling;//检测sclk下降沿的标志
always @ (posedge clk_in or negedge rst_n)
begin
if(!rst_n)
cs_dly1 <= 1'd1;//初值
else
cs_dly1 <= cs;////延迟一个周期,用来检测上升沿和下降沿
end
always @ (posedge clk_in or negedge rst_n)
begin
if(!rst_n)
sclk_dly1 <= 0;//初值
else
sclk_dly1 <= sclk;//延迟一个周期,用来检测spi时钟上升沿和下降沿
end
//bit计数
always @ (posedge clk_in or negedge rst_n)
begin
if(!rst_n)
bit_counter <= 0;//初值
else if(cs)
bit_counter <= 0;//当cs为高说明还没开始传输,此时一直清零
else if(sclk_rising)
bit_counter <= bit_counter + 1;//当cs为低,传输正在进行,此时可以计数了
else
bit_counter <= bit_counter;//这个也可以删去,但是最好留着。其它状态下保持
end
always @ (posedge clk_in or negedge rst_n)
begin
if(!rst_n)
datain_shift <= 0;//数据清空
else if(cs)
datain_shift <= 0;//当cs为高时,数据寄存器清空
else if(sclk_rising)
datain_shift <= {datain_shift[14:0],mosi};//每当有sclk的上升沿,就进行一个移位
else
datain_shift <= datain_shift;//也可以删去。
end
//设置spi写
always @ (posedge clk_in or negedge rst_n)
begin
if(!rst_n) begin
info_reg <= 0;
data_wr <= 0;
end
else if(bit_counter == 15) begin
info_reg <= datain_shift;//前16位为地址和读写的信息,存入信息寄存器
data_wr <= data_wr;//此时写数据保存
end
else if(bit_counter == 31) begin
info_reg <= info_reg;//保持地址和读写信息不变
data_wr <= datain_shift;//后十六位写入数据寄存器中,用来给对应地址的寄存器写数据
end
end
//spi读
always @ (posedge clk_in or negedge rst_n)
begin
if(!rst_n)
dataout_shift <= 0;
else if((bit_counter == 16)&&rd_wr_mark)//当为读的时候,将要读的数据给到dataout_shift
dataout_shift <= data_rd;
else if(sclk_falling && rd_wr_mark)
dataout_shift <= {dataout_shift[14:0],1'b1};//当sclk下降沿且为读状态时,进行数据的移位
else
dataout_shift <= dataout_shift;
end
always @ (posedge clk_in or negedge rst_n)
begin
if(!rst_n)
miso <= 0;
else if(rd_wr_mark && sclk_rising)
miso <= dataout_shift[15];//当sclk上升沿且为读状态时,将dataout_shift的最高位数据输出
else
miso <= miso;//保持输出
end
assign cs_rising = cs && (~cs_dly1);//检测cs上升沿
assign cs_falling = cs_dly1 && (~cs);//检测cs下降沿
assign sclk_rising = sclk && (~sclk_dly1);//检测sclk时钟上升沿
assign sclk_falling = sclk_dly1 && (~sclk);//检测scl时钟下降沿
assign address_reg = info_reg[4:0];//info-reg的后五位用做地址
assign rd_wr_mark = info_reg[15];//最高位为读写状态标志位,其他位保留
endmodule