11_SPI_Flash 读数据实验

11_SPI_Flash 读数据实验

  • 1. 实验目标
  • 2. 操作时序
    • 2.1 数据读操作指令
    • 2.2 数据读操作时序
  • 3. 流程框图
    • 3.1 顶层模块
    • 3.2 数据读模块
  • 4. 波形图绘制
  • 5. RTL
    • 5.1 flash_read_ctrl
    • 5.2 spi_flash_read
  • 6. testbench

1. 实验目标

使用页写或连续写操作向 Flash 芯片写入数据,再使用数据读操作读取之前写入数据,将读取的数据使用串口传回 PC 机,使用串口助手传回数据并与之前写入数据比较,判断正误。

2. 操作时序

2.1 数据读操作指令

在这里插入图片描述

2.2 数据读操作时序

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

3. 流程框图

3.1 顶层模块

在这里插入图片描述

3.2 数据读模块

在这里插入图片描述

在这里插入图片描述

4. 波形图绘制

读取数据阶段
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

读出了数据,下面是把串行的数据 转换为并行的数据,传入到接口数据的读取上升沿。
在这里插入图片描述
在这里插入图片描述

5. RTL

5.1 flash_read_ctrl

`timescale  1ns/1ns
module  flash_read_ctrl(input   wire            sys_clk     ,   //系统时钟,频率50MHzinput   wire            sys_rst_n   ,   //复位信号,低电平有效input   wire            key         ,   //按键输入信号input   wire            miso        ,   //读出flash数据output  reg             sck         ,   //串行时钟output  reg             cs_n        ,   //片选信号output  reg             mosi        ,   //主输出从输入数据output  reg             tx_flag     ,   //输出数据标志信号output  wire    [7:0]   tx_data         //输出数据);//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************////parameter define
parameter   IDLE    =   3'b001  ,   //初始状态READ    =   3'b010  ,   //数据读状态SEND    =   3'b100  ;   //数据发送状态parameter   READ_INST   =   8'b0000_0011;   //读指令
parameter   NUM_DATA    =   16'd100     ;   //读出数据个数
parameter   SECTOR_ADDR =   8'b0000_0000,   //扇区地址PAGE_ADDR   =   8'b0000_0100,   //页地址BYTE_ADDR   =   8'b0010_0101;   //字节地址
parameter   CNT_WAIT_MAX=   16'd6_00_00 ;//wire  define
wire    [7:0]   fifo_data_num   ;   //fifo内数据个数
//reg   define
reg     [4:0]   cnt_clk         ;   //系统时钟计数器
reg     [2:0]   state           ;   //状态机状态
reg     [15:0]  cnt_byte        ;   //字节计数器
reg     [1:0]   cnt_sck         ;   //串行时钟计数器
reg     [2:0]   cnt_bit         ;   //比特计数器
reg             miso_flag       ;   //miso提取标志信号
reg     [7:0]   data            ;   //拼接数据
reg             po_flag_reg     ;   //输出数据标志信号
reg             po_flag         ;   //输出数据
reg     [7:0]   po_data         ;   //输出数据
reg             fifo_read_valid ;   //fifo读有效信号
reg     [15:0]  cnt_wait        ;   //等待计数器
reg             fifo_read_en    ;   //fifo读使能
reg     [7:0]   read_data_num   ;   //读出fifo数据个数//********************************************************************//
//***************************** 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 == READ)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    <=  16'd0;else    if((cnt_clk == 5'd31) && (cnt_byte == NUM_DATA + 16'd3))cnt_byte    <=  16'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 == READ)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 == NUM_DATA + 16'd3) && (cnt_clk == 5'd31) && (state == READ))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   <=  READ;READ:   if((cnt_byte == NUM_DATA + 16'd3) && (cnt_clk == 5'd31))state   <=  SEND;SEND:   if((read_data_num == NUM_DATA)&& ((cnt_wait == (CNT_WAIT_MAX - 1'b1))))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 == READ) && (cnt_byte>= 16'd4))mosi    <=  1'b0;else    if((state == READ) && (cnt_byte == 16'd0) && (cnt_sck == 2'd0))mosi    <=  READ_INST[7 - cnt_bit];  //读指令else    if((state == READ) && (cnt_byte == 16'd1) && (cnt_sck == 2'd0))mosi    <=  SECTOR_ADDR[7 - cnt_bit];  //扇区地址else    if((state == READ) && (cnt_byte == 16'd2) && (cnt_sck == 2'd0))mosi    <=  PAGE_ADDR[7 - cnt_bit];    //页地址else    if((state == READ) && (cnt_byte == 16'd3) && (cnt_sck == 2'd0))mosi    <=  BYTE_ADDR[7 - cnt_bit];    //字节地址//miso_flag:miso提取标志信号
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)miso_flag   <=  1'b0;else    if((cnt_byte >= 16'd4) && (cnt_sck == 2'd1))miso_flag   <=  1'b1;elsemiso_flag   <=  1'b0;//data:拼接数据
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)data    <=  8'd0;else    if(miso_flag == 1'b1)data    <=  {data[6:0],miso};//po_flag_reg:输出数据标志信号
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)po_flag_reg <=  1'b0;else    if((cnt_bit == 3'd7) && (miso_flag == 1'b1))po_flag_reg <=  1'b1;elsepo_flag_reg <=  1'b0;//po_flag:输出数据标志信号
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)po_flag <=  1'b0;elsepo_flag <=  po_flag_reg;//po_data:输出数据
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)po_data <=  8'd0;else    if(po_flag_reg == 1'b1)po_data <=  data;elsepo_data <=  po_data;//fifo_read_valid:fifo读有效信号
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)fifo_read_valid <=  1'b0;else    if((read_data_num == NUM_DATA)&& ((cnt_wait == (CNT_WAIT_MAX - 1'b1))))fifo_read_valid <=  1'b0;else    if(fifo_data_num == NUM_DATA)fifo_read_valid <=  1'b1;//cnt_wait:两数据读取时间间隔
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_wait    <=  16'd0;else    if(fifo_read_valid == 1'b0)cnt_wait    <=  16'd0;else    if(cnt_wait == (CNT_WAIT_MAX - 1'b1))cnt_wait    <=  16'd0;else    if(fifo_read_valid == 1'b1)cnt_wait    <=  cnt_wait + 1'b1;//fifo_read_en:fifo读使能信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)fifo_read_en <=  1'b0;else    if((cnt_wait == (CNT_WAIT_MAX - 1'b1))&& (read_data_num < NUM_DATA))fifo_read_en <=  1'b1;elsefifo_read_en <=  1'b0;//read_data_num:自fifo中读出数据个数计数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)read_data_num <=  8'd0;else    if(fifo_read_valid == 1'b0)read_data_num <=  8'd0;else    if(fifo_read_en == 1'b1)read_data_num <=  read_data_num + 1'b1;//tx_flag
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)tx_flag <=  1'b0;elsetx_flag <=  fifo_read_en;//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//-------------fifo_data_inst--------------
fifo_data fifo_data_inst(.clock  (sys_clk      ),    //时钟信号.data   (po_data      ),    //写数据,8bit.wrreq  (po_flag      ),    //写请求.rdreq  (fifo_read_en ),    //读请求.q      (tx_data      ),    //数据读出,8bit.usedw  (fifo_data_num)     //fifo内数据个数
);endmodule

5.2 spi_flash_read

`timescale  1ns/1ns
module  spi_flash_read(input   wire    sys_clk     ,   //系统时钟,频率50MHzinput   wire    sys_rst_n   ,   //复位信号,低电平有效input   wire    pi_key      ,   //按键输入信号input   wire    miso        ,   //读出flash数据output  wire    cs_n        ,   //片选信号output  wire    sck         ,   //串行时钟output  wire    mosi        ,   //主输出从输入数据output  wire    tx              );//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   CNT_MAX     =   20'd999_999     ;   //计数器计数最大值
parameter   UART_BPS    =   14'd9600        ,   //比特率CLK_FREQ    =   26'd50_000_000  ;   //时钟频率//wire  define
wire            po_key  ;   //消抖处理后的按键信号
wire            tx_flag ;   //输入串口发送模块数据标志信号
wire    [7:0]   tx_data ;   //输入串口发送模块数据//********************************************************************//
//*************************** 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_read_ctrl_inst-------------
flash_read_ctrl  flash_read_ctrl_inst(.sys_clk    (sys_clk    ),  //系统时钟,频率50MHz.sys_rst_n  (sys_rst_n  ),  //复位信号,低电平有效.key        (po_key     ),  //按键输入信号.miso       (miso       ),  //读出flash数据.sck        (sck        ),  //片选信号.cs_n       (cs_n       ),  //串行时钟.mosi       (mosi       ),  //主输出从输入数据.tx_flag    (tx_flag    ),  //输出数据标志信号.tx_data    (tx_data    )   //输出数据);//-------------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     (tx_data  ),   //并行数据.pi_flag     (tx_flag  ),   //并行数据有效标志信号.tx          (tx       )    //串口发送数据
);endmodule

6. testbench

`timescale  1ns/1ns
module  tb_spi_flash_read();//wire  define
wire    cs_n;
wire    sck ;
wire    mosi;
wire    miso;
wire    tx  ;//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 = "initM25P16_test.txt";
defparam spi_flash_read_inst.flash_read_ctrl_inst.CNT_WAIT_MAX = 1000;
defparam spi_flash_read_inst.uart_tx_inst.CLK_FREQ = 100000;//------------- spi_flash_read -------------
spi_flash_read    spi_flash_read_inst(.sys_clk    (clk    ),  //input     sys_clk.sys_rst_n  (rst_n  ),  //input     sys_rst.pi_key     (key    ),  //input     key.miso       (miso   ),.sck        (sck    ),  //output    sck.cs_n       (cs_n   ),  //output    cs_n.mosi       (mosi   ),  //output    mosi.tx         (tx     ));//------------- memory -------------
m25p16  memory (.c          (sck    ), .data_in    (mosi   ), .s          (cs_n   ), .w          (1'b1   ), .hold       (1'b1   ), .data_out   (miso   )
);endmodule

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

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

相关文章

[LeetCode周赛复盘] 第 354 场周赛20230716

[LeetCode周赛复盘] 第 354 场周赛20230716 一、本周周赛总结6889. 特殊元素平方和1. 题目描述2. 思路分析3. 代码实现 6929. 数组的最大美丽值1. 题目描述2. 思路分析3. 代码实现 6927. 合法分割的最小下标1. 题目描述2. 思路分析3. 代码实现 6924. 最长合法子字符串的长度1.…

什么是统一建模语言(UML)UML与UML类图的基本概念

什么是统一建模语言UML&#xff08;Unified Modeling Language&#xff09; UML&#xff08;统一建模语言&#xff09;是一种通用的建模语言&#xff0c;用于描述软件系统的结构、行为和交互。它提供了一组符号和规则&#xff0c;用于创建可视化的图形模型&#xff0c;帮助开发…

【Leetcode】43. 字符串相乘

Halo&#xff0c;这里是Ppeua。平时主要更新C&#xff0c;数据结构算法&#xff0c;Linux与ROS…感兴趣就关注我bua&#xff01; Leetcode 43 题目&#xff1a;示例&#xff1a;题解&#xff1a;详细图解:代码实现: 题目&#xff1a; 示例&#xff1a; 题解&#xff1a; 这是…

DBeaver数据库管理工具安装连接PostgreSQL和DM

文章目录 1. 安装2. 连接PostgreSQL3. 连接DM83.1 下载驱动3.2 添加驱动3.3 连接3.4 创建表空间和用户3.5 执行sql 4. 连接Mysql 1. 安装 下载地址 https://dbeaver.io/download/ 2. 连接PostgreSQL 配置显示所有数据库 第二个勾选会显示模板数据库 点击测试连接&#xff0…

如何搭建个人博客?

博客成品展示&#xff1a; 首页&#xff1a; 代码高亮 文章分类 首先需要准备一台云服务器和域名。 域名没有备案的话推荐雨云的美国&#xff0c;速度挺快的。 点我跳转服务器购买地址 配置选入门版也够用了&#xff0c;一年大概200块钱不到&#xff0c;标准版更好咯&#x…

【UniApp开发小程序】项目创建+整合UI组件(FirstUI和uView)

创建项目 下图为初始化的项目的文件结构 引入组件 俗话说&#xff1a;“工欲善其事&#xff0c;必先利其器”&#xff0c;为了更加方便地开发出页面较为美观的小程序&#xff0c;我们先引入成熟的UI组件&#xff0c;再开始开发之旅。&#xff08;如果你是前端高手&#xff0…

mycat设置sql隔离级别的问题

问题 General log中出现大量SQL “SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ”。 该语句会引起两个问题&#xff0c; 1: "REPEATABLE READ"不是我们预期的事物隔离级别。 2: 大量无效的SQL影响性能。 注&#xff1a; MySql的可重复读会带来怎样…

[STM32教程]01如何开始准备hal库的开发环境

文章目录 概述1、认识硬件环境1.1 ARM简介1.2 STM32简介 2. 软件开发环境准备2.1 Keil MDK安装2.2 安装STM32Cube MX2.3 安装STM32 HAL库2.4 St-Link V2使用 总结 概述 本文介绍如何准备stm32f103的hal库工程开发环境&#xff0c;包括cubemx安装、keil mdk安装、stm32 hal库安…

Linux下如何部署Nuxt项目(二)

Linux下如何部署Nuxt项目(一)_小鸟哗啦啦的博客-CSDN博客&#xff0c;书接上回&#xff0c;以实际场景开始。 请认真看完这篇文章&#xff0c;还不会部署Nuxt&#xff0c;我直接拿弹弓打你们家玻璃&#xff01; 一、nuxt的配置检查 服务端渲染的应用&#xff0c;应该是先编译构…

【从零开始学习JAVA | 第二十九篇】Stream流

目录 前言&#xff1a; Stram流&#xff1a; 设计目标&#xff1a; 使用步骤&#xff1a; 1.先得到一条Stream流&#xff0c;并把数据放上去。 2.利用Stream流中的各种API进行操作。 使用Stream流的注意事项&#xff1a; 总结: 前言&#xff1a; 本文我们将学习Stream流…

vue3 前端编码规范

prettier 配置 1. vscode 安装prettier 的 插件 2. 新建 .prettierrc 文件 {"semi": false, // 不尾随分号"singleQuote": true, // 使用单引号"trailingComma": "none" // 多行逗号分隔的语法&#xff0c;最后一行不加逗号 }eslin…

《远见》阅读笔记

不同的环境&#xff0c;不同的职业&#xff0c;职业生涯的建议并没有什么不同 找到热爱的工作&#xff0c;建立热爱的生活 如何思考职业远景 如何分配时间 如何扩张人脉 职业生涯决策框架 三个部分 职场思维、框架、工具实用性建议和案例现实生活为基础&#xff0c;平衡职…