SPI Slave端口及测试代码

来源:互联网 发布:java转游戏开发 编辑:程序博客网 时间:2024/06/18 18:09

//SPI_SLAVE.v
//SPI从端接口
//SPI的数据线上,高位数据先发
//2010-12-20
/*
SPI从模块接受端
在iCS_N为低电平时,每一个iSCLK信号上升沿到来时,从iMOSI端口接受一位数据
当接收一个字节的数据后,oDATA端口输出数据,同时oEN置高电平,表示当前oDATA端口的数据为有效数据
*/
module SPI_SLAVE(
    iCLK,    //全局时钟
    iRST_N,    //全局复位
    iSCLK,    //SPI时钟信号
    iCS_N,    //片选信号
    iMOSI,    //SPI数据输入端口
    oDATA,    //输出数据
    oEN        //输出有效信号
);

input iCLK;
input iRST_N;
input iSCLK;
input iCS_N;
input iMOSI;
output [7:0] oDATA;
output oEN;

reg [7:0] oDATA;
reg [3:0]rOEN;
reg [7:0] rData;
reg [2:0] rCnt;

reg sclk_bak;
always@(posedge iCLK)begin
    sclk_bak <= iSCLK;
end
wire wSclkRaise=((sclk_bak==1'b0)&&(iSCLK==1'b1));    //iSCLK上升沿

always@(posedge iCLK or negedge iRST_N)begin
    if(!iRST_N)begin
        rData <= 8'd0;
        rCnt <= 3'd0;
    end
    else if(!iCS_N) begin
        if(wSclkRaise)begin
            rData <= {rData[6:0],iMOSI};
            rCnt <= rCnt + 3'd1;
        end
    end
    else begin
        rData <= rData;
        rCnt <= 3'd0;
    end
end

reg [2:0] rCnt_bak;
always@(posedge iCLK)begin
    rCnt_bak <= rCnt;
end
wire w8Bits=((rCnt==3'd0) && (rCnt_bak==3'd7));    //接收8字节标记

always@(posedge iCLK or negedge iRST_N)begin
    if(!iRST_N)begin
        oDATA <= 8'd0;
    end
    if(!iCS_N)begin
        if(w8Bits)begin
            oDATA <= rData;
        end
        else begin
            oDATA <= oDATA;
        end
    end
    else begin
        if(oEN)begin
            oDATA <= oDATA;
        end
        else begin
            oDATA <= 8'd0;
        end
    end
end

always@(posedge iCLK or negedge iRST_N)begin
    if(!iRST_N)begin
        rOEN<=4'd0;
    end
    if(!iCS_N)begin
        if(w8Bits)begin
            rOEN<=4'd1;
        end
        else begin
            rOEN<={rOEN[2:0],1'b0};
        end
    end
    else begin
        rOEN<={rOEN[2:0],1'b0};
    end
end

assign oEN=|rOEN;

endmodule

//tb1.v
//SPI_SLAVE测试程序
//2010-12-20
module tb1();
reg clk;
reg rst_n;
reg sclk;
reg cs_n;

initial begin
    clk=0;
    forever begin
        #10;
        clk=~clk;
    end
end

initial begin
    rst_n=0;
    repeat(4)@(negedge clk);
    rst_n=1;
end

reg [7:0] data,data_bak;
reg si_data;
initial begin
    cs_n=1;
    sclk=0;
    si_data=0;
    data=0;
    repeat(4)@(negedge clk);
    cs_n=0;
    forever begin
        data=$random;
        data_bak=data;
        repeat(8)begin
            si_data=data[7];
            data={data[6:0],1'b0};
            sclk=1;
            repeat(2)@(negedge clk);
            sclk=0;
            repeat(2)@(negedge clk);
        end
    end
end

wire [7:0] wdata;
wire wen;
SPI_SLAVE SPI_SLAVE_0(
    .iCLK(clk),    //全局时钟
    .iRST_N(rst_n),    //全局复位
    .iSCLK(sclk),    //SPI时钟信号
    .iCS_N(cs_n),    //片选信号
    .iMOSI(si_data),    //SPI数据输入端口
    .oDATA(wdata),    //输出数据
    .oEN(wen)        //输出有效信号
);

initial begin
    repeat(100)begin
        @(posedge wen);
        if(wdata == data_bak)begin
            ;
        end
        else begin
            $display("wdata=%X",wdata);
            $display("data_bak=%X",data_bak);
            $display("Faild...");
            $stop;
        end
    end
    $display("Success...");
    $stop;
end

endmodule