加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 設計原理及思路
    • 設計架構(gòu)
    • 設計代碼
    • SignalTap 采集圖
  • 推薦器件
  • 相關推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

基于FPGA的內(nèi)存128M flash芯片控制器設計

04/19 15:10
2380
閱讀需 25 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

大俠好,歡迎來到FPGA技術(shù)江湖,江湖偌大,相見即是緣分。大俠可以關注FPGA技術(shù)江湖,在“闖蕩江湖”、"行俠仗義"欄里獲取其他感興趣的資源,或者一起煮酒言歡。

今天給大俠帶來基于FPGA的內(nèi)存128M flash芯片控制器設計,話不多說,上貨。

設計原理及思路

FLASH閃存?閃存的英文名稱是"Flash Memory",一般簡稱為"Flash",它屬于內(nèi)存器件的一種,是一種不揮發(fā)性( Non-Volatile )內(nèi)存。

閃存的物理特性與常見的內(nèi)存有根本性的差異:目前各類 DDRSDRAM 或者 RDRAM 都屬于揮發(fā)性內(nèi)存,只要停止電流供應內(nèi)存中的數(shù)據(jù)便無法保持,因此每次電腦開機都需要把數(shù)據(jù)重新載入內(nèi)存;閃存在沒有電流供應的條件下也能夠長久地保持數(shù)據(jù),其存儲特性相當于硬盤,這項特性正是閃存得以成為各類便攜型數(shù)字設備的存儲介質(zhì)的基礎。

本次設計使用的是 W25Q128FV 內(nèi)存128M的flash芯片,大家可以自己在官網(wǎng)上下載器件手冊。在這里為了方便,也提供給各位,需要使用的可以在公眾號內(nèi)部回復“W25Q128FV手冊資料”,各位可以根據(jù)實際項目應用靈活設計。

這款flash芯片的的存儲是一個扇區(qū)4KB,一個扇區(qū)可以存256個字,一個字是8位,一個塊是64KB,一共有256個塊組成一個存儲flash內(nèi)存。

在下面的講解中,將主要講實現(xiàn)一下字節(jié)的讀寫,本次設計使用的協(xié)議是SPI協(xié)議,這個芯片支持QSPI,雙端口SPI等。flash有三個狀態(tài)寄存器,每一個狀態(tài)寄存器的每一位都有各自的功能。大家可以具體的看器件手冊,首先給大家簡單的講一下第一個狀態(tài)寄存器。

這個狀態(tài)寄存器第一位是可讀、忙和不忙的標志位,大家可以在我們的設計中判斷芯片是否忙和不忙來是否進行下一步的操作。第二位是一個寫標志的信號,當寫使能打開的時候它為1,只有它為1的時候我們才可以進行寫,值得一說的不管是頁操作,還是擦除等命令后都會使這個標志位變成0。然后前面的命令算的上的是保護命令,具體有使用的邏輯功能。

在flash中,寫數(shù)據(jù)前先要擦除數(shù)據(jù)(想要擦除的地方),然后進行寫,如果沒有用過的flash芯片的話那么可以不用擦除,因為flash掉電不丟失數(shù)據(jù)。

設計思路大概是先讀出器件廠商和芯片ID,然后寫命令,寫使能打開,頁操作寫入數(shù)據(jù)(值得說明的是我們FLASH是新的所以沒進行擦除命令,建議擦除---關閉寫使能 -- 打開寫使能),然后讀第一個寄存器判斷芯片的第一位是否忙,不忙然后進行讀操作之后再數(shù)碼管上顯示出我們寫入的數(shù)據(jù)。

部分操作命令如下:

我們的發(fā)送格式為在時鐘的上升沿寫入命令,在時鐘的下降沿讀出命令,用的是標準的SPI協(xié)議,端口IO0,和IO1,都是單向的。

寫使能時序:

讀使能時序:

其他的時序在這里就不分別列舉出來了,大家可以參考器件手冊。

設計架構(gòu)

本次的設計是用一個FSM控制器來控制發(fā)送什么命令,flash模塊判斷FSM發(fā)送過來的state信號來選擇應該執(zhí)行什么操作,當命令寫入或者讀出后,會發(fā)送一個flag_done命令,這個命令讓我們判斷上個指令是否完成,如果完成后FAM將發(fā)送下一個命令??傮w架構(gòu)圖如下:

設計代碼

頂層模塊 flash_top 代碼:

module flash_top(clk , rst_n, q0,  q1, sclk, cs, seg, sel);
  input clk, rst_n;  input q0;  output q1;  output  sclk;  output  cs;  output [5:0] sel;  output  [7:0] seg;  wire [7:0] command;  wire [23:0] addr;  wire [2:0] state;  wire [7:0] data;  wire [23:0] show_data;  wire flag_done;      flash flash_dut(    .clk(clk) ,    .rst_n(rst_n),    .q0(q0),    .q1(q1),    .sclk(sclk),    .cs(cs),    .command(command),    .addr(addr),    .state(state),    .data(data),    .show_data(show_data),    .flag_done(flag_done)  );    fsm fsm_dut(    .clk(clk),    .rst_n(rst_n),    .flag_done(flag_done),    .command(command),    .addr(addr),     .state(state),    .data(data)  );    seg seg_dut(    .clk(clk),    .rst_n(rst_n),    .sel(sel),    .seg7(seg),    .data_in(show_data)  );

endmodule?

設計模塊 fsm?代碼:

module fsm(clk, rst_n, flag_done, command, addr, state, data);
  input clk, rst_n;  input flag_done;   //輸入標志位  output reg [7:0] command;   //輸出命令  output reg [23:0] addr;     //輸出地址  output reg [2:0] state;    //輸出狀態(tài)模式  output reg [7:0] data;     //輸出寫入數(shù)據(jù)    reg [2:0] state_s;  reg [20:0] count;  always @ (posedge clk)    if(!rst_n)      begin        state_s <= 0;        data <= 8'd0;        addr <= 24'd0;        command <= 8'd0;        state <= 0;        count <= 0;      end    else      case (state_s)        0  :  begin              if(count < 200)    //延遲一段時間                count <= count + 1;              else                begin       //發(fā)送讀廠商ID的命令                  command <= 8'h90;                  addr <= 24'd0;                  state <= 1;                  count <= 1;                end              if(flag_done)   //檢查是否完成                state_s <= 1;            end                1  :  begin              if(count < 200)  //延遲一段時間                count <= count + 1;              else                begin    //寫使能                  command <= 8'h06;                  state <= 3;                  count <= 0;                end              if(flag_done)  //檢查是否完成                state_s <= 2;            end                2  :  begin              if(count < 200)   //延遲一段時間                count <= count + 1;              else                begin    //頁操作                  command <= 8'h02;                  addr <= 24'd0;                  state <= 4;                  data <= 8'haa;                  count <= 0;                end              if(flag_done)   //檢查是否完成                state_s <= 3;            end                3  :  begin              if(count < 200)   //延遲一段時間                count <= count + 1;              else                begin    //讀寄存器                  command <= 8'h05;                  count <= 0;                  state <= 5;                end              if(flag_done)   //檢查是否完成                state_s <= 4;            end                    4  :  begin               if(count < 200)    //延遲一段時間                count <= count + 1;              else                    begin     //讀數(shù)據(jù)                  command <= 8'h03;                  addr <= 24'd0;                  state <= 2;                  count <= 0;                end            end                default: state_s <= 0;      endcase      endmodule

中間模塊flash代碼:

module flash (clk , rst_n, q0,  q1, sclk, cs, command, addr, state, data, show_data, flag_done);    input clk, rst_n;          input q0;  output reg q1;  output reg sclk;  output reg cs;  input [7:0] command;      //輸入命令  input [23:0] addr;      //地址  input [2:0] state;      //狀態(tài)  input [7:0] data;        //數(shù)據(jù)  output reg [23:0] show_data;   //顯示  output reg flag_done;    //命令完成標志
  reg [5:0] count;  reg [5:0] cnt;  reg [31:0] temp;  reg [15:0] d;  reg [5:0] count_s;  reg [7:0] dou;  reg [39:0] xie;  reg [7:0] r_reg;    always @ (posedge clk)    if(!rst_n)      begin        sclk <= 1;        count_s <= 0;      end    else if(cs)      begin        count_s <= 0;        sclk <= 1;      end    else      begin          if(count_s == 25 - 1)   //產(chǎn)生1M的時鐘            begin              count_s <= 0;              sclk <= ~sclk;            end        else          count_s <= count_s + 1;      end        reg [1:0] signle_s;    //邊沿檢測電路  always @ (posedge clk or negedge rst_n)    if(!rst_n)      begin        signle_s <= 2'b11;      end    else      begin        signle_s[0] <= sclk;        signle_s[1] <= signle_s[0];      end    assign pose_dge = signle_s[0] && ~signle_s[1];  //上升沿脈沖  assign nege_dge = ~signle_s[0] && signle_s[1];  //下降沿脈沖     reg [1:0] s;  reg [1:0] s1,s2,s3,s4;  always @ (posedge clk or negedge rst_n)    if(!rst_n)      begin        q1 <= 0;        count <= 0;         cs <= 1;        temp <= 0;        d <= 0;        cnt <= 0;        s <= 0;        s1 <= 0;        s2 <= 0;        s3 <= 0;        flag_done <= 0;        s4  <= 0;      end    else      begin      if (state == 1)      //state == 1進入讀芯片的廠商和ID        case (s)          0:  begin  cs <= 0;  temp <= {command,addr}; s <= 1; end                  1  : begin              if(nege_dge)    //下降沿發(fā)送數(shù)據(jù)                begin                  if(count < 32)                      begin                      q1 <= temp[31];                      count <= count + 1;                      temp <= {temp[30:0],temp[31]};                    end                  else                     begin                      count <= 0;                      s <= 2;                    end                end              else                q1 <= q1;            end                      2  :  begin              if(pose_dge)    //上升沿采集數(shù)據(jù)                begin                  if(count < 16)                    begin                      count <= count + 1;                      d <= {d[14:0],q0};                    end                  else                    begin                      s <= 3;                      cs <= 1;                      count <= 0;                      flag_done <= 1;                      show_data <= d;                    end                end              else                begin                  s <= 2;                end            end                        3  :   begin                flag_done <= 0;              end                    endcase              else if(state == 2)      //state == 2進入讀模式      case (s1)        0:  begin  cs <= 0;  temp <= {command,addr}; s1 <= 1; end              1  :begin            if(nege_dge)              begin                if(count < 32)                  begin                    q1 <= temp[31];                    count <= count + 1;                    temp <= {temp[30:0],temp[31]};                  end                else                   begin                    count <= 0;                    s1 <= 2;                  end              end            else              q1 <= q1;          end                  2  :  begin            if(pose_dge)              begin                if(count < 8)                  begin                    count <= count + 1;                    dou <= {dou[6:0],q0};                    s1 <= 2;                  end                else                  begin                    s1 <= 3;                    cs <= 1;                    count <= 0;                    flag_done <= 1;                    show_data <= dou;                  end              end            else              begin                s1 <= 2;              end          end                    3  :   begin              flag_done <= 0;            end      endcase          else if(state == 3)      //state == 3 進入寫使能模式      case (s2)        0:  begin  cs <= 0;  temp <= {command,addr}; s2 <= 1; end              1  :begin            if(nege_dge)              begin                if(count < 8)                  begin                    q1 <= temp[31];                    count <= count + 1;                    temp <= {temp[30:0],temp[31]};                  end                else                   begin                    count <= 0;                    s2 <= 2;                    cs <= 1;                    flag_done <= 1;                  end              end            else              q1 <= q1;          end            2  : flag_done <= 0;    endcase          else if(state == 4)      //state == 4 進入頁寫操作      case (s3)        0:  begin  cs <= 0;  xie <= {command,addr,data}; s3 <= 1; end              1  :begin            if(nege_dge)              begin                if(count < 40)                  begin                    q1 <= xie[39];                    count <= count + 1;                    xie <= {xie[38:0],xie[39]};                  end                else                   begin                    count <= 0;                    s3 <= 2;                    cs <= 1;                    flag_done <= 1;                  end              end            else              q1 <= q1;          end            2  : flag_done <= 0;          endcase          else if(state == 5)      //state == 5 進入讀第一個狀態(tài)寄存器操作      case (s4)        0:  begin  cs <= 0;  r_reg <= command; s4 <= 1; end              1  :begin            if(nege_dge)              begin                if(count < 8)                  begin                    q1 <= r_reg[7];                    count <= count + 1;                    r_reg <= {r_reg[6:0],r_reg[7]};                  end                else                   begin                    count <= 0;                    s4 <= 2;                  end              end            else              q1 <= q1;          end            2  :  begin              if(pose_dge)                begin                  if(count < 8)                    begin                      count <= count + 1;                      d <= {d[14:0],q0};                    end                  else                    begin                      cs <= 1;                      count <= 0;                      if(!d[8]) //判斷BUSY位忙不忙,不忙進入下個狀態(tài)                        begin                          flag_done <= 1;                          s4 <= 3;                        end                      else    //忙繼續(xù)讀第一個寄存器                        s4 <= 0;                    end                end              else                begin                  s4 <= 2;                end            end            3  : flag_done <= 0;          endcase          end    endmodule 

數(shù)碼管模塊seg代碼:

module seg(clk,rst_n,sel,seg7,data_in);
  input clk;  input rst_n;  input  [23:0] data_in;  output reg [5:0] sel;  output reg [7:0] seg7;    parameter s0 = 3'b000;  parameter s1 = 3'b001;  parameter s2 = 3'b010;  parameter s3 = 3'b011;  parameter s4 = 3'b100;  parameter s5 = 3'b101;    `define T1ms  50_000  //`define T1ms  5  reg [15:0] count;  reg  flag;  always @ (posedge clk or negedge rst_n)    if(!rst_n)      begin        count <= 16'd0;        flag <= 1;      end    else      if(count == (`T1ms / 2 - 1))        begin          count <= 16'd0;          flag <= ~ flag;        end      else        begin          count <= count + 1'b1;        end    reg [2:0] state;   reg [3:0] num;    always @ (posedge flag or negedge rst_n)    if(!rst_n)      begin        sel <= 3'b0;        state <= 3'b0;        num <= 4'b0;      end    else      begin        case (state)          s0:begin              state <= s1;              sel <= 6'b011111;              num <= data_in[23:20];            end          s1:begin              state <= s2;              sel <= 6'b101111;              num <= data_in[19:16];            end          s2:begin              state <= s3;              sel <= 6'b110111;              num <= data_in[15:12];            end          s3:begin                            state <= s4;              sel <= 6'b111011;              num <= data_in[11:8];                            end          s4:begin              state <= s5;              sel <= 6'b111101;              num <= data_in[7:4];            end          s5:begin              state <= s0;              sel <= 6'b111110;              num <= data_in[3:0];            end          default:state <= s0;        endcase      end  
  always @ (*)      begin        case (num)          0:seg7 = 8'b1100_0000;          1:seg7 = 8'b1111_1001;          2:seg7 = 8'b1010_0100;          3:seg7 = 8'b1011_0000;          4:seg7 = 8'b1001_1001;          5:seg7 = 8'b1001_0010;          6:seg7 = 8'b1000_0010;          7:seg7 = 8'b1111_1000;          8:seg7 = 8'b1000_0000;          9:seg7 = 8'b1001_0000;          10:seg7 = 8'b1000_1000;          11:seg7 = 8'b1000_0011;          12:seg7 = 8'b1100_0110;          13:seg7 = 8'b1010_0001;          14:seg7 = 8'b1000_0110;          15:seg7 = 8'b1000_1110;          default:;        endcase      endendmodule

SignalTap 采集圖

圖中顯示的和我們的設計一樣,發(fā)送的各個命令也是一樣的,我們寫入的是AA然后接收的也是AA,設計正確。

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風險等級 參考價格 更多信息
EPM1270T144I5N 1 Altera Corporation Flash PLD, 10ns, 980-Cell, CMOS, PQFP144, 22 X 22 MM, 0.50 MM PITCH, LEAD FREE, TQFP-144

ECAD模型

下載ECAD模型
$145.11 查看
10M08SCU169I7G 1 Intel Corporation Field Programmable Gate Array, 8000-Cell, CMOS, PBGA169, 11 X 11 MM, 0.80 MM PITCH, ROHS COMPLIANT, UBGA-169

ECAD模型

下載ECAD模型
$28.99 查看
EPM570T100I5N 1 Altera Corporation Flash PLD, 8.7ns, 440-Cell, CMOS, PQFP100, 16 X 16 MM, 0.50 MM PITCH, LEAD FREE, TQFP-100

ECAD模型

下載ECAD模型
$21.73 查看

相關推薦

電子產(chǎn)業(yè)圖譜

任何技術(shù)的學習就好比一個江湖,對于每一位俠客都需要不斷的歷練,從初入江湖的小白到歸隱山林的隱世高人,需要不斷的自我感悟自己修煉,讓我們一起仗劍闖FPGA乃至更大的江湖。