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

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

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

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

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

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

設(shè)計(jì)原理及思路

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

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

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

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

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

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

在flash中,寫數(shù)據(jù)前先要擦除數(shù)據(jù)(想要擦除的地方),然后進(jìn)行寫,如果沒(méi)有用過(guò)的flash芯片的話那么可以不用擦除,因?yàn)閒lash掉電不丟失數(shù)據(jù)。

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

部分操作命令如下:

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

寫使能時(shí)序:

讀使能時(shí)序:

其他的時(shí)序在這里就不分別列舉出來(lái)了,大家可以參考器件手冊(cè)。

設(shè)計(jì)架構(gòu)

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

設(shè)計(jì)代碼

頂層模塊 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?

設(shè)計(jì)模塊 fsm?代碼:

module fsm(clk, rst_n, flag_done, command, addr, state, data);
  input clk, rst_n;  input flag_done;   //輸入標(biāo)志位  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)    //延遲一段時(shí)間                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)  //延遲一段時(shí)間                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)   //延遲一段時(shí)間                count <= count + 1;              else                begin    //頁(yè)操作                  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)   //延遲一段時(shí)間                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)    //延遲一段時(shí)間                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;    //命令完成標(biāo)志
  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的時(shí)鐘            begin              count_s <= 0;              sclk <= ~sclk;            end        else          count_s <= count_s + 1;      end        reg [1:0] signle_s;    //邊沿檢測(cè)電路  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進(jìn)入讀芯片的廠商和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進(jìn)入讀模式      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 進(jìn)入寫使能模式      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 進(jìn)入頁(yè)寫操作      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 進(jìn)入讀第一個(gè)狀態(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位忙不忙,不忙進(jìn)入下個(gè)狀態(tài)                        begin                          flag_done <= 1;                          s4 <= 3;                        end                      else    //忙繼續(xù)讀第一個(gè)寄存器                        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 采集圖

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

推薦器件

更多器件
器件型號(hào) 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊(cè) ECAD模型 風(fēng)險(xiǎn)等級(jí) 參考價(jià)格 更多信息
LFE3-70EA-8FN484C 1 Lattice Semiconductor Corporation Field Programmable Gate Array, 500MHz, 67000-Cell, PBGA484, 23 X 23 MM, LEAD FREE, FPBGA-484

ECAD模型

下載ECAD模型
$73.57 查看
XC6SLX9-2CSG225C 1 AMD Xilinx Field Programmable Gate Array, 715 CLBs, 667MHz, 9152-Cell, CMOS, PBGA225, 13 X 13 MM, 0.80 MM PITCH, LEAD FREE, BGA-225

ECAD模型

下載ECAD模型
$19.67 查看
A3P1000-FGG144I 1 Microsemi FPGA & SoC Field Programmable Gate Array, 1000000 Gates, CMOS, PBGA144, 1 MM PITCH, GREEN, FBGA-144
$133.31 查看

相關(guān)推薦

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

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