ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

16经典的SPI Flash的扇区擦除flash_se功能

2020-05-28 21:51:59  阅读:419  来源: 互联网

标签:begin sck 16 flash 扇区 rst sck1 sck0 Begin


一设计功能

对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%就是记录整理勒。画好图纸比敲代码重要得多,代码只不过是思路的描述。

 

标签:begin,sck,16,flash,扇区,rst,sck1,sck0,Begin
来源: https://www.cnblogs.com/Xwangzi66/p/12984197.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有