关于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

posted @ 2020-07-20 00:10  桂七二  阅读(723)  评论(0编辑  收藏  举报