一设计功能

对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. 搭建 NFS 服务 & 实时同步

    今日内容 NFS简介 实现 NFS 文件同步功能 NFS 配置详解 统一用户 搭建 web 服务 NFS 实现文件共享 内容详细 1.NFS 简介 1.1 介绍 实现多台 web 服务器可以共享数据资 ...

  2. Solution -「ZJOI 2020」「洛谷 P6631」序列

    \(\mathcal{Description}\)   Link.   给定一个长为 \(n\) 的非负整数序列 \(\lang a_n\rang\),你可以进行如下操作: 取 \([l,r]\),将 ...

  3. .NET 云原生架构师训练营(权限系统 代码实现 WebApplication)--学习笔记

    目录 开发任务 代码实现 开发任务 DotNetNB.Security.Core:定义 core,models,Istore:实现 default memory store DotNetNB.WebA ...

  4. 如何在TypeScript/JavaScript项目里引入MD5校验和

    摘要:MD5校验和则是其中一种数学算法,通常是使用工具对文件计算得出的一组32 个字符的十六进制字母和数字. 本文分享自华为云社区<TypeScript/JavaScript项目里如何做MD5校 ...

  5. [LeetCode]1464. 数组中两元素的最大乘积

    给你一个整数数组 nums,请你选择数组的两个不同下标 i 和 j,使 (nums[i]-1)*(nums[j]-1) 取得最大值. 请你计算并返回该式的最大值. 示例 1: 输入:nums = [3 ...

  6. NSSCTF-error

    打开网页出现一个输入框,尝试使用127.0.0.1发现只是回显我们输入的内容 尝试进行注入,输入数字1会回显没有提示......,order by进行判断列数,得到有三列 接着就是正常注入的思路,使用 ...

  7. Vue UI API简单笔记

    VUE UI 目录 VUE UI 一 移动端常用UI组件库 二 PC端常用UI组件库 三 ElementUI组件按需引入 一 移动端常用UI组件库 Vant http://vant-contrib.g ...

  8. 太骚了,用Excel玩机器学习

    最近发现了一个好玩的Python库,它可以将训练好的机器学习模型转换为Java.C.JavaScript.Go.Ruby,VBA 本地代码,可以让连Python和机器学习一无所知的同学也能感受预测的神 ...

  9. 浅谈MySQL日志文件|手撕MySQL|对线面试官

    关注微信公众号[程序员白泽],进入白泽的知识分享星球 前言 上周五面试了字节的第三面,深感数据库知识的重要,我也意识到在平时的学习中,自己对于数据库的学习较为薄弱.甚至在有过一定实习经验之后,依旧因为 ...

  10. CDH6.2.0离线安装(详细)

    目录 01 准备工作 02 环境配置 03 CDH安装 报错 01 准备工作 官网地址下载页面:https://www.cloudera.com/downloads/cdh.html,现在下载好像需要 ...