08_SPI-Flash 扇区擦除实验

08_SPI-Flash 扇区擦除实验

  • 1. 实验目标
  • 2. 操作时序
    • 2.1 扇区擦除操作指令
    • 2.2 完整扇区擦除操作时序
  • 3. 程序框图
    • 3.1 顶层框图
    • 3.2 扇区擦除模块
  • 4. 波形图
  • 5. RTL
    • 5.1 flash_se_ctrl
    • 5.2 spi_flash_se
  • 6. Testbench
    • 6.1 tb_flash_se_ctrl
    • 6.2 tb_spi_flash_se

1. 实验目标

编写扇区擦除工程,擦除事先烧录到 Flash 中的流水灯程序所占的某个扇区,使流水灯程序不能正常工作。在此次实验工程,我们选择擦除第 0 个扇区,擦除地址为24’h00_04_25。

2. 操作时序

2.1 扇区擦除操作指令

扇区擦除(Sector Erase)操作,简称 SE,操作指令为 8’b1101_0000(D8h)。
在这里插入图片描述

2.2 完整扇区擦除操作时序

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

3. 程序框图

3.1 顶层框图

在这里插入图片描述

3.2 扇区擦除模块

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

4. 波形图

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

5. RTL

5.1 flash_se_ctrl

`timescale  1ns/1ns
module  flash_se_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 ,   //等待状态SE      =   4'b1000 ;   //扇区擦除状态
parameter   WR_EN_INST  =   8'b0000_0110,   //写使能指令SE_INST     =   8'b1101_1000;   //扇区擦除指令
parameter   SECTOR_ADDR =   8'b0000_0000,   //扇区地址PAGE_ADDR   =   8'b0000_0100,   //页地址BYTE_ADDR   =   8'b0010_0101;   //字节地址//reg   define
reg     [3: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    <=  4'd0;else    if((cnt_clk == 5'd31) && (cnt_byte == 4'd9))cnt_byte    <=  4'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 == SE) && (cnt_byte >= 4'd5) && (cnt_byte <= 4'd8))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 == 4'd2) && (cnt_clk == 5'd31) && (state == WR_EN))cs_n    <=  1'b1;else    if((cnt_byte == 4'd3) && (cnt_clk == 5'd31) && (state == DELAY))cs_n    <=  1'b0;else    if((cnt_byte == 4'd9) && (cnt_clk == 5'd31) && (state == SE))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 == 4'd2) && (cnt_clk == 5'd31))state   <=  DELAY;DELAY:  if((cnt_byte == 4'd3) && (cnt_clk == 5'd31))state   <=  SE;SE:     if((cnt_byte == 4'd9) && (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 == 4'd2))mosi    <=  1'b0;else    if((state == SE) && (cnt_byte == 4'd9))mosi    <=  1'b0;else    if((state == WR_EN) && (cnt_byte == 4'd1) && (cnt_sck == 5'd0))mosi    <=  WR_EN_INST[7 - cnt_bit];  //写使能指令else    if((state == SE) && (cnt_byte == 4'd5) && (cnt_sck == 5'd0))mosi    <=  SE_INST[7 - cnt_bit];    //扇区擦除指令else    if((state == SE) && (cnt_byte == 4'd6) && (cnt_sck == 5'd0))mosi    <=  SECTOR_ADDR[7 - cnt_bit];  //扇区地址else    if((state == SE) && (cnt_byte == 4'd7) && (cnt_sck == 5'd0))mosi    <=  PAGE_ADDR[7 - cnt_bit];    //页地址else    if((state == SE) && (cnt_byte == 4'd8) && (cnt_sck == 5'd0))mosi    <=  BYTE_ADDR[7 - cnt_bit];    //字节地址endmodule

5.2 spi_flash_se

`timescale  1ns/1ns
module  spi_flash_se
(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_se_ctrl_inst -------------
flash_se_ctrl  flash_se_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

6. Testbench

6.1 tb_flash_se_ctrl

`timescale  1ns/1ns
module  tb_flash_se_ctrl();//wire  define
wire    cs_n;
wire    sck ;
wire    mosi ;//reg   define
reg     sys_clk     ;
reg     sys_rst_n   ;
reg     key         ;//时钟、复位信号、模拟按键信号
initialbeginsys_clk     =   0;sys_rst_n   <=  0;key <=  0;#100sys_rst_n   <=  1;#1000key <=  1;#20key <=  0;endalways  #10 sys_clk <=  ~sys_clk;//写入Flash仿真模型初始值(全F)
defparam memory.mem_access.initfile = "initmemory.txt";//------------- flash_se_ctrl_inst -------------
flash_se_ctrl  flash_se_ctrl_inst
(.sys_clk    (sys_clk    ),  //系统时钟,频率50MHz.sys_rst_n  (sys_rst_n  ),  //复位信号,低电平有效.key        (key        ),  //按键输入信号.sck        (sck        ),  //串行时钟.cs_n       (cs_n       ),  //片选信号.mosi       (mosi       )   //主输出从输入数据
);//------------- 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

6.2 tb_spi_flash_se

`timescale  1ns/1ns
module  tb_spi_flash_se();//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_se-------------
spi_flash_se    spi_flash_se_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/22127.html

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

相关文章

Oracle表设计

设计原则 为了建立冗余较小、结构合理的数据库&#xff0c;设计数据库时必须遵循一定的规 则。在关系型数据库中这种规则就称为范式。 范式是符合某一种设计要求的总结。 要想设计一个结构合理的关系型数据库&#xff0c;必须满足一定的范式。在实际开发中最为 常见的设计范式…

学校食堂升级改造?看这篇就够了!

在现代化的食堂管理中&#xff0c;智慧食堂扮演着重要的角色。通过利用智能技术和先进的收银系统&#xff0c;食堂能够实现快速、准确和便捷的收银过程&#xff0c;为顾客提供更好的用餐体验。 智慧食堂是适应现代社会对快捷、便利、个性化餐饮服务需求的创新解决方案&#xff…

面试题更新之-HTML5的新特性

文章目录 导文新特性有哪些&#xff1f;HTML5的新特性带来了许多好处 导文 面试题更新之-HTML5的新特性 新特性有哪些&#xff1f; HTML5引入了许多新特性和改进&#xff0c;以下是一些HTML5的新特性&#xff1a; 语义化标签&#xff1a;HTML5引入了一系列的语义化标签&#…

在vue中点击弹框给弹框中的表格绑值

场景描述&#xff1a;如下图所示&#xff0c;我们需要点击 ‘账单生成’ 按钮&#xff0c;然后里边要展示一个下图这样的表格。 最主要的是如何展示表格中的内容&#xff0c;一起看看吧&#xff01; <template><!-- 水费 欠费--><el-dialog title"水费欠费…

pnpm安装方式

pnpm安装方式 要使用pnpm进行安装&#xff0c;首先需要确保已经安装了Node.js。然后&#xff0c;按照以下步骤进行pnpm的安装&#xff1a; 打开终端或命令提示符。 在命令行中输入以下命令来全局安装pnpm&#xff1a; npm install -g pnpm这将使用npm将pnpm包全局安装到您的…

centos7.9php8swoole5swoft2环境安装遇到确实redis扩展的解决办法

1、环境介绍 运行系统&#xff1a;centos7.9 php版本&#xff1a;php8.0.29 swoole版本&#xff1a;swoole5 swoft版本&#xff1a;swoft2.02、遇到的问题 The requested PHP extension ext-redis * is missing from your system. Install or enable PHPs redis extension。这…

C++ IO流

文章目录 C语言的输入与输出流是什么?CIO流C标准IO流C文件流 stringstream的简单介绍 C语言的输入与输出 在C语言中,我们使用最频繁的输入输出方式为: scanf 和 printf. scanf : 从输入设备(键盘)读取数据,并将值存放在变量中.printf: 将指定的文字/字符串输出到标准输出设备…

详解c++---c++11(下)

目录标题 default关键字delete关键字lambda表达式为什么会有lambda表达式lambda的用法多线程和lambdalambda的底层 可变参数模板emplace包装器为什么会有包装器包装器的使用 bind default关键字 C11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数&#xff0…

Java中字符串相关的类

目录 String类 StringBuffer类 StringBuilder类 String类 String类&#xff1a;代表字符串。Java 程序中的所有字符串字面值&#xff08;如 "abc" &#xff09;都作为此类的实例实现。 String是一个final类&#xff0c;代表不可变的字符序列。 字符串是常量&…

webpack相关

在 webpack < 4 的版本中&#xff0c;通常将 vendor 作为一个单独的入口起点添加到 entry 选项中&#xff0c;以将其编译为一个单独的文件&#xff08;与 CommonsChunkPlugin 结合使用&#xff09;。而在 webpack 4 中不鼓励这样做。而是使用 optimization.splitChunks 选项…

Vim使用tips ---用鼠标定位代码

在vim界面里我们想用鼠标操作定位代码是不可以的&#xff01;&#xff01; 但是我们可以更改设置&#xff1a; 按下 Esc 键返回到普通模式shift&#xff1a; 输人命令 set mouse a回车 这时候我们就可以定位到代码啦&#xff01;&#xff01; 还可以批量选中复制和删除&…

【Docker】Docker高级网络(NetWork)

【Docker】Docker高级网络(NetWork) 文章目录 【Docker】Docker高级网络(NetWork)1. 概述2. 网络2.1 网桥类型2.2 创建网络自定义桥2.3 查看所有网络2.4 查看特定网络的细节2.5 删除特定网络2.6 多个容器使用指定网络 参考文档&#xff1a;高级网络配置 Docker – 从入门到实践…