FLASH使用笔记~M25P64

        1.通过阅读产品手册可知其是一枚工作在50mhz(最高)下的flash芯片,编写控制器的过程中需要输出分频时钟来确保数据的稳定。(FPGA的时钟频率也只有50MHZ,低一点好控制一些)

        2.其操作命令如下:

        需要进行BE,SE,PP指令的时候,需要先发送写指令,并等待一段时间,之后再发送需要使用的指令+地址+使用数据,原文:

        如果需要发送指令+地址+数据,数据可以使用RAM或FIFO来存储,提前写入。

代码:

        擦除:SE = 8'hd8

        首先需要先拉低CS_N,然后发送WR = 8'h06命令,发送完成后等待100ns(至少),发送SE命令+作用的地址,SE的擦除对应的是bank擦除,范围非常大。

        细节:

        虽然M25P64支持50mhz,但是这款FPGA芯片(SP6)仅有50MHZ,为此进行了分频至12.5MHZ处理。

        一开始:Slave_data_out <= WR_DATA_COMMAND[7],在div_cnt == 'd3的时候将WR_DATA_COMMAND向左移位的操作,对于SPI而言,上升沿锁存数据,下降沿写入数据,所以每一位数据在div_cnt == 'd1(上升沿)的适合锁存,我们在div_cnt == 'd3的适合改变是合理的。

    always @(*) begin
        if(STATE == STATE_WR) begin
            Slave_data_out <= WR_DATA_COMMAND[7];
        end else if(STATE == STATE_SE) begin
            Slave_data_out <= WR_DATA_ADDR[31];
        end else begin
            Slave_data_out <= 'd0;
        end
    end

 完整代码:

module Flash_SE #(
    // parameter tSE   = 1_500_000_000,//3s
    parameter tSHWL = 16             //100ns
) (
    input   wire            Sys_clk,
    input   wire            Rst_n  ,
    //spi       
    input   wire            SE_flag,
    // input   wire            Slave_data_in ,
    input   wire [23:0]     SE_ADDR       ,
    output  reg             Slave_data_out,
    output  reg             Slave_CS_N    ,
    output  reg             Slave_CLK     
);
    //command
    localparam COMMAND_WREN  = 8'b0000_0110;
    localparam COMMAND_SE    = 8'hD8       ;
    //state
    localparam STATE_IDLE    = 4'b0001;
    localparam STATE_WR      = 4'b0010;
    localparam STATE_PROTECT = 4'b0100;
    localparam STATE_SE      = 4'b1000;
    //cnt
            reg  [1:0]  div_cnt  ;
            reg  [7:0]  bit_cnt  ;
            reg  [3:0]  STATE    ;
            reg  [3:0]  tSHWL_cnt;
    //WR_DATA
            reg  [7:0]  WR_DATA_COMMAND;
            reg  [31:0] WR_DATA_ADDR   ;
    //Slave_CS_N
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Slave_CS_N <= 1'b1;
        end else if(STATE == STATE_IDLE && SE_flag == 1'b1) begin
            Slave_CS_N <= 1'b0;
        end else if(STATE == STATE_WR && bit_cnt ==  'd8 && div_cnt == 'd3) begin
            Slave_CS_N <= 1'b1;
        end else if(STATE == STATE_PROTECT && tSHWL_cnt == tSHWL -1'b1) begin
            Slave_CS_N <= 1'b0;
        end else if(STATE == STATE_SE && bit_cnt == 'd32 && div_cnt == 'd3) begin
            Slave_CS_N <= 1'b1;
        end else begin
            Slave_CS_N <= Slave_CS_N;
        end
    end
    //div_cnt
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            div_cnt <= 'd0;
        end else if(STATE == STATE_WR || STATE == STATE_SE) begin
            if(div_cnt == 'd3) begin
                div_cnt <= 'd0;
            end else begin
                div_cnt <= div_cnt + 1'b1;
            end
        end else begin
            div_cnt <= 'd0;
        end
    end
    //Slave_CLK
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Slave_CLK <= 'd0;
        end else if(STATE == STATE_WR && bit_cnt <= 'd7) begin
            if(bit_cnt == 'd7 && div_cnt == 'd3) begin
                Slave_CLK <= 'd0;
            end else if(div_cnt == 'd1 || div_cnt == 'd3) begin
                Slave_CLK <= ~Slave_CLK;
            end else begin
                Slave_CLK <= Slave_CLK;
            end
        end else if(STATE == STATE_SE && bit_cnt <= 'd31) begin
            if(bit_cnt == 'd31 && div_cnt == 'd3) begin
                Slave_CLK <= 'd0;
            end else if(div_cnt == 'd1 || div_cnt == 'd3) begin
                Slave_CLK <= ~Slave_CLK;
            end else begin
                Slave_CLK <= Slave_CLK;
            end
        end else begin
            Slave_CLK <= 'd0;
        end
    end
    //tSHWL_cnt
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            tSHWL_cnt <= 'd0;
        end else if(tSHWL_cnt == tSHWL -1'b1) begin
            tSHWL_cnt <= 'd0;
        end else if(STATE == STATE_PROTECT) begin
            tSHWL_cnt <= tSHWL_cnt + 1'b1;
        end else begin
            tSHWL_cnt <= tSHWL_cnt;
        end
    end
    //bit_cnt
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            bit_cnt <= 'd0;
        end else if(STATE == STATE_WR && bit_cnt == 'd8  && div_cnt == 'd3) begin
            bit_cnt <= 'd0;
        end else if(STATE == STATE_SE && bit_cnt == 'd32 && div_cnt == 'd3) begin
            bit_cnt <= 'd0;
        end else if(div_cnt == 'd3) begin
            bit_cnt <= bit_cnt + 1'b1;
        end else begin
            bit_cnt <= bit_cnt;
        end
    end
    //WR_DATA_COMMAND
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            WR_DATA_COMMAND <= 'd0;
        end else if(STATE == STATE_IDLE && SE_flag) begin
            WR_DATA_COMMAND <= COMMAND_WREN;
        end else if(STATE == STATE_WR && div_cnt == 'd3 && bit_cnt <= 'd7) begin
            WR_DATA_COMMAND <= {WR_DATA_COMMAND[6:0],1'd0};
        end else begin
            WR_DATA_COMMAND <= WR_DATA_COMMAND;
        end
    end 
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            WR_DATA_ADDR <= 'd0;
        end else if(STATE == STATE_IDLE && SE_flag) begin
            WR_DATA_ADDR <= {COMMAND_SE,SE_ADDR};
        end else if(STATE == STATE_SE && bit_cnt <= 'd31 && div_cnt == 'd3) begin
            WR_DATA_ADDR <= {WR_DATA_ADDR[30:0],1'd0};
        end else begin
            WR_DATA_ADDR <= WR_DATA_ADDR;
        end
    end
    always @(*) begin
        if(STATE == STATE_WR) begin
            Slave_data_out <= WR_DATA_COMMAND[7];
        end else if(STATE == STATE_SE) begin
            Slave_data_out <= WR_DATA_ADDR[31];
        end else begin
            Slave_data_out <= 'd0;
        end
    end
    //state
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            STATE <= STATE_IDLE;
        end else begin
            case (STATE)
                STATE_IDLE   :
                    begin if(SE_flag) 
                        begin
                            STATE <= STATE_WR;
                        end else begin
                            STATE <= STATE_IDLE;
                        end
                    end   
                STATE_WR     :
                    begin if(bit_cnt == 'd8 && div_cnt == 'd3) 
                        begin
                            STATE <= STATE_PROTECT;
                        end else begin
                            STATE <= STATE_WR;
                        end
                    end     
                STATE_PROTECT:
                    begin if(tSHWL_cnt == tSHWL -1'b1) 
                        begin
                            STATE <= STATE_SE;
                        end else begin
                            STATE <= STATE_PROTECT;
                        end
                    end
                STATE_SE     :    
                    begin 
                        if(bit_cnt == 'd32 && div_cnt == 'd3) begin
                            STATE <= STATE_IDLE;
                        end else begin
                            STATE <= STATE_SE;
                        end
                    end 
                default:
                    begin
                        STATE <= STATE_IDLE;
                    end
            endcase
        end
    end
//         
//         //ila
//             wire   [35:0]    CONTROL0;
//             wire   [39:0]    TRIG0   ;
// assign  TRIG0 = {
//                 Slave_CS_N    ,
//                 Slave_CLK     ,
//                 Slave_data_out,
//                 SE_ADDR,//24
//                 STATE,
//                 SE_flag
//                 };
// CS_icon CS_icon_inst0 (
//     .CONTROL0   (   CONTROL0    ) // INOUT BUS [35:0]
// );
// CS_ila CS_ila_insty0 (
//     .CONTROL    (   CONTROL0    ), // INOUT BUS [35:0]
//     .CLK        (   Sys_clk     ), // IN
//     .TRIG0      (   TRIG0       ) // IN BUS [39:0]
// );
endmodule

写入(页写入):PP = 8'h02

        和SE类似,区别仅在于命令不同,此外需要在完成命令发送以后连续写入8x256位数据,即连续写入256字节。

        所以写入的方法采取提前把数据写入FIFO,在即将完成PP指令的发送的时候读出(标准模式,卡时间的话可以采取先入先出模式。)数据,再分割后通过SPI发送即可。

        WR命令,PP命令,写入数据的发送:

    always @(*) begin
        if(STATE == STATE_WR) begin
            Slave_data_out <= WR_DATA_COMMAND[7];
        end else if(STATE == STATE_PP 
            && bit_cnt <= 'd31) begin
            Slave_data_out <= WR_PP_SETING[31];
        end else if(STATE == STATE_PP 
            && bit_cnt > 'd31 
            && bit_cnt <= PP_DATA_NUM - 1'd1)begin
            Slave_data_out <= RD_REG[7];
        end else begin
            Slave_data_out <= 'd0;
        end
    end

        读使能要在真正写入之前:

    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            RD_EN_IN <= 'd0;
        end else if(STATE == STATE_PP && bit_cnt == 31 
            && div_cnt == 'd1) begin
            RD_EN_IN <= 1'd1;
        end else if(STATE == STATE_PP && shift_cnt == 'd7 
            && div_cnt == 'd1 && bit_cnt < PP_DATA_NUM - 1'd1)begin
            RD_EN_IN <= 1'd1;
        end else begin
            RD_EN_IN <= 1'd0;
        end
    end

        因为是标准模式,所以实际数据可用时间要滞后。

    always @(posedge Sys_clk) begin
        RD_EN_IN_wait <= RD_EN_IN;
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            RD_REG <= 'd0;
        end else if(RD_EN_IN_wait) begin
            RD_REG <= RD_DATA_OUT;
        end else if(bit_cnt > 31 && div_cnt == 'd3) begin
            RD_REG <= {RD_REG[6:0],1'd0};
        end else begin
            RD_REG <= RD_REG;
        end
    end

完整代码:

module Flash_PP #(
    parameter tSHWL = 'd16           ,  //100ns
    parameter PP_DATA_NUM = 'd2080
) (
    input   wire            Sys_clk,
    input   wire            Rst_n  ,
    //spi       
    input   wire            PP_flag,
    // input   wire            Slave_data_in ,
    input   wire [23:0]     PP_ADDR       ,
    output  reg             Slave_data_out,
    output  reg             Slave_CS_N    ,
    output  reg             Slave_CLK     ,
    //fifo
    input   wire            WR_EN         ,
    input   wire [7:0]      WR_DATA     
);
    //command
    localparam COMMAND_WREN  = 8'b0000_0110;
    localparam COMMAND_PP    = 8'b0000_0010;
    //state
    localparam STATE_IDLE    = 4'b0001;
    localparam STATE_WR      = 4'b0010;
    localparam STATE_PROTECT = 4'b0100;
    localparam STATE_PP      = 4'b1000;
    //cnt
            reg  [ 1:0]      div_cnt  ;
            reg  [11:0]      bit_cnt  ;
            reg  [ 3:0]      STATE    ;
            reg  [ 3:0]      tSHWL_cnt;
    //WR_DATA    
            reg  [ 7:0]      WR_DATA_COMMAND;
            reg  [ 31:0]     WR_PP_SETING   ;
    //fifo
            reg              RD_EN_IN       ;
            reg              RD_EN_IN_wait  ;
            wire [7:0]       RD_DATA_OUT    ;
            reg  [7:0]       RD_REG         ;
            wire             full           ;
            wire             empty          ;
            reg  [2:0]       shift_cnt      ;
//
    S_FIFO_8x256 S_FIFO_8x256_INST1 (
    .clk      ( Sys_clk    ), // input clk
    .din      ( WR_DATA    ), // input [7 : 0] din
    .wr_en    ( WR_EN      ), // input wr_en
    .rd_en    ( RD_EN_IN   ), // input rd_en
    .dout     ( RD_DATA_OUT), // output [7 : 0] dout
    .full     ( full       ), // output full
    .empty    ( empty      ) // output empty
    );
//
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            RD_EN_IN <= 'd0;
        end else if(STATE == STATE_PP && bit_cnt == 31 && div_cnt == 'd1) begin
            RD_EN_IN <= 1'd1;
        end else if(STATE == STATE_PP && shift_cnt == 'd7 && div_cnt == 'd1 && bit_cnt < PP_DATA_NUM - 1'd1)begin
            RD_EN_IN <= 1'd1;
        end else begin
            RD_EN_IN <= 1'd0;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            shift_cnt <= 'd0;
        end else if(STATE == STATE_PP && bit_cnt > 31) begin
            if(shift_cnt == 'd7 && div_cnt == 'd3) begin
                shift_cnt <= 'd0;
            end else if(div_cnt == 'd3) begin
                shift_cnt <= shift_cnt + 1'b1;
            end
        end else begin
            shift_cnt <= 'd0;
        end
    end
    always @(posedge Sys_clk) begin
        RD_EN_IN_wait <= RD_EN_IN;
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            RD_REG <= 'd0;
        end else if(RD_EN_IN_wait) begin
            RD_REG <= RD_DATA_OUT;
        end else if(bit_cnt > 31 && div_cnt == 'd3) begin
            RD_REG <= {RD_REG[6:0],1'd0};
        end else begin
            RD_REG <= RD_REG;
        end
    end
//
    //Slave_CS_N
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Slave_CS_N <= 1'b1;
        end else if(STATE == STATE_IDLE && PP_flag == 1'b1) begin
            Slave_CS_N <= 1'b0;
        end else if(STATE == STATE_WR && bit_cnt ==  'd8 && div_cnt == 'd3) begin
            Slave_CS_N <= 1'b1;
        end else if(STATE == STATE_PROTECT && tSHWL_cnt == tSHWL -1'b1) begin
            Slave_CS_N <= 1'b0;
        end else if(STATE == STATE_PP && bit_cnt == PP_DATA_NUM && div_cnt == 'd3) begin
            Slave_CS_N <= 1'b1;
        end else begin
            Slave_CS_N <= Slave_CS_N;
        end
    end
    //div_cnt
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            div_cnt <= 'd0;
        end else if(STATE == STATE_WR || STATE == STATE_PP) begin
            if(div_cnt == 'd3) begin
                div_cnt <= 'd0;
            end else begin
                div_cnt <= div_cnt + 1'b1;
            end
        end else begin
            div_cnt <= 'd0;
        end
    end
    //Slave_CLK
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Slave_CLK <= 'd0;
        end else if(STATE == STATE_WR && bit_cnt <= 'd7) begin
            if(bit_cnt == 'd7 && div_cnt == 'd3) begin
                Slave_CLK <= 'd0;
            end else if(div_cnt == 'd1 || div_cnt == 'd3) begin
                Slave_CLK <= ~Slave_CLK;
            end else begin
                Slave_CLK <= Slave_CLK;
            end
        end else if(STATE == STATE_PP && bit_cnt <= PP_DATA_NUM - 1'd1) begin
            if(bit_cnt == PP_DATA_NUM - 1'd1 && div_cnt == 'd3) begin
                Slave_CLK <= 'd0;
            end else if(div_cnt == 'd1 || div_cnt == 'd3) begin
                Slave_CLK <= ~Slave_CLK;
            end else begin
                Slave_CLK <= Slave_CLK;
            end
        end else begin
            Slave_CLK <= 'd0;
        end
    end
    //tSHWL_cnt
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            tSHWL_cnt <= 'd0;
        end else if(tSHWL_cnt == tSHWL -1'b1) begin
            tSHWL_cnt <= 'd0;
        end else if(STATE == STATE_PROTECT) begin
            tSHWL_cnt <= tSHWL_cnt + 1'b1;
        end else begin
            tSHWL_cnt <= tSHWL_cnt;
        end
    end
    //bit_cnt
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            bit_cnt <= 'd0;
        end else if(STATE == STATE_WR && bit_cnt == 'd8  && div_cnt == 'd3) begin
            bit_cnt <= 'd0;
        end else if(STATE == STATE_PP && bit_cnt == PP_DATA_NUM && div_cnt == 'd3) begin
            bit_cnt <= 'd0;
        end else if(div_cnt == 'd3) begin
            bit_cnt <= bit_cnt + 1'b1;
        end else begin
            bit_cnt <= bit_cnt;
        end
    end
    //WR_DATA_COMMAND
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            WR_DATA_COMMAND <= 'd0;
        end else if(STATE == STATE_IDLE && PP_flag) begin
            WR_DATA_COMMAND <= COMMAND_WREN;
        end else if(STATE == STATE_WR && div_cnt == 'd3 && bit_cnt <= 'd7) begin
            WR_DATA_COMMAND <= {WR_DATA_COMMAND[6:0],1'd0};
        end else begin
            WR_DATA_COMMAND <= WR_DATA_COMMAND;
        end
    end 
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            WR_PP_SETING <= 'd0;
        end else if(STATE == STATE_IDLE && PP_flag) begin
            WR_PP_SETING <= {COMMAND_PP,PP_ADDR};
        end else if(STATE == STATE_PP && bit_cnt <= 'd31 && div_cnt == 'd3) begin
            WR_PP_SETING <= {WR_PP_SETING[30:0],1'd0};
        end else begin
            WR_PP_SETING <= WR_PP_SETING;
        end
    end
    always @(*) begin
        if(STATE == STATE_WR) begin
            Slave_data_out <= WR_DATA_COMMAND[7];
        end else if(STATE == STATE_PP && bit_cnt <= 'd31) begin
            Slave_data_out <= WR_PP_SETING[31];
        end else if(STATE == STATE_PP && bit_cnt > 'd31 && bit_cnt <= PP_DATA_NUM - 1'd1)begin
            Slave_data_out <= RD_REG[7];
        end else begin
            Slave_data_out <= 'd0;
        end
    end
    //state
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            STATE <= STATE_IDLE;
        end else begin
            case (STATE)
                STATE_IDLE   :
                    begin if(PP_flag) 
                        begin
                            STATE <= STATE_WR;
                        end else begin
                            STATE <= STATE_IDLE;
                        end
                    end   
                STATE_WR     :
                    begin if(bit_cnt == 'd8 && div_cnt == 'd3) 
                        begin
                            STATE <= STATE_PROTECT;
                        end else begin
                            STATE <= STATE_WR;
                        end
                    end     
                STATE_PROTECT:
                    begin if(tSHWL_cnt == tSHWL -1'b1) 
                        begin
                            STATE <= STATE_PP;
                        end else begin
                            STATE <= STATE_PROTECT;
                        end
                    end
                STATE_PP     :    
                    begin 
                        if(bit_cnt == PP_DATA_NUM && div_cnt == 'd3) begin
                            STATE <= STATE_IDLE;
                        end else begin
                            STATE <= STATE_PP;
                        end
                    end 
                default:
                    begin
                        STATE <= STATE_IDLE;
                    end
            endcase
        end
    end
endmodule

读取:RD = 8'h03

        读取是一个很特殊的状态,它的读取长度是没有限制的,读取完一页会再读取下一页。所以必须人为定义其读取的长度,例如:

         此代码通过将输入的字节长度转为比特长度作为一个参数使用。

        COMMAND_ADDR_length是本身读需要的命令+地址长度。

    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            bit_cnt_end <= 'd0;
        end else if(RD_flag == 'd1) begin
            bit_cnt_end <= ((RD_data_length)<<3'd3) + COMMAND_ADDR_length;
        end else begin
            bit_cnt_end <= bit_cnt_end;
        end
    end

        数据接收

        读取操作还需要缓存在发送完COMMAND_ADDR_length以后对数据进行接收的问题。

    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            WR_DATA <= 'd0;
        end else if(bit_cnt > COMMAND_ADDR_length - 1'b1 
            && Div_cnt == DIV_NUM - 2'd2 
            && bit_cnt <= bit_cnt_end - 1'b1) begin
            WR_DATA <= {WR_DATA[6:0],Slave_data_in};
        end else begin
            WR_DATA <= WR_DATA;
        end   
    end

        这个数据会被写入到FIFO中,FIFO的写使能也需要每8bits一次产生。

        FIFO的写使能和写数据同步变化也能写入正确的数据,很省心。

//DATA_IN
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            shift_cnt <= 'd0;
        end else if(bit_cnt > COMMAND_ADDR_length - 1'b1
            && bit_cnt <= bit_cnt_end - 1'b1) begin
            if(shift_cnt == 'd7 && Div_cnt == DIV_NUM - 1'b1) begin
                shift_cnt <= 'd0;
            end else if(Div_cnt == DIV_NUM - 1'b1) begin
                shift_cnt <= shift_cnt + 1'b1;
            end
        end else begin
            shift_cnt <= 'd0;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            WR_EN <= 'd0;
        end else if(bit_cnt > COMMAND_ADDR_length - 1'b1 
            && shift_cnt == 'd7  
            && Div_cnt == DIV_NUM - 2'd2 
            && bit_cnt <= bit_cnt_end - 1'b1) begin
            WR_EN <= 1'b1;
        end else begin
            WR_EN <= 1'b0;
        end
    end

        完整代码: 

module Flash_RD #(
    parameter   DIV_NUM   = 'd4   ,
    parameter   COMMAND_ADDR_length = 'd32
)(
    input   wire            Sys_clk,
    input   wire            Rst_n  ,
    //slave
    input   wire            RD_flag,
    input   wire [23:0]     RD_ADDR,
    input   wire [10:0]     RD_data_length,
    output  reg             Slave_CLK     ,
    output  reg             Slave_CS_N    ,
    input   wire            Slave_data_in , 
    output  reg             Slave_data_out,
    //fifo
    input   wire            FIFO_RD_EN   ,
    output  wire            FIFO_RD_ready,
    output  wire [ 7:0]     RD_DATA      
);
            localparam      COMMAND_RD = 8'b0000_0011;  
            reg  [31:0]     Read_data  ; 
            reg  [ 1:0]     Div_cnt    ;
            reg  [15:0]     bit_cnt    ;
            reg  [ 3:0]     shift_cnt  ;   
            reg  [15:0]     bit_cnt_end;
        //fifo
            reg             FIFO_RD_AVAI;
            reg  [ 7:0]     WR_DATA    ;  
            reg             WR_EN      ;
            wire [ 7:0]     RD_DATA_REG;
            // reg             FIFO_RD_EN_delay;p
            wire            full       ;
            wire            empty      ;
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            bit_cnt_end <= 'd0;
        end else if(RD_flag == 'd1) begin
            bit_cnt_end <= ((RD_data_length)<<3'd3) + COMMAND_ADDR_length;
        end else begin
            bit_cnt_end <= bit_cnt_end;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Slave_CLK <= 'd0;
        end else if(Slave_CS_N == 'd0 && bit_cnt <= bit_cnt_end - 1'b1) begin
            if((Div_cnt == ((DIV_NUM - 1'b1)>>1)) || (Div_cnt == (DIV_NUM - 1'b1))) begin
                Slave_CLK <= ~Slave_CLK;
            end else begin
                Slave_CLK <= Slave_CLK;
            end
        end else begin
            Slave_CLK <= 'd0;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Slave_CS_N <= 'd1;
        end else if(RD_flag == 1'b1) begin
            Slave_CS_N <= 'd0;
        end else if(bit_cnt == bit_cnt_end && Div_cnt == DIV_NUM - 1'b1) begin
            Slave_CS_N <= 'd1;
        end else begin
            Slave_CS_N <= Slave_CS_N;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
		  Div_cnt <= 'd0;
        end else if(Slave_CS_N == 'd0) begin
            if(Div_cnt == DIV_NUM - 1'b1) begin
                Div_cnt <= 'd0;
            end else begin
                Div_cnt <= Div_cnt + 1'b1;
            end
        end else begin
            Div_cnt <= 'd0; 
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            bit_cnt <= 'd0;
        end else if(Slave_CS_N == 'd0) begin
            if(bit_cnt == bit_cnt_end && Div_cnt == DIV_NUM - 1'b1) begin
                bit_cnt <= 'd0;
            end else if(Div_cnt == DIV_NUM - 1'b1) begin
                bit_cnt <= bit_cnt + 1'b1;
            end else begin
                bit_cnt <= bit_cnt;
            end
        end else begin
            bit_cnt <= 'd0;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Read_data <= 'd0;
        end else if(RD_flag == 1'b1) begin
            Read_data <= {COMMAND_RD,RD_ADDR};
        end else if(Slave_CS_N == 'd0 && bit_cnt <= 'd31 && Div_cnt == DIV_NUM - 1'b1) begin
            Read_data <= {Read_data[30:0],1'b0};
        end else begin
            Read_data <= Read_data;
        end
    end
    always @(*) begin
        if(Slave_CS_N == 'd0 && bit_cnt <= 'd31) begin
            Slave_data_out <= Read_data[31];
        end else begin
            Slave_data_out <= 'd0;
        end
    end
//DATA_IN
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            shift_cnt <= 'd0;
        end else if(bit_cnt > COMMAND_ADDR_length - 1'b1 
        && bit_cnt <= bit_cnt_end - 1'b1) begin
            if(shift_cnt == 'd7 && Div_cnt == DIV_NUM - 1'b1) begin
                shift_cnt <= 'd0;
            end else if(Div_cnt == DIV_NUM - 1'b1) begin
                shift_cnt <= shift_cnt + 1'b1;
            end
        end else begin
            shift_cnt <= 'd0;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            WR_DATA <= 'd0;
        end else if(bit_cnt > COMMAND_ADDR_length - 1'b1 
        && Div_cnt == DIV_NUM - 2'd2 
        && bit_cnt <= bit_cnt_end - 1'b1) begin
            WR_DATA <= {WR_DATA[6:0],Slave_data_in};
        end else begin
            WR_DATA <= WR_DATA;
        end   
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            WR_EN <= 'd0;
        end else if(bit_cnt > COMMAND_ADDR_length - 1'b1 
        && shift_cnt == 'd7  
        && Div_cnt == DIV_NUM - 2'd2 
        && bit_cnt <= bit_cnt_end - 1'b1) begin
            WR_EN <= 1'b1;
        end else begin
            WR_EN <= 1'b0;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            FIFO_RD_AVAI <= 'd0;
        end else if(bit_cnt == bit_cnt_end && Div_cnt == DIV_NUM - 1'b1) begin
            FIFO_RD_AVAI <= 'd1;
        end else if(FIFO_RD_AVAI == 'd1 && empty == 'd1)begin
            FIFO_RD_AVAI <= 'd0;
        end else begin
            FIFO_RD_AVAI <= FIFO_RD_AVAI;
        end
    end
    assign FIFO_RD_ready = FIFO_RD_AVAI && (!empty);
    // always @(posedge Sys_clk) begin
    //     FIFO_RD_EN_delay <= FIFO_RD_EN;
    // end
    // always @(posedge Sys_clk or negedge Rst_n) begin
    //     if(Rst_n == 'd0) begin
    //         RD_DATA <= 'd0; 
    //     end else if(FIFO_RD_EN) begin
    //         RD_DATA <= RD_DATA_REG;
    //     end else begin
    //         RD_DATA <= RD_DATA;
    //     end
    // end
//
    S_FIFO_1024x8 S_FIFO_1024x8_INST1 (
    .clk      ( Sys_clk    ), // input clk
    .din      ( WR_DATA    ), // input [7 : 0] din
    .wr_en    ( WR_EN      ), // input wr_en
    .rd_en    ( FIFO_RD_EN ), // input rd_en
    .dout     ( RD_DATA    ), // output [7 : 0] dout
    .full     ( full       ), // output full
    .empty    ( empty      ) // output empty
    );
endmodule

[1]威三学院FPGA教程

[2]小梅哥AC620V2教程

[3]FPGA中ICAP原语的使用——Multiboot功能的实现_朽月的博客-CSDN博客

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值