一设计功能

对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. 5、架构--Nginx、搭建超级玛丽游戏

    笔记 1.晨考 1.NFS共享文件步骤 - 服务端 [root@backup ~]# yum install nfs-utils rpcbind -y [root@backup ~]# mkdir / ...

  2. Note/Solution -「洛谷 P6466」分散层叠算法

    \(\mathcal{Description}\)   Link.   给定 \(m\) 个长度为 \(n\) 的有严格升序且不包含重复元素的序列 \(a_1,a_2,\cdots,a_m\),\(q ...

  3. Solution -「LOJ #6485」 LJJ 学二项式定理

    \(\mathcal{Description}\)   Link.   给定 \(n,s,a_0,a_1,a_2,a_3\),求: \[\sum_{i=0}^n\binom{n}is^ia_{i\bm ...

  4. netty系列之:channel,ServerChannel和netty中的实现

    目录 简介 channel和ServerChannel netty中channel的实现 AbstractChannel和AbstractServerChannel LocalChannel和Loca ...

  5. 异常Java

    异常 1.什么是异常 异常指程序运行过程中出现的不期而至的各种状况,如:文件找不到.网络连接失败等 异常发生在程序运行期间,它影响了正常的程序执行流程 public class Demo01 { pu ...

  6. NPM保资源管理工具

    一.简介 什么是NPM NPM全称Node Package Manager,是Node.js包管理工具,是全球最大的模块生态系统,里面所有的模块都是开源免费的:也是Node.js的包管理工具,相当于前 ...

  7. 在 .NET 平台使用 ReflectionDynamicObject 优化反射调用代码

    基于封装的原则,API 的设计者会将部分成员(属性.字段.方法等)隐藏以保证健壮性.但总有需要直接访问这些私有成员的情况. 为了访问一个类型的私有成员,除了更改 API 设计还有就是使用反射技术: p ...

  8. 单片机中volatile的应用

    01.简述 一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了.精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使 ...

  9. 5款开源BI系统倾力推荐,企业信息化的利器

    如今的企业都在选择开源BI系统,提升企业信息化的水平.那么开源BI系统到底该如何选择?在目前的百度上面有着许许多多类似的内容,本文就整理了其中优秀的5款工具,帮助大家选择合适的软件. 1.Smartb ...

  10. 从菜鸟到高手, HMS Core图像分割服务教你如何在复杂背景里精细抠图

    2021年以来,自动驾驶赛道进入爆发期,该行业成为大厂以及初创企业的必争之地.其中众多公司都采用了计算机视觉作为自动驾驶的技术底座,通过图像分割技术,汽车才能够有效理解道路场景,分清楚哪里是路,哪里是 ...