Serial Flash Loader读写Flash存储芯片

主要通过调用Quartus的ip核Serial Flash Loader对M25P16的擦除,写和读

因为Serial Flash Loader没有仿真库,所以验证数据是否写入和读出正确时,这里采用Quartus 自带的SignalTap II 在线调试验证的

先来看一下Serial Flash Loader的调用
这里写图片描述

代码实现分为SPI和SPI_ctrl两个模块,Flash的擦除,写入,读写都在SPI_ctrl模块中,当然也可以单独分开,擦除,写入,读写各作为一个模块

先来一下RTL视图吧
这里写图片描述

实现以3个按键消抖后分别控制擦除,写入,和读

时序图:
SE(擦除)
这里写图片描述
PP(页写入)
这里写图片描述
RD(读)
这里写图片描述

实现代码:

1.按键模块

//key_press 主要代码
//当按键按下时经过消抖延时后 产生一个按下的脉冲标志key_in_flag 
module  key_press(
                    input sclk,
                    input rst_n,
                    input key_in,
                    output reg key_in_flag
                    );
//  .....
always @(posedge sclk or negedge rst_n)
    if(rst_n ==1'b0)
        state <= IDLE;
    else begin 
        case(state)
            IDLE    :   if(key_neg_flag == 1'b1)
                            state <=PRE_FLAG;
            PRE_FLAG:   if(pre_end_10ms == 1'b1 && key_in == 1'b0)
                            state <=KEY_FLAG;
                        else if(pre_end_10ms == 1'b1 && key_in == 1'b1)
                            state <= IDLE;
            KEY_FLAG:   if(key_pos_flag == 1'b1)
                            state <= POST_FLAG;
            POST_FLAG:  if(post_end_10ms == 1'b1)
                            state <= IDLE;
            default : state <=IDLE;
        endcase
    end

    //key flag
    always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        key_in_flag <= 1'b0;
    else if(state == KEY_FLAG && key_cnt == END_20MS)
        key_in_flag <= 1'b1;
    else
        key_in_flag <= 1'b0;
//.......
endmodule

2.SPI_ctrl模块

module SPI_ctrl(
                input clk,
                input rst_n,
                input key_se,
                input key_wr,
                input key_rd,

                output reg CS_n,
                output reg SCK,
                output reg DATA_IN
                );
//-------------instruction------
    parameter 
            WR_Instru   = 8'h06,
            SE_Instru   = 8'hd8,
            PP_Instru   = 8'h02,
            RD_Instru   = 8'h03,
            ADDR        = 24'h000000,
            WR_DATA     = 8'h0f;//写一个byte为例
//--------部分主要代码-------------
//---------state ctrl falg ----------------------------------------
    wire wr_state_flag,se_state_flag,pp_state_flag,rd_state_flag;
    assign wr_state_flag = (state == WREN && cnt_sck == 7'd19)? 1'b1:1'b0;
    assign se_state_flag = (state == SE && cnt_sck == 7'd67)? 1'b1:1'b0;
    assign pp_state_flag = (state == PP && cnt_sck == 7'd83)? 1'b1:1'b0;
    assign rd_state_flag = (state == RD && cnt_sck == 7'd83)? 1'b1:1'b0;

    //---------en_sck ctrl flag ----------------------------------------
    wire en_sck_wr,en_sck_se,en_sck_pp,en_sck_rd;
    assign en_sck_wr = (state == WREN && cnt_sck == 7'd17)? 1'b1:1'b0;
    assign en_sck_se = (state == SE && cnt_sck == 7'd65) ? 1'b1:1'b0;
    assign en_sck_pp = (state == PP && cnt_sck == 7'd81) ? 1'b1:1'b0;
    assign en_sck_rd = (state == RD && cnt_sck == 7'd81) ? 1'b1:1'b0;
//----------chip selection ctrl----------------------------------------
    always @(posedge clk or negedge rst_n)
    if(!rst_n)  
        CS_n <= 1'b1;
    else if(key_se || key_wr || key_rd || cnt_delay == 4'd15)
        CS_n <= 1'b0;   
    else if(wr_state_flag||se_state_flag||pp_state_flag||rd_state_flag)
        CS_n <= 1'b1;
    else 
        CS_n <= CS_n;

    //------------cs_n==0 cnt_sck++-----------------------------------------
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        cnt_sck <= 7'd0;
    else if(CS_n == 1'b0)
        cnt_sck <= cnt_sck + 1'b1;
    else 
        cnt_sck <= 7'd0;

    //-------------SCK signel en-----------------------------------------   
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        en_sck <= 1'b0;
    else if(cnt_sck == 7'd1)
        en_sck <= 1'b1;
    else if(en_sck_wr ||en_sck_se || en_sck_pp || en_sck_rd)
        en_sck <= 1'b0;
    else
        en_sck <= en_sck;

    //-----------SCK = ~SCK-----------------------------------------------
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        SCK <= 1'b0;
    else if((state == WREN||state == SE||state == PP || state == RD) && en_sck)
        SCK <= ~SCK;
    else
        SCK <= 1'b0;

    //-------------DATA_IN ctrl-------------------------------------------- 
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        data_wr <= WR_Instru;
    else if(state == WREN && en_sck == 1'b1 && SCK == 1'b0)
        data_wr <= {data_wr[6:0],data_wr[7]};
    else 
        data_wr <= data_wr;

    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        data_se <= {SE_Instru,ADDR};
    else if(state == SE && en_sck == 1'b1 && SCK == 1'b0)
        data_se <= {data_se[30:0],data_se[31]};
    else 
        data_se <= data_se;

    //-------------DATA_IN------------------------------
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        DATA_IN <= 1'b0;
    else begin
        case(state)
            WREN    :   DATA_IN <= data_wr[7];
            SE      :   DATA_IN <= data_se[31];
            PP      :   DATA_IN <= data_pp[39];
            RD      :   DATA_IN <= data_rd[31];
            default :   DATA_IN <= 1'b0;
        endcase
    end

    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        data_pp <= {PP_Instru,ADDR,WR_DATA};
    else if(state == PP && en_sck == 1'b1 && SCK == 1'b0)
        data_pp <= {data_pp[38:0],data_pp[39]};
    else 
        data_pp <= data_pp;

    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        shift_flag <= 1'b0;
    else if(cnt_sck > 7'd0 && cnt_sck <= 7'd63)
        shift_flag <= 1'b1;
    else 
        shift_flag <= 1'b0;

    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        data_rd <= {RD_Instru,ADDR};
    else if(state == RD && en_sck == 1'b1 && SCK == 1'b0 && shift_flag == 1'b1)
        data_rd <= {data_rd[30:0],data_rd[31]};
    else 
        data_rd <= data_rd;

    //------------key state choose flag-----------------------------------
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        key_se_flag <= 1'b0;
    else if(key_se)
        key_se_flag <= 1'b1;
    else if(se_state_flag)// SE state end
        key_se_flag <= 1'b0;
    else 
        key_se_flag <= key_se_flag;

    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        key_wr_flag <= 1'b0;
    else if(key_wr)
        key_wr_flag <= 1'b1;
    else if(pp_state_flag)// PP state end
        key_wr_flag <= 1'b0;
    else 
        key_wr_flag <= key_wr_flag;

    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        key_rd_flag <= 1'b0;
    else if(key_rd)
        key_rd_flag <= 1'b1;
    else if(rd_state_flag)// RD state end
        key_rd_flag <= 1'b0;
    else 
        key_rd_flag <= key_rd_flag;

    //-------------DELAY state keep------------------------------------------   
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        cnt_delay <= 4'd0;
    else if(state == DELAY)begin
        if(cnt_delay == 4'd15)
            cnt_delay <= 4'd0;
        else 
            cnt_delay <= cnt_delay + 1'b1;      
    end
    else 
        cnt_delay <= 4'd0;

    //-------------------state skip-----------------------------------------
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
        state <= IDLE;
    else begin
        case(state)
            IDLE    :   if(CS_n == 1'b0 && key_rd_flag)
                            state <= RD;
                        else if(CS_n == 1'b0)
                            state <= WREN;
                        else 
                            state <= IDLE;
            WREN    :   if(CS_n == 1'b1)
                            state <= DELAY;
                        else 
                            state <= WREN;
            DELAY   :   if(CS_n == 1'b0 && key_se_flag)
                            state <= SE;
                        else if(CS_n == 1'b0 && key_wr_flag)
                            state <= PP;
                        else 
                            state <= DELAY;
            SE      :   if(CS_n == 1'b1)
                            state <= IDLE;
                        else
                            state <= SE;
            PP      :   if(CS_n == 1'b1)
                            state <= IDLE;
                        else
                            state <= PP;
            RD      :   if(CS_n == 1'b1)
                            state <= IDLE;
                        else
                            state <= RD;
            default :   state <= IDLE;
        endcase     
    end

endmodule

3.TOP模块
//因为Serial Flash Loader使用的是专用引脚,所以这里不用设置输出

module SPI(
                    input clk,
                    input rst_n,
                    input key_se,
                    input key_wr,
                    input key_rd

                    );

//M25P16根据手可知最大达到 50 MHz SPI Bus Interface 
//而手册中read data byte可知,a maximum frequency fR,读数据最大频率20Mhz
//所以这里SCK信号是12.5MHz
//比较简单的实现方法是:通过PLL对系统时钟进行分频得到25Mhz即可
key_press key_se_inst(
                    .sclk(clk_25M),
                    .rst_n(rst_n),
                    .key_in(key_se),
                    .key_in_flag(key_se_flag)
                    );
//....
SPI_ctrl SPI_ctrl_inst(
                .clk(clk_25M),
                .rst_n(rst_n),
                .key_se(key_se_flag),
                .key_wr(key_wr_flag),
                .key_rd(key_rd_flag),

                .CS_n(CS_n),
                .SCK(SCK),
                .DATA_IN(DATA_IN)
                );

    spi_flash   spi_flash_inst (
    .asdo_in ( DATA_IN ),
    .asmi_access_granted ( 1'b1 ),
    .dclk_in ( SCK ),
    .ncso_in ( CS_n ),
    .noe_in ( 1'b0 ),
    .asmi_access_request ( ),
    .data0_out (  )
    );

因为Serial Flash Loader不能仿真验证,这里只对擦除,写入和读的时序进行仿真
这里写图片描述

时序达到要求后,进一步使用Signaltap验证是否准确写入和读出

擦除验证
这里写图片描述
写入验证
这里写图片描述
读出验证
这里写图片描述

这里可以看到 DATA0_OUT的输出是’h0f 与我们写入的数据一致

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值