10_SPI_Flash 连续写实验

10_SPI_Flash 连续写实验

  • 1. 实验目标
  • 2. 连续写方法
  • 3. 操作时序
  • 4. 流程框图
    • 4.1 顶层模块
    • 4.2 连续写模块
  • 5. 波形图
  • 6. RTL
    • 6.1 flash_seq_wr_ctrl
    • 6.2 spi_flash_seq_wr
  • 7. Testbench

1. 实验目标

使用页写指令,将串口发送过来的连续不定量数据写入 Flash。本实验中,我们发送数据为 100 字节,串口波特率位 9600。
注意:在向 Flash 芯片写入数据之前,先要对芯片执行全擦除操作。

2. 连续写方法

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

3. 操作时序

和页写操作的操作时序一样。

4. 流程框图

4.1 顶层模块

在这里插入图片描述

4.2 连续写模块

在这里插入图片描述

在这里插入图片描述

5. 波形图

在这里插入图片描述

6. RTL

6.1 flash_seq_wr_ctrl

`timescale  1ns/1ns
module  flash_seq_wr_ctrl(input   wire            sys_clk     ,   //系统时钟,频率50MHzinput   wire            sys_rst_n   ,   //复位信号,低电平有效input   wire            pi_flag     ,   //数据标志信号input   wire    [7:0]   pi_data     ,   //写入数据output  reg             sck         ,   //串行时钟output  reg             cs_n        ,   //片选信号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   ADDR        =   24'h00_04_25;   //数据写入地址//reg   define
reg     [23:0]  addr_reg;   //数据写入地址寄存器
reg     [23:0]  addr    ;   //数据写入地址reg     [4:0]   cnt_clk ;   //系统时钟计数器
reg     [3:0]   state   ;   //状态机状态
reg     [3:0]   cnt_byte;   //字节计数器
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'd10))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 == PP) && (cnt_byte >= 4'd5) && (cnt_byte <= 4'd9))cnt_sck <=  cnt_sck + 1'b1;//addr_reg:数据写入地址寄存器
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)addr_reg    <=  ADDR;else    if(pi_flag == 1'b1)addr_reg    <=  addr_reg + 1'b1 ;//addr:数据写入地址
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)addr    <=  24'd0;else    if(pi_flag == 1'b1)addr    <=  addr_reg;//cs_n:片选信号
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)cs_n    <=  1'b1;else    if(pi_flag == 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'd10) && (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;//state:两段式状态机第一段,状态跳转
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)state   <=  IDLE;elsecase(state)IDLE:   if(pi_flag == 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   <=  PP;PP:     if((cnt_byte == 4'd10) && (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 == PP) && (cnt_byte == 4'd10))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 == PP) && (cnt_byte == 4'd5) && (cnt_sck == 5'd0))mosi    <=  PP_INST[7 - cnt_bit];       //扇区擦除指令else    if((state == PP) && (cnt_byte == 4'd6) && (cnt_sck == 5'd0))mosi    <=  addr[23 - cnt_bit];         //扇区地址else    if((state == PP) && (cnt_byte == 4'd7) && (cnt_sck == 5'd0))mosi    <=  addr[15 - cnt_bit];         //页地址else    if((state == PP) && (cnt_byte == 4'd8) && (cnt_sck == 5'd0))mosi    <=  addr[7 - cnt_bit];          //字节地址else    if((state == PP) && (cnt_byte == 4'd9) && (cnt_sck == 5'd0))mosi    <=  pi_data[7 - cnt_bit];       //写入数据endmodule

6.2 spi_flash_seq_wr

`timescale  1ns/1ns
module  spi_flash_seq_wr(input   wire    sys_clk     ,   //系统时钟,频率50MHzinput   wire    sys_rst_n   ,   //复位信号,低电平有效input   wire    rx          ,   //串口接收数据output  wire    cs_n        ,   //片选信号output  wire    sck         ,   //串行时钟output  wire    mosi        ,   //主输出从输入数据output  wire    tx              //串口发送数据);//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   UART_BPS    =   14'd9600        ,   //比特率CLK_FREQ    =   26'd50_000_000  ;   //时钟频率//wire  define
wire            po_flag ;
wire    [7:0]   po_data ;//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************////-------------uart_rx_inst-------------
uart_rx
#(.UART_BPS    (UART_BPS ),         //串口波特率.CLK_FREQ    (CLK_FREQ )          //时钟频率
)
uart_rx_inst(.sys_clk     (sys_clk  ),   //系统时钟50Mhz.sys_rst_n   (sys_rst_n),   //全局复位.rx          (rx       ),   //串口接收数据.po_data     (po_data  ),   //串转并后的数据.po_flag     (po_flag  )    //串转并后的数据有效标志信号
);//-------------flash_seq_wr_ctrl_inst-------------
flash_seq_wr_ctrl  flash_seq_wr_ctrl_inst(.sys_clk    (sys_clk    ),  //系统时钟,频率50MHz.sys_rst_n  (sys_rst_n  ),  //复位信号,低电平有效.pi_flag    (po_flag    ),  //数据标志信号.pi_data    (po_data    ),  //写入数据.sck        (sck        ),  //片选信号.cs_n       (cs_n       ),  //串行时钟.mosi       (mosi       )   //主输出从输入数据);//-------------uart_tx_inst-------------
uart_tx
#(.UART_BPS    (UART_BPS ),         //串口波特率.CLK_FREQ    (CLK_FREQ )          //时钟频率
)
uart_tx_inst
(.sys_clk     (sys_clk  ),   //系统时钟50Mhz.sys_rst_n   (sys_rst_n),   //全局复位.pi_data     (po_data  ),   //并行数据.pi_flag     (po_flag  ),   //并行数据有效标志信号.tx          (tx       )    //串口发送数据
);endmodule

7. Testbench

`timescale  1ns/1ns
module  tb_spi_flash_seq_wr();//wire define
wire    tx  ;
wire    cs_n;
wire    sck ;
wire    mosi;
wire    miso;//reg define
reg           clk   ;
reg           rst_n ;
reg           rx    ;
reg   [7:0]   data_mem [299:0] ;  //data_mem是一个存储器,相当于一个ram//读取sim文件夹下面的data.txt文件,并把读出的数据定义为data_mem
initial$readmemh("E:/base_code/10_spi_flash/spi_flash_write/spi_flash_seq_wr/sim/spi_flash.txt",data_mem);//时钟、复位信号
initialbeginclk     =   1'b1  ;rst_n   <=  1'b0  ;#200rst_n   <=  1'b1  ;endalways  #10 clk = ~clk;initialbeginrx  <=  1'b1;#200rx_byte();endtask  rx_byte();integer j;for(j=0;j<300;j=j+1)rx_bit(data_mem[j]);
endtasktask  rx_bit(input[7:0] data);  //data是data_mem[j]的值。integer i;for(i=0;i<10;i=i+1)begincase(i)0:  rx  <=  1'b0   ;  //起始位1:  rx  <=  data[0];2:  rx  <=  data[1];3:  rx  <=  data[2];4:  rx  <=  data[3];5:  rx  <=  data[4];6:  rx  <=  data[5];7:  rx  <=  data[6];8:  rx  <=  data[7];  //上面8个发送的是数据位9:  rx  <=  1'b1   ;  //停止位endcase#1040;                  //一个波特时间=sclk周期*波特计数器end
endtask//重定义defparam,用于修改参数,缩短仿真时间
defparam spi_flash_seq_wr_inst.uart_rx_inst.CLK_FREQ    = 500000;
defparam spi_flash_seq_wr_inst.uart_tx_inst.CLK_FREQ    = 500000;
defparam memory.mem_access.initfile = "initmemory.txt";//-------------spi_flash_seq_wr_inst-------------
spi_flash_seq_wr  spi_flash_seq_wr_inst(.sys_clk    (clk    ),    //input   sys_clk.sys_rst_n  (rst_n  ),    //input   sys_rst_n.rx         (rx     ),    //input   rx.cs_n       (cs_n   ),    //output  cs_n.sck        (sck    ),    //output  sck.mosi       (mosi   ),    //output  mosi.tx         (tx     )     //output  tx);m25p16  memory (.c          (sck    ), .data_in    (mosi   ), .s          (cs_n   ), .w          (1'b1   ), .hold       (1'b1   ), .data_out   (miso   )
); endmodule

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

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

相关文章

Web安全——数据库mysql学习

数据库mysql基础 Web安全分享一、数据库的基本操作1、MYSQL登录与退出2、MYSQL数据库的一些解释3、MYSQL注释符有三种&#xff1a; 二、数据库的一些基本操作1、数据库的增删改查(sql语句) 三、table 表的操作1、查看表结构2、查看表的内容3、建立表4、约束条件5、修改表的操作…

网络通信原理系统的认知(NEBASE第十四课)

1 物理层 第一层 物理层&#xff1a;建立、维护、断开物理连接&#xff0c;定义了接口及介质&#xff0c;实现了比特流的传输。 1.1传输层介质分类 有线介质&#xff1a;网线 &#xff08;双绞线&#xff09;光纤 无线: 无线电 1.2 双绞线 五类线 cat5 &#xff1a;适用 10…

第二次CCF计算机软件能力认证

第一题&#xff1a;相邻数对 给定 n 个不同的整数&#xff0c;问这些数中有多少对整数&#xff0c;它们的值正好相差 1。 输出格式 输入的第一行包含一个整数 n&#xff0c;表示给定整数的个数。 第二行包含所给定的 n 个整数。 输出格式 输出一个整数&#xff0c;表示值正好相…

KMP算法

KMP KMP 算法是一个快速查找匹配串的算法&#xff0c;它的作用其实就是本题问题&#xff1a;如何快速在「原字符串」中找到「匹配字符串」。 而 KMP 算法的复杂度为 O(mn)实际上是O(N),因为O(M)不可能大于O(N) KMP 之所以能够在 O(mn)复杂度内完成查找&#xff0c;是因为其能…

巴斯夫与长三角物理研究中心开展合作,专注固态和钠离子电池领域

“巴斯夫&#xff0c;全球知名化学公司&#xff0c;宣布与长三角物理研究中心合作&#xff0c;在江苏溧阳市成立联合研究中心&#xff0c;专注于固态电池和钠离子电池的科研。” 根据巴斯夫官方微博消息&#xff0c;新成立的研究中心名为“巴斯夫–长三角物理研究中心新能源汽车…

高德地图的使用

JS API 结合 Vue 使用 高德地图 jsapi 下载、引入 npm add amap/amap-jsapi-loaderimport AMapLoader from amap/amap-jsapi-loader 使用2.0版本的loader需要在window对象下先配置 securityJsCode JS API 安全密钥使用 JS API 使用 script 标签同步加载增加代理服务器设置…

【计算机网络】网络编程套接字(二)

文章目录 网络编程套接字&#xff08;二&#xff09;简单TCP服务器实现创建套接字服务器绑定服务器监听服务器接收连接服务器处理请求 简单TCP客户端实现创建套接字客户端发起连接客户端发起请求 服务器简单测试服务器简单测评多进程版TCP服务器捕捉SIGCHLD信号孙子进程提供服务…

【RuoYi-Cloud-Plus】学习笔记 09 - Sentinel(四)熔断降级知识整理

文章目录 前言参考目录版本说明学习笔记1、包结构2、DegradeSlot3、DegradeRule4、DegradeRuleManager5、CircuitBreaker5.1 CircuitBreaker.State6、AbstractCircuitBreaker6.1、AbstractCircuitBreaker#fromCloseToOpen6.2、AbstractCircuitBreaker#fromHalfOpenToOpen6.3、A…

支付宝接入

支付宝接入 python-alipay-sdk pycryptodome一、电脑网站支付 1.1 获取支付宝密钥 沙箱网址 1.APPID 2.应用私钥 3.支付宝公钥1.2 存放密钥 在与 settings.py 的同级目录下创建 pem 文件夹pem 文件夹下创建 app_private_key.pem 和 alipay_public_key.pem app_private_key…

神经网络初谈

文章目录 简介神经网络的发展历程神经网络的初生神经网络的第一次折戟神经网络的新生&#xff0c;Hinton携BP算法登上历史舞台命途多舛&#xff0c;神经网络的第二次寒冬神经网络的重生&#xff0c;黄袍加身&#xff0c;一步封神神经网络的未来&#xff0c;众说纷纭其他时间点 …

STM32 Proteus仿真LCD12864俄罗斯方块-FZ0063

STM32 Proteus仿真LCD12864俄罗斯方块-FZ0063 Proteus仿真小实验&#xff1a; STM32 Proteus仿真LCD12864俄罗斯方块-FZ0063 功能&#xff1a; 硬件组成&#xff1a;STM32F103R6单片机 LCD12864显示器多个按键 1.标准俄罗斯方块经典游戏玩法&#xff0c;带计时&#xff0c…

Kong 服务和路由的添加

管理服务 这里参考DB-less-Mode&#xff0c;因为使用的是yaml配置文件的形式&#xff0c;所以所有的相关配置只需要往初始化的kong.yml文件中添加就可以了&#xff0c;就像nginx的配置文件 DB-less-Mode 创建服务 vim /etc/kong/kong.yml services: - name: my-service #…

MySQL---表数据高效率查询(简述)

目录 前言 一、聚合查询 &#x1f496;聚合函数 &#x1f496;GROUP BY子句 &#x1f496;HAVING 二、联合查询 &#x1f496;内连接 &#x1f496;外连接 &#x1f496;自连接 &#x1f496;子查询 &#x1f496;合并查询 &#x1f381;博主介绍&#xff1a;博客名…

Idea 修改默认 Maven 为自己的

每次我们打开新项目时,都要去配置一遍 maven,很麻烦,其实可以去修改 idea 里面默认的 maven 配置,这样后面不管是打开新项目还是老项目,就都是用的自己的 maven 了. 1.文件->新项目设置->新项目的设置 File->Other Settings -> Settings for New Project 2.然后和…

git下载源码及环境搭建之数据库(二)

学习目标&#xff1a; 数据库 新项目使用 数据库文件 的配置 及相关属性的设置 步骤&#xff1a; 数据库 下图所示为开发时所用数据库 第一步&#xff1a;新建一个数据库 注意&#xff1a; 字符集与排序规则我们应该选择utf-8 相关 选中新创建的表&#xff0c;点击备份—还…

MySQL单表查询练习题

目录 第一题 第二题 第三题 第一题 1.创建数据表pet&#xff0c;并对表进行插入、更新与删除操作&#xff0c;pet表结构如表8.3所示。 (1&#xff09;首先创建数据表pet&#xff0c;使用不同的方法将表8.4中的记录插入到pet表中。 mysql> create table pet( name varchar(…

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。这…

python爬虫哪个库用的最多

目录 常用的python爬虫库有哪些 1. Requests&#xff1a; 2. BeautifulSoup&#xff1a; 3. Scrapy&#xff1a; 4. Selenium&#xff1a; 5. Scrapy-Redis&#xff1a; 哪个爬虫库用的最多 Scrapy示例代码 总结 常用的python爬虫库有哪些 Python拥有许多常用的爬虫库…

Java反射与“整活--(IOC容器)”

文章目录 前言反射什么是反射基本操作获取类对象获取类属性获取类方法方法的执行对构造方法的操作 注解定义获取注解 整活&#xff08;IOC容器&#xff09;项目结构IOC/DI流程ApplicationContextBeanDefinitionReaderBeanDefinitionBeanWrappergetBean&#xff08;&#xff09;…

Django_admin数据管理后台

目录 一、基础操作 二、自定义后台操作数据行为 源码等资料获取方法 admin数据管理后台是django内置的一个后台管理界面&#xff0c;能查看已注册模型类的数据结构&#xff0c;以及对数据的增删改。 一、基础操作 1.1 检查项目目录下的urls.py有没有如下配置 1.2 创建djan…