zoukankan      html  css  js  c++  java
  • 16经典的SPI Flash的扇区擦除flash_se功能

    一设计功能

    对SPI_flash进行扇区擦除,分为写指令和扇区擦除两个时序部分。

    二设计知识点

    我简单理解flash,第一它是掉电不丢失数据的存储器,第二它每次写入新数据前首先得擦除数据,分为扇区擦除和全擦擦。

    下面讲讲我自己亲自动手设计的原创代码过程:

    自己设计过程:

    第一步:就先看了SPI FLASH文档,了解SPI FLAHS的原理:先有写使能信号及其时序波形,然后是扇区擦除指令和地址及时序波形,再是延时3秒回到初始状态。

    第二步:自己画出所有的状态及其转移图,还是就是用线性序列机表达写使能指令的时序和扇区擦除的时序,并且把他们用EXCEL表弄出相应的时间点和信号的变化(对输出信号赋值)。做完后再弄出模块框图。

    第三步:根据自己的模块框图和状态转移图,还有线性序列机的EXCEL表格,描述对应的代码。

    第四步:仿真验证是否出错。

    我的设计思想如下图所示,三部分。

    一是计数器(写使能时序的计数器,扇区擦除的计数器,延时三秒的计数器).

    二是,状态机。(初始状态,写使能指令状态,擦除扇区的状态,延时三秒的状态)

    三是,线性序列机。(由写指令和擦除扇区的时序图弄好计数值及信号变化)

    计数器:

    一是WF计数器,计到41,位宽为6。

     二是SE计数器,计到128.,位宽为9

     三是延时3秒的计数器, 计到150M,位宽为28

    针对众多时序逻辑的编码方法:第一步在excel中,分成两列,一列是计数值(使用序列填充,等差),一列是对应的信号变化。第二步,直接在notepad++里使用列编辑加上分号,欧克勒。

    线性序列机:

                    

    WE的时序逻辑:下图为WREN时序波形图。

    时间ns

    计数值

    信号的操作

    0

    0

    Begin sck<=0;cs_n<=1;sdi<=0;end

    20

    1

    Begin sck<=0; cs_n<=0;end

    80

    4

    sck<=1;

    120

    6

    sck<=0;

    160

    8

    sck<=1;

    200

    10

    sck<=0;

    240

    12

    sck<=1;

    280

    14

    sck<=0;

    320

    16

    sck<=1;

    360

    18

    sck<=0;

    400

    20

    sck<=1;

    440

    22

    Begin sck<=0; sdi<=1;end

    480

    24

    sck<=1;

    520

    26

    Begin sck<=0; sdi<=1;end

    560

    28

    sck<=1;

    600

    30

    Begin sck<=0; sdi<=0;end

    640

    32

    sck<=1;

    680

    34

    sck<=0;

    700

    35

    cs_n<=1;

    800

    40

    SE的时序逻辑:下图为SE时序波形图。

     

    下面为线性序列机的EXCEL描述SE时序:

    时间点

    计数值

    信号的变化

    40

    2

    Begin sck<=1;sdi<=1;end

    80

    4

    sck<=0;

    120

    6

    Begin sck<=1;sdi<=1;end

    160

    8

    sck<=0;

    200

    10

    Begin sck<=1;sdi<=0;end

    240

    12

    sck<=0;

    280

    14

    Begin sck<=1;sdi<=1;end

    320

    16

    sck<=0;

    360

    18

    Begin sck<=1;sdi<=1;end

    400

    20

    sck<=0;

    440

    22

    Begin sck<=1;sdi<=0;end

    480

    24

    sck<=0;

    520

    26

    sck<=1;

    560

    28

    sck<=0;

    600

    30

    sck<=1;

    640

    32

    sck<=0;

    680

    34

    Begin sck<=1;sdi<=SE_addr[23];end

    720

    36

    sck<=0;

    760

    38

    Begin sck<=1;sdi<=SE_addr[22];end

    800

    40

    sck<=0;

    840

    42

    Begin sck<=1;sdi<=SE_addr[21];end

    880

    44

    sck<=0;

    920

    46

    Begin sck<=1;sdi<=SE_addr[20];end

    960

    48

    sck<=0;

    1000

    50

    Begin sck<=1;sdi<=SE_addr[19];end

    1040

    52

    sck<=0;

    1080

    54

    Begin sck<=1;sdi<=SE_addr[18];end

    1120

    56

    sck<=0;

    1160

    58

    Begin sck<=1;sdi<=SE_addr[17];end

    1200

    60

    sck<=0;

    1240

    62

    Begin sck<=1;sdi<=SE_addr[16];end

    1280

    64

    sck<=0;

    1320

    66

    Begin sck<=1;sdi<=SE_addr[15];end

    1360

    68

    sck<=0;

    1400

    70

    Begin sck<=1;sdi<=SE_addr[14];end

    1440

    72

    sck<=0;

    1480

    74

    Begin sck<=1;sdi<=SE_addr[13];end

    1520

    76

    sck<=0;

    1560

    78

    Begin sck<=1;sdi<=SE_addr[12];end

    1600

    80

    sck<=0;

    1640

    82

    Begin sck<=1;sdi<=SE_addr[11];end

    1680

    84

    sck<=0;

    1720

    86

    Begin sck<=1;sdi<=SE_addr[10];end

    1760

    88

    sck<=0;

    1800

    90

    Begin sck<=1;sdi<=SE_addr[9];end

    1840

    92

    sck<=0;

    1880

    94

    Begin sck<=1;sdi<=SE_addr[8];end

    1920

    96

    sck<=0;

    1960

    98

    Begin sck<=1;sdi<=SE_addr[7];end

    2000

    100

    sck<=0;

    2040

    102

    Begin sck<=1;sdi<=SE_addr[6];end

    2080

    104

    sck<=0;

    2120

    106

    Begin sck<=1;sdi<=SE_addr[5];end

    2160

    108

    sck<=0;

    2200

    110

    Begin sck<=1;sdi<=SE_addr[4];end

    2240

    112

    sck<=0;

    2280

    114

    Begin sck<=1;sdi<=SE_addr[3];end

    2320

    116

    sck<=0;

    2360

    118

    Begin sck<=1;sdi<=SE_addr[2];end

    2400

    120

    sck<=0;

    2440

    122

    Begin sck<=1;sdi<=SE_addr[1];end

    2480

    124

    sck<=0;

    2520

    126

    Begin sck<=1;sdi<=SE_addr[0];end

    2560

    128

    sck<=0;

    二设计输入

    Flash扇区擦除的功能模块

    module flash_se(

    input wire clk,

    input wire rst_n,

    input wire we_flag,

    input wire [23:0]SE_addr,

    output reg     sck,

    output reg     sdi,

    output reg     cs_n

           );

    reg we_en;            //进入写使能指令时序的标志信号

    reg se_en;             //进入扇区擦除指令时序的标志信号

    reg [3:0]state;//定义状态变量

    reg sck0,sck1;

    reg sdi0,sdi1;

    reg cs_n0,cs_n1;

    parameter idel = 4'b0001;           //初始状态

    parameter WERN = 4'b0010;             //写使能指令状态

    parameter SE = 4'b0100;             //扇区擦除

    parameter DELAY = 4'b1000;//3秒延时状态

    reg[5:0]we_cnt;

    reg[7:0]se_cnt;

    reg[27:0]delay_cnt;

    //写使能指令时序的计数器

    always@(posedge clk or negedge rst_n)

    if(!rst_n)

           we_cnt<=0;

    else if(we_cnt=='d41)

           we_cnt<=0;

    else if(we_en)

           we_cnt<=we_cnt+1'b1;

    //扇区擦除时序的计数器

    always@(posedge clk or negedge rst_n)

    if(!rst_n)

           se_cnt<=0;

    else if(se_cnt=='d128)

           se_cnt<=0;

    else if(se_en)

           se_cnt<=se_cnt+1'b1;  

    parameter T3S = 28'd150_000_000-1;

    always@(posedge clk or negedge rst_n)begin

           if(rst_n==1'b0)begin

                  state<=idel;

                  delay_cnt<=0;

                  we_en<=0;

                  se_en<=0;

                  end

           else begin

                  case(state)

                         idel: if(we_flag)    //投入0.5元

                                       state<=WERN;

                                       else

                                       state<=idel;

                                      

                         WERN:if(we_cnt=='d41)begin

                                       state<=SE;

                                       we_en<=0;

                                       end

                                else begin

                                       state<=state;

                                       we_en<=1;

                                       end

                         SE:if(se_cnt=='d128)begin

                                       state<=DELAY;

                                       se_en<=0;

                                       end

                                else begin

                                       state<=state;

                                       se_en<=1;

                                       end

                         DELAY:if(delay_cnt==T3S)begin

                                       state<=idel;

                                       delay_cnt<=0;

                                       end

                                else begin

                                       delay_cnt<=delay_cnt+1'b1;

                                       state<=state;

                                end

                         default:state<=idel;

                  endcase

           end

    end

    //写使能信号时序通过线性序列机

    always@(posedge clk or negedge rst_n)

    if(!rst_n)begin

           sck0<=0;cs_n0<=1;sdi0<=0;

    end

           else begin

                  case(we_cnt)

                        

    0 :cs_n0<=0;

    1 :sck0<=1;

    4 :sck0<=0;

    6 :sck0<=1;

    8 :sck0<=0;

    10:sck0<=1;

    12:sck0<=0;

    14:sck0<=1;

    16:sck0<=0;

    18:sck0<=1;

    20:sck0<=0;

    22:begin sck0<=1; sdi0<=1;end

    24:sck0<=0;

    26:begin sck0<=1; sdi0<=1;end

    28:sck0<=0;

    30:begin sck0<=1; sdi0<=0;end

    32:sck0<=0;

    34:sck0<=1;

    35:sck0<=0;

    40:begin sck0<=0;cs_n0<=1;sdi0<=0;end

                  default: ;

                  endcase

           end

    //扇区擦除时序通过线性序列机

    always@(posedge clk or negedge rst_n)

    if(!rst_n)begin

           sck1<=0;cs_n1<=1;sdi1<=0;

    end

           else begin

                  case(se_cnt)

    0:begin sck1<=0;cs_n1<=1;sdi1<=0;end          

    2     :begin sck1<=1;cs_n1<=0;end

    4     :sck1<=0;

    6     :begin sck1<=1;sdi1<=1;end

    8     :sck1<=0;

    10   :begin sck1<=1;sdi1<=0;end

    12   :sck1<=0;

    14   :begin sck1<=1;sdi1<=1;end

    16   :sck1<=0;

    18   :begin sck1<=1;sdi1<=1;end

    20   :sck1<=0;

    22   :begin sck1<=1;sdi1<=0;end

    24   :sck1<=0;

    26   :sck1<=1;

    28   :sck1<=0;

    30   :sck1<=1;

    32   :sck1<=0;

    34   :begin sck1<=1;sdi1<=SE_addr[23];end

    36   :sck1<=0;

    38   :begin sck1<=1;sdi1<=SE_addr[22];end

    40   :sck1<=0;

    42   :begin sck1<=1;sdi1<=SE_addr[21];end

    44   :sck1<=0;

    46   :begin sck1<=1;sdi1<=SE_addr[20];end

    48   :sck1<=0;

    50   :begin sck1<=1;sdi1<=SE_addr[19];end

    52   :sck1<=0;

    54   :begin sck1<=1;sdi1<=SE_addr[18];end

    56   :sck1<=0;

    58   :begin sck1<=1;sdi1<=SE_addr[17];end

    60   :sck1<=0;

    62   :begin sck1<=1;sdi1<=SE_addr[16];end

    64   :sck1<=0;

    66   :begin sck1<=1;sdi1<=SE_addr[15];end

    68   :sck1<=0;

    70   :begin sck1<=1;sdi1<=SE_addr[14];end

    72   :sck1<=0;

    74   :begin sck1<=1;sdi1<=SE_addr[13];end

    76   :sck1<=0;

    78   :begin sck1<=1;sdi1<=SE_addr[12];end

    80   :sck1<=0;

    82   :begin sck1<=1;sdi1<=SE_addr[11];end

    84   :sck1<=0;

    86   :begin sck1<=1;sdi1<=SE_addr[10];end

    88   :sck1<=0;

    90   :begin sck1<=1;sdi1<=SE_addr[9];end

    92   :sck1<=0;

    94   :begin sck1<=1;sdi1<=SE_addr[8];end

    96   :sck1<=0;

    98   :begin sck1<=1;sdi1<=SE_addr[7];end

    100  :sck1<=0;

    102  :begin sck1<=1;sdi1<=SE_addr[6];end

    104  :sck1<=0;

    106  :begin sck1<=1;sdi1<=SE_addr[5];end

    108  :sck1<=0;

    110  :begin sck1<=1;sdi1<=SE_addr[4];end

    112  :sck1<=0;

    114  :begin sck1<=1;sdi1<=SE_addr[3];end

    116  :sck1<=0;

    118  :begin sck1<=1;sdi1<=SE_addr[2];end

    120  :sck1<=0;

    122  :begin sck1<=1;sdi1<=SE_addr[1];end

    124  :sck1<=0;

    126  :begin sck1<=1;sdi1<=SE_addr[0];end

    128  :begin sck1<=0;cs_n1<=1;sdi1<=0;end

                  default: ;

                  endcase

           end 

           //对于输出避免冒险通过选择器

           always@(posedge clk or negedge rst_n)

           if(!rst_n)

           begin

                  sck<=0;cs_n<=1;sdi<=0;

           end

           else if(state==WERN)begin

                  sck<=sck0;cs_n<=cs_n0;sdi<=sdi0;

    end

           else if(state==SE)begin

                  sck<=sck1;cs_n<=cs_n1;sdi<=sdi1;

    end

    endmodule

    Flash扇区擦除的测试模块

    `timescale 1ns/1ns

    `define clk_period 20

    module flash_se_tb;

    reg   clk   ;

    reg   rst_n ;

    reg   we_fla;

    reg[23:0]SE_add;

    wire  sck   ;

    wire  sdi   ;

    wire  cs_n  ;

    initial clk =1;

    always#10 clk =~clk;

    initial begin

           rst_n =0;

           we_fla =0;

           SE_add = 0;

           #(`clk_period*2);

           rst_n =1;

           we_fla =1;

           SE_add = 24'b0100_0010_0000_0000_0000_0000;

           #(`clk_period);we_fla =0;

           #(`clk_period*400);

           rst_n =0;

    #(`clk_period*20);

    $stop;

    end

           flash_se #(.T3S(199)) inst_flash_se (

                         .clk     (clk),

                         .rst_n   (rst_n),

                         .we_flag (we_fla),

                         .SE_addr (SE_add),

                         .sck     (sck),

                         .sdi     (sdi),

                         .cs_n    (cs_n)

                  );

    endmodule

    三FLASH的扇区擦除的仿真波形如下

    我的收获是:

    首先是第一次遇到陌生有难度的东西,不要怂,要静下心来亲自动手做和思考,一步步的。

    其次是,弄懂设计原理和设计思路,这可能占了整个设计的40%,调试代码占了40%,敲代码只占了10%,还有10%就是记录整理勒。画好图纸比敲代码重要得多,代码只不过是思路的描述。

  • 相关阅读:
    模拟
    广搜——最优方案
    动态规划——背包
    动态规划——树规
    动态规划——区间
    fill 的用法
    状态压缩dp
    超大背包问题
    lower_bound
    弹性碰撞 poj 3684
  • 原文地址:https://www.cnblogs.com/Xwangzi66/p/12984197.html
Copyright © 2011-2022 走看看