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

描述

设计背景:

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。然后前面的命令算的上的是保护命令,具体有使用的逻辑功能。FPGA

在flash中我们写数据前先要擦除数据你想擦除的地方,然后进行写,如果没有用过的flash芯片的话那么可以不用擦除。毕竟我们的flash可是掉电不丢失数据的。

我的设计思路是这样的我们先读出我们的器件厂商,和芯片ID,然后记性写命令,写使能打开,页操作写入数据(值得说明的是我们FLASH是新的所以没进行擦除命令,建议擦除---关闭写使能 -- 打开写使能),然后读第一个寄存器判断芯片的第一位是否忙,不忙然后进行读操作之后再数码管上显示出我们写入的数据。

部分操作命令如下

FPGA

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

写使能时序:

FPGA

    读使能时序:

        FPGA

    之后别的时序我们将不展示,大家可以参考器件手册。

设计架构图:

我们的设计是用一个FSM控制器来控制发送什么命令,flash模块判断FSM发送过来的state信号来选择应该执行什么操作,当命令写入或者读出后,会发送一个flag_done命令,这个命令让我们判断上个指令是否完成,如果完成后FAM将发送下一个命令。

FPGA

设计代码:

设计模块

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;  //输出状态模式

output reg [7:0] data;     //输出写入数据

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

SignalTap 采集图

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

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分