一设计功能

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

16经典的SPI Flash的扇区擦除flash_se功能的更多相关文章

  1. RTT下spi flash+elm fat文件系统移植小记

    背景: MCU:STM32F207 SPI flash: Winbond W25Q16BV OS: RTT V1.1.1 bsp: STM32F20x 1 将spi_core.c,spi_dev.c及 ...

  2. spi flash 操作

    W25Q16V 是华邦出的一颗 spi flash. 25系列是比较通用的一个系列. 后面的数字 16 跟容量有关, 16 表示 16Mbits, 相当于 2MB. 与此类似的还有 W25Q128V ...

  3. 基于FPGA的SPI FLASH控制器设计

    1.SPI FLASH的基本特征 本文实现用FPGA来设计SPI FLASH,FLASH型号为W25Q128BV.支持3种通信方式,SPI.Dual SPI和Quad SPI.FLASH的存储单元无法 ...

  4. Arduino SPI + SPI Flash芯片W25Q80BV

    W25Q80BV是台湾华邦电子(Winbond)生产的8M-bit串行flash芯片.主要特性有: 工作电压:2.5 ~ 3.6 V 功耗:读写(active)时4mA,低功耗(power-down) ...

  5. RTThread DFS文件系统使用: 基于使用SFUD驱动的SPI FLASH之上的ELM FATFS文件系统

    参考博文: 博文很长,但是实际要操作的步骤没几下. http://m.elecfans.com/article/730878.html  为了防止几年后文章链接找不到,我把文章复制过来了 /***** ...

  6. OpenRisc-32-ORPSoC烧写外部spi flash

    引言 经过前面的分析和介绍,我们对ORPSoC的启动过程(http://blog.csdn.net/rill_zhen/article/details/8855743)和 ORpSoC的debug子系 ...

  7. SPI Flash(W25Q16DV) 驱动

    大体上可分为以下几个部分: 1.注册设备驱动 spi_register_driver 2.分配 mtd_info 结构体 3.配置 mtd_info 结构体 4.注册 mtd_info 结构体 构建 ...

  8. SPI Flash(W25Q16DV) 基本操作

    读取厂家\设备 ID 发送 90H 指令,再发送 00h 的地址,然后接收即可. 代码如下: void SPIFlashReadID(int *pMID, int *pDID) { SPIFlash_ ...

  9. (电工基地笔记)Vivado固化至SPI Flash

    如果从头开始做SPI Flash固化是有一些麻烦的,要在完成综合之后,打开 synthesized Design (图) (图) 然后在synthesized Design打开状态下,选择Tools- ...

随机推荐

  1. 06.python语法入门--与用户交互、运算符

    与用户交互 输入 input    # python2与python3的区别        '''python3'''    # 将获取到的用户输入赋值给变量名res    res = input(' ...

  2. Solution -「ARC 101E」「AT 4352」Ribbons on Tree

    \(\mathcal{Description}\)   Link.   给定一棵 \(n\) 个点的树,其中 \(2|n\),你需要把这些点两两配对,并把每对点间的路径染色.求使得所有边被染色的方案数 ...

  3. python3发邮件脚本

    官方文档中建议保存token,且token是每2小时更新一次. 所以token先保存在本地token.txt文件夹中,设定计划任务每1小时删除一下token.txt.虽然造成了浪费,对于发消息不多的人 ...

  4. Python中读写文件三部曲

    写入文件:要把第二个参数 'r' 改成 'w' ,表示write,即以写入的模式打开文件;  往文件中写入内容,使用write()函数. 例子如下:注意 'w' 写入模式会暴力清空掉原有文件,然后再写 ...

  5. python中try...excpet多种使用方法

    1 print('\n欢迎使用除法计算器!\n') 2 3 while True: 4 try: 5 x = input('请你输入被除数:') 6 y = input('请你输入除数:') 7 z ...

  6. 记一次对ctf试题中对git文件泄露的漏洞的挖掘

    拿到题,先f12查看代码 发现情况直接进行访问 最后试了发现flag.js可以访问  服务器返回了如下图所示的乱码 很显然有可能是git泄露  话不多说,直接利用https://github.com/ ...

  7. 2、CPU是怎么实现运算的 ?

    我先来了解一下芯片构造,芯片由晶体管组成的.晶体管组成逻辑运算与或非电路. P型半导体的"P"表示正电的意思,取自英文Positive的第一个字母. N型半导体的"N&q ...

  8. 决策树CART回归树——算法实现

    决策树模型 选择最好的特征和特征的值进行数据集划分 根据上面获得的结果创建决策树 根据测试数据进行剪枝(默认没有数据的树分支被剪掉) 对输入进行预测 模型树 import numpy as np de ...

  9. Qt:QThread

    0.说明 QThread提供了一种与平台无关的线程管理方法. 一个QThread对象管理一个线程.QThread通过run()方法启动线程.默认情况下,run()方法通过exec()启动一个事件循环, ...

  10. Vue 常用命令

    创建全局脚手架 npm install -g @vue/cli-init # `vue init` 的运行效果将会跟 `vue-cli@2.x` 相同 vue init webpack my-proj ...