07_flash全擦除实验

07_flash全擦除实验

  • 1. SPI 协议
    • 1.1 SPI 协议
    • 1.2 SPI 物理层
    • 1.3 SPI 协议层
      • 1.3.1 SPI 通讯模式时序图
      • 1.3.2 CPHA=0 时的 SPI 通讯模式
      • 1.3.3 CPHA=1 时的 SPI 通讯模式
  • 2. 实验目标
  • 3. SPI-Flash 芯片
    • 3.1 硬件资源
    • 3.2 板载 Flash 原理图
    • 3.3 操作时序
      • 3.3.1 全擦除时序
      • 3.3.2 写使能时序
      • 3.3.3 串行输入时序图
  • 4. 模块框图
  • 5. 波形图
  • 6. RTL
    • 6.1 flash_be_ctrl
    • 6.2 spi_flash_be
  • 7. Testbench
    • 7.1 tb_flash_be_ctrl
    • 7.2 tb_spi_flash_be

1. SPI 协议

1.1 SPI 协议

在这里插入图片描述
在这里插入图片描述

1.2 SPI 物理层

对于 SPI 协议的物理层,需要讲解的就是 SPI 通讯设备的连接方式和设备引脚的功能描述。SPI 通讯设备的通讯模式是主从通讯模式,通讯双方有主从之分,根据从机设备的个数,SPI 通讯设备之间的连接方式可分为一主一从和一主多从。
一主一从 SPI 通讯设备连接图
在这里插入图片描述
一主多从 SPI 通讯设备连接图
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

1.3 SPI 协议层

1.3.1 SPI 通讯模式时序图

在这里插入图片描述
CPOL = 0,空闲状态时 SCK 为低电平
CPOL = 1,空闲状态时SCK 为高电平
CPHA = 0,数据采样是在 SCK 时钟的奇数边沿,偶数跟新。
CPHA = 1,数据采样是在 SCK 时钟的偶数边沿,奇数跟新。

1.3.2 CPHA=0 时的 SPI 通讯模式

CPHA = 0,数据采样是在 SCK 时钟的奇数边沿,偶数跟新。
在这里插入图片描述

1.3.3 CPHA=1 时的 SPI 通讯模式

CPHA = 1,数据采样是在 SCK 时钟的偶数边沿,奇数跟新。
在这里插入图片描述

2. 实验目标

事先向 Flash 芯片中烧录流水灯程序,FPGA 上电执行流水灯程序,下载 Flash 芯片全擦除程序到 FPGA 内部 SRAM 并执行,擦除 Flash 芯片中烧录的流水灯程序,FPGA 重新上电后,无程序执行。

3. SPI-Flash 芯片

3.1 硬件资源

Flash 型号为 W25Q16 存储容量为 16Mbit(2M 字节)
在这里插入图片描述

3.2 板载 Flash 原理图

在这里插入图片描述

3.3 操作时序

3.3.1 全擦除时序

全擦除(Bulk Erase)操作,简称 BE,操作指令为 8’b1100_0111(C7h)
在这里插入图片描述
全擦除时序
在这里插入图片描述

3.3.2 写使能时序

写使能(Write Enable)指令,简称 WREN,操作指令为 8’b0000_0110(06h)。
在这里插入图片描述
写使能指令详细介绍及操作时序
在这里插入图片描述

3.3.3 串行输入时序图

在这里插入图片描述
SPI-Flash 是取 12.5MHZ 来算的。一个时钟周期是 80ns , 则传输8bit 需要 640ns。
还需要注意 t_slch 延迟,>=5ns ,在这里为了方便取 640ns。

全擦除 要把 所有的bite 位 变成1 (BE操作变成 全部为 1 ) 在此时前要有一个写使能指令。
实现全擦除需要下面六个步骤:

  1. 写使能
  2. 器件进入到一个写锁存的状态
  3. 全擦除写入 BE
  4. 写入的时候 拉低 s 片选信号
  5. 写入完成拉高s
  6. 完成后 等待一定的周期 完成

4. 模块框图

在这里插入图片描述

5. 波形图

板卡输入的是50MHZ,而协议是基于12.5MHZ 在这里需要注意。
640ns 则需要32个 50MHZ 的时钟周期。SPI 为 0/0 模式。
当cnt_byte == 1 并且 cnt_sck == 2 因为 0/0 模式下 是偶数沿进行的跟新
奇数沿采样 偶数沿进行数据的跟新
大概波形

计数器规范
在这里插入图片描述
详细波形
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6. RTL

6.1 flash_be_ctrl

`timescale  1ns/1ns
module  flash_be_ctrl
(input   wire            sys_clk     ,   //系统时钟,频率50MHzinput   wire            sys_rst_n   ,   //复位信号,低电平有效input   wire            key         ,   //按键输入信号output  reg             cs_n        ,   //片选信号output  reg             sck         ,   //串行时钟output  reg             mosi            //主输出从输入数据
);//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************////parameter define
parameter   IDLE    =   4'b0001 ,   //初始状态WR_EN   =   4'b0010 ,   //写状态DELAY   =   4'b0100 ,   //等待状态BE      =   4'b1000 ;   //全擦除状态
parameter   WR_EN_INST  =   8'b0000_0110,   //写使能指令BE_INST     =   8'b1100_0111;   //全擦除指令//reg   define
reg     [2:0]   cnt_byte;   //字节计数器
reg     [3:0]   state   ;   //状态机状态
reg     [4:0]   cnt_clk ;   //系统时钟计数器
reg     [1:0]   cnt_sck ;   //串行时钟计数器
reg     [2:0]   cnt_bit ;   //比特计数器//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************////cnt_clk:系统时钟计数器,用以记录单个字节
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_clk  <=  5'd0;else    if(state != IDLE)cnt_clk  <=  cnt_clk + 1'b1;//cnt_byte:记录输出字节个数和等待时间
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_byte    <=  3'd0;else    if((cnt_clk == 5'd31) && (cnt_byte == 3'd6))cnt_byte    <=  3'd0;else    if(cnt_clk == 31)cnt_byte    <=  cnt_byte + 1'b1;//cnt_sck:串行时钟计数器,用以生成串行时钟
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_sck <=  2'd0;else    if((state == WR_EN) && (cnt_byte == 1'b1))cnt_sck <=  cnt_sck + 1'b1;else    if((state == BE) && (cnt_byte == 3'd5))cnt_sck <=  cnt_sck + 1'b1;//cs_n:片选信号
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)cs_n    <=  1'b1;else    if(key == 1'b1)cs_n    <=  1'b0;else    if((cnt_byte == 3'd2) && (cnt_clk == 5'd31) && (state == WR_EN))cs_n    <=  1'b1;else    if((cnt_byte == 3'd3) && (cnt_clk == 5'd31) && (state == DELAY))cs_n    <=  1'b0;else    if((cnt_byte == 3'd6) && (cnt_clk == 5'd31) && (state == BE))cs_n    <=  1'b1;//sck:输出串行时钟
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)sck <=  1'b0;else    if(cnt_sck == 2'd0)sck <=  1'b0;else    if(cnt_sck == 2'd2)sck <=  1'b1;//cnt_bit:高低位对调,控制mosi输出
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_bit <=  3'd0;else    if(cnt_sck == 2'd2)cnt_bit <=  cnt_bit + 1'b1;//state:两段式状态机第一段,状态跳转
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)state   <=  IDLE;elsecase(state)IDLE:   if(key == 1'b1)state   <=  WR_EN;WR_EN:  if((cnt_byte == 3'd2) && (cnt_clk == 5'd31))state   <=  DELAY;DELAY:  if((cnt_byte == 3'd3) && (cnt_clk == 5'd31))state   <=  BE;BE:     if((cnt_byte == 3'd6) && (cnt_clk == 5'd31))state   <=  IDLE;default:    state   <=  IDLE;endcase//mosi:两段式状态机第二段,逻辑输出
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)mosi    <=  1'b0;else    if((state == WR_EN) && (cnt_byte == 3'd2))mosi    <=  1'b0;else    if((state == BE) && (cnt_byte == 3'd6))mosi    <=  1'b0;else    if((state == WR_EN) && (cnt_byte == 3'd1) && (cnt_sck == 5'd0))mosi    <=  WR_EN_INST[7 - cnt_bit];    //写使能指令else    if((state == BE) && (cnt_byte == 3'd5) && (cnt_sck == 5'd0))mosi    <=  BE_INST[7 - cnt_bit];       //全擦除指令endmodule

6.2 spi_flash_be

`timescale  1ns/1ns
module  spi_flash_be
(input   wire    sys_clk     ,   //系统时钟,频率50MHzinput   wire    sys_rst_n   ,   //复位信号,低电平有效input   wire    pi_key      ,   //按键输入信号output  wire    cs_n        ,   //片选信号output  wire    sck         ,   //串行时钟output  wire    mosi            //主输出从输入数据
);//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   CNT_MAX =   20'd999_999;    //计数器计数最大值//wire  define
wire    po_key  ;//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------- key_filter_inst -------------
key_filter
#(.CNT_MAX    (CNT_MAX    )   //计数器计数最大值
)
key_filter_inst
(.sys_clk    (sys_clk    ),  //系统时钟,频率50MHz.sys_rst_n  (sys_rst_n  ),  //复位信号,低电平有效.key_in     (pi_key     ),  //按键输入信号.key_flag   (po_key     )   //消抖后信号
);//------------- flash_be_ctrl_inst -------------
flash_be_ctrl  flash_be_ctrl_inst
(.sys_clk    (sys_clk    ),  //系统时钟,频率50MHz.sys_rst_n  (sys_rst_n  ),  //复位信号,低电平有效.key        (po_key     ),  //按键输入信号.sck        (sck        ),  //片选信号.cs_n       (cs_n       ),  //串行时钟.mosi       (mosi       )   //主输出从输入数据
);endmodule

7. Testbench

做测试时候需要额外添加的文件。
在这里插入图片描述

7.1 tb_flash_be_ctrl

`timescale  1ns/1nsmodule  tb_flash_be_ctrl();//wire  define
wire            cs_n    ;   //Flash片选信号
wire            sck     ;   //Flash串行时钟
wire            mosi    ;   //Flash主输出从输入信号//reg   define
reg     sys_clk     ;   //模拟时钟信号
reg     sys_rst_n   ;   //模拟复位信号
reg     key         ;   //模拟全擦除触发信号//时钟、复位信号、模拟按键信号
initialbeginsys_clk     =   1'b1;sys_rst_n   <=  1'b0;key <=  1'b0;#100sys_rst_n   <=  1'b1;#1000key <=  1'b1;#20key <=  1'b0;endalways  #10 sys_clk <=  ~sys_clk;   //模拟时钟,频率50MHz//写入Flash仿真模型初始值(全F)
defparam memory.mem_access.initfile = "initmemory.txt";//------------- flash_be_ctrl_inst -------------
flash_be_ctrl  flash_be_ctrl_inst
(.sys_clk    (sys_clk    ),  //输入系统时钟,频率50MHz,1bit.sys_rst_n  (sys_rst_n  ),  //输入复位信号,低电平有效,1bit.key        (key        ),  //按键输入信号,1bit.sck        (sck        ),  //输出串行时钟,1bit.cs_n       (cs_n       ),  //输出片选信号,1bit.mosi       (mosi       )   //输出主输出从输入数据,1bit
);//------------- memory -------------
m25p16  memory
(.c          (sck    ),  //输入串行时钟,频率12.5Mhz,1bit.data_in    (mosi   ),  //输入串行指令或数据,1bit.s          (cs_n   ),  //输入片选信号,1bit.w          (1'b1   ),  //输入写保护信号,低有效,1bit.hold       (1'b1   ),  //输入hold信号,低有效,1bit.data_out   (       )   //输出串行数据
);endmodule

7.2 tb_spi_flash_be

`timescale  1ns/1ns
module  tb_spi_flash_be();//wire  define
wire    cs_n;
wire    sck ;
wire    mosi ;//reg   define
reg     clk     ;
reg     rst_n   ;
reg     key     ;//时钟、复位信号、模拟按键信号
initialbeginclk =   0;rst_n   <=  0;key <=  0;#100rst_n   <=  1;#1000key <=  1;#20key <=  0;endalways  #10 clk <=  ~clk;defparam memory.mem_access.initfile = "initmemory.txt";//-------------spi_flash_erase-------------
spi_flash_be    spi_flash_be_inst
(.sys_clk    (clk    ),  //系统时钟,频率50MHz.sys_rst_n  (rst_n  ),  //复位信号,低电平有效.pi_key     (key    ),  //按键输入信号.sck        (sck    ),  //串行时钟.cs_n       (cs_n   ),  //片选信号.mosi       (mosi   )   //主输出从输入数据
);m25p16  memory
(.c          (sck    ),  //输入串行时钟,频率12.5Mhz,1bit.data_in    (mosi   ),  //输入串行指令或数据,1bit.s          (cs_n   ),  //输入片选信号,1bit.w          (1'b1   ),  //输入写保护信号,低有效,1bit.hold       (1'b1   ),  //输入hold信号,低有效,1bit.data_out   (       )   //输出串行数据
);endmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/21483.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CDN技术(Content Delivery Network,内容分发网络)分布式网络架构(CND与P2P(Peer-to-Peer)区别)

文章目录 CDN是什么&#xff1f;CDN的优势CDN的应用1. 静态内容加速2. 动态内容加速3. 视频流媒体4. 软件分发5. 游戏加速6. 移动应用加速 CDN收费吗&#xff1f;CND与P2P区别什么是静态内容和动态内容&#xff1f; CDN是什么&#xff1f; CDN&#xff08;Content Delivery Ne…

html相关面试题

html相关面试题 1.html和css中的图片加载与渲染规则是什么样的&#xff1f;2.title与h1的区别、b与strong的区别、i与em的区别&#xff1f;title 和 h1 的区别b 和 strong 的区别i 和 em 的区别最后 3.script 标签为什么建议放在 body 标签的底部&#xff08;defer、async&…

WebDAV之π-Disk派盘 + PDF Expert

PDF Expert 支持WebDAV方式连接π-Disk派盘。 PDF Expert是一款macOS上的办公软件,它具有专业的PDF编辑功能,可以快速从邮件、网页支持PDF打开,支持用户进行阅读、批注等功能,用户可以直接在PDF上进行编辑文字图片,表单文档、创建笔记、添加书单等自定义使用,大大提高工…

【从零开始学习JAVA | 第二十八篇】不可变集合

目录 目录 前言&#xff1a; 不可变集合&#xff1a; 常见的不可变集合&#xff1a; 1.创建list的不可变集合&#xff1a; 2.创建map的不可变集合&#xff1a; 应用场景&#xff1a; 总结&#xff1a; 前言&#xff1a; 本文我们将为大家介绍JAVA中的不可变集合&#x…

TDengine数据建模

文章目录 1 引言2 数据建模3 数据建模的步骤4 创建库5 创建超级表实例 1 引言 工业互联网中有大量的时序数据需要存储和处理&#xff0c;tdengine是一个开源的、国产的、云原生时序数据库&#xff0c;tdengine不是基于其他第三方开源软件高级封装&#xff0c;是涛思数据完全自…

MySQL练习题(6)

创建两个表插入数据 CREATE DATABASE beifen;use beifen;CREATE TABLE books(bk_id INT NOT NULL PRIMARY KEY,bk_title VARCHAR(50) NOT NULL,copyright YEAR NOT NULL);INSERT INTO booksVALUES (11078, Learning MySQL, 2010),(11033, Study Html, 2011),(11035, How to u…

TiDB简述及TiKV的数据结构与存储 | 京东物流技术团队

1 概述 TiDB 是 PingCAP 公司自主设计、研发的开源分布式关系型数据库&#xff0c;是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactional and Analytical Processing, HTAP) 的融合型分布式数据库产品&#xff0c;具备水平扩容或者缩容、金融级高可用、实时 HTAP、…

从零开始制作一个Web蜜罐扫描器(2)

从零开始制作一个Web蜜罐扫描器(0)_luozhonghua2000的博客-CSDN博客 从零开始制作一个Web蜜罐扫描器(1)_luozhonghua2000的博客-CSDN博客 文件读取和写入实现 上面的工作已经完成了逻辑判断的部分,下面还需要进一步完善一些旁支末节的部分因为爬虫生成的文件是一个ison文件…

swin-transformer

面向视觉任务的transfomer Vision Transformer(ViT)在视觉任务中的局限性 需求数据量巨大 CNN中是图像整体输入&#xff0c;并且经过多年的演变&#xff0c;发展出了多个不同的优化策略。从而在学习时能够在一定先验知识的前提下拟合数据。 而transformer是将图像切割成若干较小…

Golang gui walk入门教程(一)安装walk环境

一、golang环境 Go 1.11.x or later 二、安装walk go get github.com/lxn/walk 三、安装rsrc 运行walk程序需要manifest&#xff0c;rsrc提供了这个功能 go install github.com/akavel/rsrc 安装完成后在GOPATH的bin下面会有一个rsrc.exe的可执行文件 在idea的termial输入r…

二维码生成器简单使用

生成器工具类 以下是一个简单的 QRCodeUtil 示例&#xff0c;这个工具类使用了 zxing 库来生成二维码图片&#xff1a; import com.google.zxing.BarcodeFormat; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.QRCodeWriter;import javax.image…

C语言、C++和C#:区别与特点的比较

C语言、C和C#是三种不同的编程语言&#xff0c;它们在以下几个方面存在区别&#xff1a; 设计宗旨&#xff1a;C语言是一种过程式编程语言&#xff0c;旨在提供高效的系统级编程。C是在C语言基础上发展而来的&#xff0c;既支持过程式编程&#xff0c;也支持面向对象编程。C#是…