09_SPI-Flash 页写实验

09_SPI-Flash 页写实验

  • 1. 实验目标
  • 2. 操作时序
  • 3. 模块框图
    • 3.1 顶层模块
    • 3.2 页写模块
  • 4. 波形图
  • 5. RTL
    • 5.1 flash_pp_ctrl
    • 5.2 spi_flash_pp
  • 6. Testbench
    • 6.1 tb_flash_pp_ctrl
    • 6.2 tb_spi_flash_pp

1. 实验目标

使用页写指令,向 Flash 中写入 N 字节数据,N 为整数,且大于 0 小于等于 256。在本 实 验 中 我 们 向 Flash 芯 片 中 写 入 0-99 , 共 100 字 节 数 据 , 数 据 初 始 地 址 为24’h00_04_25。
注意:在向 Flash 芯片写入数据之前,先要对芯片执行全擦除操作。

2. 操作时序

在这里插入图片描述
在这里插入图片描述
写满不支持跨页写,在这一页刚开始的地方写。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
扇区地址 s 页地址 p 字节地址 b

3. 模块框图

3.1 顶层模块

在这里插入图片描述

3.2 页写模块

在这里插入图片描述

4. 波形图

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

5. RTL

5.1 flash_pp_ctrl

`timescale  1ns/1ns
module  flash_pp_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 ,   //等待状态PP      =   4'b1000 ;   //页写状态
parameter   WR_EN_INST      =   8'b0000_0110,   //写使能指令PP_INST         =   8'b0000_0010;   //页写指令
parameter   SECTOR_ADDR     =   8'b0000_0000,   //扇区地址PAGE_ADDR       =   8'b0000_0100,   //页地址BYTE_ADDR       =   8'b0010_0101;   //字节地址
parameter   NUM_DATA        =   8'd100      ;   //页写数据个数(0-99)//reg   define
reg     [7:0]   cnt_byte        ;   //字节计数器
reg     [3:0]   state           ;   //状态机状态
reg     [4:0]   cnt_clk         ;   //系统时钟计数器
reg     [1:0]   cnt_sck         ;   //串行时钟计数器
reg     [2:0]   cnt_bit         ;   //比特计数器
reg     [7:0]   data            ;   //页写入数据//********************************************************************//
//***************************** 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    <=  8'd0;else    if((cnt_clk == 5'd31) && (cnt_byte == NUM_DATA + 8'd9))cnt_byte    <=  8'd0;else    if(cnt_clk == 5'd31)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 == 8'd1))cnt_sck <=  cnt_sck + 1'b1;else    if((state == PP) && (cnt_byte >= 8'd5)&& (cnt_byte <= NUM_DATA + 8'd9 - 1'b1))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 == 8'd2) && (cnt_clk == 5'd31) && (state == WR_EN))cs_n    <=  1'b1;else    if((cnt_byte == 8'd3) && (cnt_clk == 5'd31) && (state == DELAY))cs_n    <=  1'b0;else    if((cnt_byte == NUM_DATA + 8'd9) && (cnt_clk == 5'd31) && (state == PP))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;//data:页写入数据
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)data <=  8'd0;else    if((cnt_clk == 5'd31) && ((cnt_byte >= 8'd9)&& (cnt_byte < NUM_DATA + 8'd9 - 1'b1)))data <=  data + 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 == 8'd2) && (cnt_clk == 5'd31))state   <=  DELAY;DELAY:  if((cnt_byte == 8'd3) && (cnt_clk == 5'd31))state   <=  PP;PP:     if((cnt_byte == NUM_DATA + 8'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== 8'd2))mosi    <=  1'b0;else    if((state == PP) && (cnt_byte == NUM_DATA + 8'd9))mosi    <=  1'b0;else    if((state == WR_EN) && (cnt_byte == 8'd1) && (cnt_sck == 5'd0))mosi    <=  WR_EN_INST[7 - cnt_bit];  //写使能指令else    if((state == PP) && (cnt_byte == 8'd5) && (cnt_sck == 5'd0))mosi    <=  PP_INST[7 - cnt_bit];    //页写指令else    if((state == PP) && (cnt_byte == 8'd6) && (cnt_sck == 5'd0))mosi    <=  SECTOR_ADDR[7 - cnt_bit];  //扇区地址else    if((state == PP) && (cnt_byte == 8'd7) && (cnt_sck == 5'd0))mosi    <=  PAGE_ADDR[7 - cnt_bit];    //页地址else    if((state == PP) && (cnt_byte == 8'd8) && (cnt_sck == 5'd0))mosi    <=  BYTE_ADDR[7 - cnt_bit];    //字节地址else    if((state == PP) && ((cnt_byte >= 8'd9)&& (cnt_byte <= NUM_DATA + 8'd9 - 1'b1)) && (cnt_sck == 5'd0))mosi    <=  data[7 - cnt_bit];  //页写入数据endmodule

5.2 spi_flash_pp

`timescale  1ns/1ns
module  spi_flash_pp
(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_pp_ctrl_inst -------------
flash_pp_ctrl  flash_pp_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_pp_ctrl

`timescale  1ns/1ns
module  tb_flash_pp_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_pp_ctrl_inst -------------
flash_pp_ctrl  flash_pp_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_pp

`timescale  1ns/1ns
module  tb_spi_flash_pp();//wire  define
wire            cs_n;
wire            sck ;
wire            mosi;
wire    [7:0]   cmd_data;//reg   define
reg     clk     ;
reg     rst_n   ;
reg     key     ;//时钟、复位信号、模拟按键信号
initialbeginclk =   0;rst_n   <=  0;key <=  0;#100rst_n   <=  1;#1000key <=  1;#20key <=  0;endinitialbegin$timeformat(-9, 0, "ns", 16);$monitor("@time %t: key=%b ", $time, key );$monitor("@time %t: cs_n=%b", $time, cs_n);$monitor("@time %t: cmd_data=%d", $time, cmd_data);endalways  #10 clk <=  ~clk;defparam memory.mem_access.initfile = "initmemory.txt";//-------------spi_flash_pp-------------
spi_flash_pp    spi_flash_pp_inst
(.sys_clk    (clk        ),  //input     sys_clk.sys_rst_n  (rst_n      ),  //input     sys_rst.pi_key     (key        ),  //input     key.sck        (sck        ),  //output    sck.cs_n       (cs_n       ),  //output    cs_n.mosi       (mosi       )   //output    mosi
);m25p16  memory
(.c          (sck    ), .data_in    (mosi   ), .s          (cs_n   ), .w          (1'b1   ), .hold       (1'b1   ), .data_out   (       )
); endmodule

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

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

相关文章

小白到运维工程师自学之路 第五十三集 (rsync+inotify备份)

一、概述 Rsync是一个用于在不同计算机之间同步文件和文件夹的工具。它可以在本地计算机和远程服务器之间复制、更新和备份文件。rsync通过比较源和目标文件的差异来最小化传输的数据量&#xff0c;从而提供高效的文件同步功能。 Inotify是Linux内核提供的一种机制&#xff0…

layui实现动态添加选项卡

前言 上一篇博客介绍了树形菜单的实现&#xff0c;这一篇将继续完善通过点击左侧树形菜单实现动态打开选项卡Tab 一. 什么是Tab选项卡 Tab广泛应用于Web页面&#xff0c;因此我们也对其进行了良好的支持&#xff08;简约风格、卡片风格、响应式Tab以及带删除的Tab等等&#…

注册中心技术Eureka、Nacos

说明&#xff1a;在微服务框架中&#xff0c;各个服务之间都是独立的。理论上来说&#xff0c;各个服务之间是可以直接通信的&#xff0c;但实际上因为服务之间通信需要管理和规划&#xff0c;如请求怎么负载均衡、请求怎么降级处理等等&#xff0c;所以就需要使用一个技术&…

mysql-windows 安装

今天&#xff0c;由于一个功能要用到mysql&#xff0c;所以下载了 mysql-8.0.33-winx64 的版本&#xff0c;突然发现&#xff0c;以前都是安装的Linux 版本&#xff0c;windows版本不会安装了&#xff0c;查看官网试着装了一次&#xff0c;记录本次经历&#xff1a; 软件下载 …

【Hello mysql】 mysql的基本查询

Mysql专栏&#xff1a;Mysql 本篇博客简介&#xff1a;介绍mysql的基本查询 mysql的基本查询 create单行插入全列插入多行查询指定列查询插入否则更新 &#xff08;不常用&#xff09;替换 Retrieveselect列全列查询指定列查询查询字段为表达式结果去重 where条件找到英语小于6…

Yocto系列讲解[技巧篇]92 - armv8 aarch64兼容armv7 32位程序运行环境

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 概述使能Multilib支持32位的helloworld程序执行出现No such file or directorylibc.so.6 cannot open shared object file修改内容固化…

手把手教你落地大模型应用创意!全新AI达人创造营限时招募

AI进入大模型时代&#xff0c;智能应用和产品的构建开始发生天翻地覆的变化。想把你的AI创意落地&#xff0c;解决实际问题&#xff1f;想让更多人看到你的AI应用的价值与意义&#xff1f; 飞桨领航团AI达人创造营第4期学员招募正式启动&#xff01; AI达人创造营是百度飞桨领…

图像处理之高斯滤波

文章目录 高斯函数1.一维高斯函数2. 二维高斯函数 高斯滤波1.高斯核生成2.滤波过程 高斯函数 高斯函数广泛应用于统计学领域&#xff0c;用于表述正态分布&#xff0c;在信号处理领域&#xff0c;用于定义高斯滤波器&#xff0c;在图像处理领域&#xff0c;二维高斯核函数常用…

1.5 纹理

这次笔记时间有点久&#xff0c;主要是这节课讲的东西需要很多基础来铺垫&#xff0c;看完了后感觉缺失信息很多&#xff0c;又去补了GAMES 101 3~10节内容。 强烈建议看不懂的先去学习GMAES101 网址Lecture 08 Shading 2 (Shading, Pipeline and Texture Mapping)_哔哩哔哩_bi…

APP开发中的数据安全:你需要知道的一切

APP开发中的数据安全&#xff0c;是指 APP开发过程中&#xff0c;所有的数据都会经过严格的安全处理。因为目前 APP开发公司的技术、资质良莠不齐&#xff0c;很多企业在开发过程中不注重对数据安全的保护。 在如今大数据时代&#xff0c; APP开发过程中&#xff0c;会产生大量…

unidbg或者java层解密方法IDEA中打包成jar包供python调用方法

一、导出jar包方法 &#xff08;1&#xff09;配置jar包参数 &#xff08;2&#xff09;创建生成jar包 成功生成&#xff01; 二、Python代码调用 import jpypejvmPath jpype.getDefaultJVMPath() d unidbg-android.jar # 对应jar地址 jpype.startJVM(jvmPath, "-ea&q…

Docker 运行花生壳实现内外网穿透

Docker 运行花生壳实现内外网穿透 1、docker安装centos2、进入centos容器安装花生壳客户端3、花生壳绑定设备4、测试外网穿透 1、docker安装centos 使用命令行安装centos7 docker run --privilegedtrue --restartalways -e TZ"Asia/Shanghai" -d --nethost --nam…