FPGA学习系列:内存128M的flash芯片设计

出处:电子发烧友 发布于:2018-09-14 13:39:39

  FLASH闪存 闪存的英文名称是"Flash Memory",一般简称为"Flash",它属于内存器件的一种,是一种不挥发性( Non-Volatile )内存。闪存的物理特性与常见的内存有根本性的差异:目前各类 DDR 、 SDRAM 或者 RDRAM 都属于挥发性内存,只要停止电流供应内存中的数据便无法保持,因此每次电脑开机都需要把数据重新载入内存;闪存在没有电流供应的条件下也能够长久地保持数据,其存储特性相当于硬盘,这项特性正是闪存得以成为各类便携型数字设备的存储介质的基础。
  设计原理:
  我们的设计用的是W25Q128FV 内存128M的flash芯片,大家可以自行在网上器件手册具体看所应用的具体命令和自己项目具体的应用和想发来设计。
  这款flash芯片的的存储是一个扇区4KB,一个扇区可以存256个字,一个字是8位,一个块是64KB,一共有256个块组成一个存储flash内存。
  我在下面的讲解中,将主要讲实现一下字节的读写,我用的协议是SPI协议,这个芯片支持QSPI,双端口SPI等。flash有三个状态寄存器,每一个状态寄存器的每一位都有各自的功能。大家可以具体的看器件手册,我给大家简单的讲一下个状态寄存器。
  这个状态寄存器位是可读忙和不忙的标志位,大家可以在我们的设计中判断芯片是否忙和不忙来是否进行下一步的操作。第二位是一个写标志的信号,当写使能打开的时候它位1,只有它为1的时候我们才可以进行写,值得一说的不管是页操作,还是擦除等命令后都会使这个标志位变成0。然后前面的命令算的上的是保护命令,具体有使用的逻辑功能。


  在flash中我们写数据前先要擦除数据你想擦除的地方,然后进行写,如果没有用过的flash芯片的话那么可以不用擦除。毕竟我们的flash可是掉电不丢失数据的。
  我的设计思路是这样的我们先读出我们的器件厂商,和芯片ID,然后记性写命令,写使能打开,页操作写入数据(值得说明的是我们FLASH是新的所以没进行擦除命令,建议擦除---关闭写使能 -- 打开写使能),然后读个寄存器判断芯片的位是否忙,不忙然后进行读操作之后再数码管上显示出我们写入的数据。
  部分操作命令如下


  我们的发送格式为在时钟的上升沿写入命令,在时钟的下降沿读出命令,我们用的是标准的SPI协议,端口IO0,和IO1,都是单向的。
  写使能时序:


  读使能时序:
  之后别的时序我们将不展示,大家可以参考器件手册。
  设计架构图:
  我们的设计是用一个FSM控制器来控制发送什么命令,flash模块判断FSM发送过来的state信号来选择应该执行什么操作,当命令写入或者读出后,会发送一个flag_done命令,这个命令让我们判断上个指令是否完成,如果完成后FAM将发送下一个命令。
  设计代码:
  设计模块
  0 module fsm(clk, rst_n, flag_done, command, addr, state, data);
  1
  2  input clk, rst_n;
  3  input flag_done;   //输入标志位
  4  output reg [7:0] command;   //输出命令
  5  output reg [23:0] addr;     //输出地址
  6  output reg [2:0] state;  //输出状态模式
  7  output reg [7:0] data;     //输出写入数据
  8
  9  reg [2:0] state_s;
  10 reg [20:0] count;
  11 always @ (posedge clk)
  12  if(!rst_n)
  13   begin
  14    state_s <= 0;
  15    data <= 8'd0;
  16    addr <= 24'd0;
  17    command <= 8'd0;
  18    state <= 0;
  19    count <= 0;
  20   end
  21  else
  22   case (state_s)
  23    0 : begin
  24       if(count < 200)    //延迟一段时间
  25        count <= count + 1;
  26       else
  27        begin       //发送读厂商ID的命令
  28         command <= 8'h90;
  29         addr <= 24'd0;
  30         state <= 1;
  31         count <= 1;
  32        end
  33       if(flag_done)   //检查是否完成
  34        state_s <= 1;
  35      end
  36
  37    1 : begin
  38       if(count < 200)  //延迟一段时间
  39        count <= count + 1;
  40       else
  41        begin    //写使能
  42         command <= 8'h06;
  43         state <= 3;
  44         count <= 0;
  45        end
  46       if(flag_done)  //检查是否完成
  47        state_s <= 2;
  48      end
  49
  50    2 : begin
  51       if(count < 200)   //延迟一段时间
  52        count <= count + 1;
  53       else
  54        begin    //页操作
  55         command <= 8'h02;
  56         addr <= 24'd0;
  57         state <= 4;
  58         data <= 8'haa;
  59         count <= 0;
  60        end
  61       if(flag_done)   //检查是否完成
  62        state_s <= 3;
  63      end
  64
  65    3 : begin
  66       if(count < 200)   //延迟一段时间
  67        count <= count + 1;
  68       else
  69        begin    //读寄存器
  70         command <= 8'h05;
  71         count <= 0;
  72         state <= 5;
  73        end
  74       if(flag_done)   //检查是否完成
  75        state_s <= 4;
  76      end
  77
  78    4 : begin
  79       if(count < 200)    //延迟一段时间
  80        count <= count + 1;
  81       else
  82        begin     //读数据
  83         command <= 8'h03;
  84         addr <= 24'd0;
  85         state <= 2;
  86         count <= 0;
  87        end
  88      end
  89
  90    default: state_s <= 0;
  91   endcase
  92
  93 endmodule
  0  module flash (clk , rst_n, q0,  q1, sclk, cs, command, addr, state,   data, show_data, flag_done);
  1
  2   input clk, rst_n;
  3   input q0;
  4   output reg q1;
  5   output reg sclk;
  6   output reg cs;
  7   input [7:0] command;   //输入命令
  8   input [23:0] addr;   //地址
  9   input [2:0] state;   //状态
  10  input [7:0] data;    //数据
  11  output reg [23:0] show_data;  //显示
  12  output reg flag_done;  //命令完成标志
  13
  14  reg [5:0] count;
  15  reg [5:0] cnt;
  16  reg [31:0] temp;
  17  reg [15:0] d;
  18  reg [5:0] count_s;
  19  reg [7:0] dou;
  20  reg [39:0] xie;
  21  reg [7:0] r_reg;
  22
  23  always @ (posedge clk)
  24   if(!rst_n)
  25    begin
  26     sclk <= 1;
  27     count_s <= 0;
  28    end
  29   else if(cs)
  30    begin
  31     count_s <= 0;
  32     sclk <= 1;
  33    end
  34   else
  35    begin
  36     if(count_s == 25 - 1)  //产生1M的时钟
  37       begin
  38        count_s <= 0;
  39        sclk <= ~sclk;
  40       end
  41     else
  42      count_s <= count_s + 1;
  43    end
  44
  45  reg [1:0] signle_s;
  46
  47  //边沿检测电路
  48  always @ (posedge clk or negedge rst_n)
  49   if(!rst_n)
  50    begin
  51     signle_s <= 2'b11;
  52    end
  53   else
  54    begin
  55     signle_s[0] <= sclk;
  56     signle_s[1] <= signle_s[0];
  57    end
  58
  59  assign pose_dge = signle_s[0] && ~signle_s[1];  //上升沿脉冲
  60  assign nege_dge = ~signle_s[0] && signle_s[1];  //下降沿脉冲
  61
  62  reg [1:0] s;
  63  reg [1:0] s1,s2,s3,s4;
  64  always @ (posedge clk or negedge rst_n)
  65   if(!rst_n)
  66    begin
  67     q1 <= 0;
  68     count <= 0;
  69     cs <= 1;
  70     temp <= 0;
  71     d <= 0;
  72     cnt <= 0;
  73     s <= 0;
  74     s1 <= 0;
  75     s2 <= 0;
  76     s3 <= 0;
  77     flag_done <= 0;
  78     s4 <= 0;
  79    end
  80   else
  81   begin
  82    if (state == 1)      //state == 1进入读芯片的厂商和ID
  83     case (s)
  84      0:  begin  cs <= 0;  temp <= {command,addr}; s <= 1;   end
  85
  86      1 : begin
  87        if(nege_dge)  //下降沿发送数据
  88         begin
  89          if(count < 32)
  90           begin
  91            q1 <= temp[31];
  92            count <= count + 1;
  93            temp <=          {temp[30:0],temp[31]};
  94           end
  95          else
  96           begin
  97            count <= 0;
  98            s <= 2;
  99           end
  100        end
  101       else
  102        q1 <= q1;
  103      end
  104
  105     2 : begin
  106       if(pose_dge)  //上升沿采集数据
  107        begin
  108         if(count < 16)
  109          begin
  110           count <= count + 1;
  111           d <= {d[14:0],q0};
  112          end
  113         else
  114          begin
  115           s <= 3;
  116           cs <= 1;
  117           count <= 0;
  118           flag_done <= 1;
  119           show_data <= d;
  120          end
  121        end
  122       else
  123        begin
  124         s <= 2;
  125        end
  126      end
  127
  128     3 :  begin
  129        flag_done <= 0;
  130       end
  131
  132     endcase
  133
  134  else if(state == 2)   //state == 2进入读模式
  135   case (s1)
  136    0:  begin  cs <= 0;  temp <= {command,addr}; s1 <= 1;    end
  137
  138    1 :begin
  139      if(nege_dge)
  140       begin
  141        if(count < 32)
  142         begin
  143          q1 <= temp[31];
  144          count <= count + 1;
  145          temp <= {temp[30:0],temp[31]};
  146         end
  147        else
  148         begin
  149          count <= 0;
  150          s1 <= 2;
  151         end
  152       end
  153      else
  154       q1 <= q1;
  155     end
  156
  157    2 : begin
  158      if(pose_dge)
  159       begin
  160        if(count < 8)
  161         begin
  162          count <= count + 1;
  163          dou <= {dou[6:0],q0};
  164          s1 <= 2;
  165         end
  166        else
  167         begin
  168          s1 <= 3;
  169          cs <= 1;
  170          count <= 0;
  171          flag_done <= 1;
  172          show_data <= dou;
  173         end
  174       end
  175      else
  176       begin
  177        s1 <= 2;
  178       end
  179     end
  180
  181    3 :  begin
  182       flag_done <= 0;
  183      end
  184   endcase
  185
  186  else if(state == 3)   //state == 3 进入写使能模式
  187   case (s2)
  188    0:  begin  cs <= 0;  temp <= {command,addr}; s2 <= 1;       end
  189
  190    1 :begin
  191      if(nege_dge)
  192       begin
  193        if(count < 8)
  194         begin
  195          q1 <= temp[31];
  196          count <= count + 1;
  197          temp <= {temp[30:0],temp[31]};
  198         end
  199        else
  200         begin
  201          count <= 0;
  202          s2 <= 2;
  203          cs <= 1;
  204          flag_done <= 1;
  205         end
  206       end
  207      else
  208       q1 <= q1;
  209     end
  210
  211   2 : flag_done <= 0;
  212  endcase
  213
  214  else if(state == 4)   //state == 4 进入页写操作
  215   case (s3)
  216    0:  begin  cs <= 0;  xie <= {command,addr,data}; s3 <=    1; end
  217
  218    1 :begin
  219      if(nege_dge)
  220       begin
  221        if(count < 40)
  222         begin
  223          q1 <= xie[39];
  224          count <= count + 1;
  225          xie <= {xie[38:0],xie[39]};
  226         end
  227        else
  228         begin
  229          count <= 0;
  230          s3 <= 2;
  231          cs <= 1;
  232          flag_done <= 1;
  233         end
  234       end
  235      else
  236       q1 <= q1;
  237     end
  238
  239   2 : flag_done <= 0;
  240
  241  endcase
  242
  243  else if(state == 5)   //state == 5 进入读个状态寄存器   操作
  244   case (s4)
  245    0:  begin  cs <= 0;  r_reg <= command; s4 <= 1; end
  246
  247    1 :begin
  248      if(nege_dge)
  249       begin
  250        if(count < 8)
  251         begin
  252          q1 <= r_reg[7];
  253          count <= count + 1;
  254          r_reg <= {r_reg[6:0],r_reg[7]};
  255         end
  256        else
  257         begin
  258          count <= 0;
  259          s4 <= 2;
  260         end
  261       end
  262      else
  263       q1 <= q1;
  264     end
  265
  266   2 : begin
  267       if(pose_dge)
  268        begin
  269         if(count < 8)
  270          begin
  271           count <= count + 1;
  272           d <= {d[14:0],q0};
  273          end
  274         else
  275          begin
  276           cs <= 1;
  277           count <= 0;
  278           if(!d[8]) //判断BUSY位忙不忙,   不忙进入下个状态
  279            begin
  280             flag_done <= 1;
  281             s4 <= 3;
  282            end
  283           else    //忙继续读个寄存器
  284            s4 <= 0;
  285          end
  286        end
  287       else
  288        begin
  289         s4 <= 2;
  290        end
  291      end
  292
  293   3 : flag_done <= 0;
  294
  295  endcase
  296
  297  end
  298
  299 endmodule

  图中显示的和我们的设计一样,发送的各个命令也是一样的,我们写入的是AA然后下班接收的也是AA。
关键词:FPGA芯片

版权与免责声明

凡本网注明“出处:维库电子市场网”的所有作品,版权均属于维库电子市场网,转载请必须注明维库电子市场网,https://www.dzsc.com,违反者本网将追究相关法律责任。

本网转载并注明自其它出处的作品,目的在于传递更多信息,并不代表本网赞同其观点或证实其内容的真实性,不承担此类作品侵权行为的直接责任及连带责任。其他媒体、网站或个人从本网转载时,必须保留本网注明的作品出处,并自负版权等法律责任。

如涉及作品内容、版权等问题,请在作品发表之日起一周内与本网联系,否则视为放弃相关权利。

广告
上传BOM文件: BOM文件
*公司名:
*联系人:
*手机号码:
QQ:
应用领域:

有效期:
OEM清单文件: OEM清单文件
*公司名:
*联系人:
*手机号码:
QQ:
有效期:

扫码下载APP,
一键连接广大的电子世界。

在线人工客服

买家服务:
卖家服务:

0571-85317607

客服在线时间周一至周五
9:00-17:30

关注官方微信号,
第一时间获取资讯。

建议反馈

联系人:

联系方式:

按住滑块,拖拽到最右边
>>
感谢您向阿库提出的宝贵意见,您的参与是维库提升服务的动力!意见一经采纳,将有感恩红包奉上哦!