目录

Flash数据普通读操作

实现原理

verilog设计代码

verilog测试代码


Flash数据普通读操作

实现原理

  1. 将片选信号拉低,写入读操作指令,最少读取一个字节的数据,写入读指令后要写入三个字节的读取地址,读操作指令和读取地址在SCK的上升沿被锁存,读数据在miso端口输出,数据在SCK的下降沿更新,读操作指令在数据手册中查看
  2. 输入的读取地址会自动进行加一操作,即可以读取整个Flash的数据,若读取到最大地址,则地址会归零,若想停止读取,则拉高片选信号
  3. 在进行擦除和写操作时,读操作是无法进行的;
  4. 需要查看数据手册中Flash读操作对时钟频率的要求。

verilog设计代码

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

verilog测试代码

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

基于SPI协议的Flash驱动控制-数据普通读操作相关推荐

  1. 基于SPI协议的Flash驱动控制-扇区擦除

    目录 Flash扇区擦除 实现原理 verilog设计代码 verilog测试代码 Flash扇区擦除 实现原理 扇区的概念 Flash型号的数字代表容量,单位兆bit,如M25P16,此Flash的 ...

  2. FPGA进阶(2):基于I2C协议的EEPROM驱动控制

    文章目录 第49讲:基于I2C协议的EEPROM驱动控制 理论部分 设计与实现 i2c_ctrl i2c_rw_data eeprom_byte_rd_wr tb_eeprom_byte_rd_wr ...

  3. 基于I2C协议的EEPROM驱动控制

    基于I2C协议的EEPROM驱动控制 `timescale 1ns / 1ps module i2c_ctrl #(parameter DEVICE_ADDR = 7'b1010_000,//i2c设 ...

  4. 基于SPI协议的Flash全擦除

    基于SPI协议的Flash全擦除 `timescale 1ns / 1ps module flash_be_ctrl(input wire sys_clk,//系统时钟频率50MHZ input wi ...

  5. 基于I2C协议的EEPROM驱动控制(笔记整理)

    一.目标 要求:设计一个使用I2C通讯协议的EEPROM读写控制器.使用写按键向EEPROM中写入1~10共10字节数据:使用读按键读出之前写入的数据并显示在数码管上. 分析:①首先按键控制读写操作按 ...

  6. FPGA实现的SPI协议(二)----基于SPI接口的FLASH芯片M25P16的使用

    写在前面 SPI协议系列文章: FPGA实现的SPI协议(一)----SPI驱动 FPGA实现的SPI协议(二)----基于SPI接口的FLASH芯片M25P16的使用 在上篇文章,简要介绍了SPI协 ...

  7. 基于SPI协议下的OLED显示

    文章目录 一.SPI简介 二.OLED显示 1.任务要求 2.实验器材 3.实验过程 (1)显示自己的学号和姓名 (2) 显示AHT20的温度和湿度 (3)上下或左右的滑动显示长字符(SSD1306驱 ...

  8. 基于 SPI 协议的0.96 寸OLED显示

    目录 一. SPI 协议 1.简介 2.SPI的连接方式 3.通信过程​ 二.OLED 1.OLED原理 2.点阵编码原理与显示 三.OLED显示实验 Demo 程序 1.要求 2. OLED 显示汉 ...

  9. 基于VXWORKS的NAND FLASH驱动程序设计

    基于VXWORKS的NAND FLASH驱动程序设计 3162412793@qq.com 技术交流QQ群: 691976956 目前,随着电子技术的不断发展,计算机技术也得到飞速的发展,产生了很多新技 ...

最新文章

  1. 1.7 Java创建对象详解(显式创建和隐含创建)
  2. media player怎么不能拖进度图mp4_榜样力量丨科研路上有难题,学长教你怎么解
  3. 数学物理方法pdf_《数学物理方法》周明儒(第2版)补充材料与习题详解
  4. 机器学习中梯度下降法和牛顿法的比较
  5. h5页面 pc端html 调用QQ群
  6. 倍周期分岔 matlab,由倍周期分岔走向混沌-Read.DOC
  7. CSDN如何获得积分?
  8. spyder selenium配置
  9. 仿站王者:Teleport Ultra
  10. layim在线客服 架构实现
  11. 【无标题】drv8825步进电机驱动板子原理图
  12. mac怎么压缩pdf文件最小
  13. 手机如何卸载android,怎样删除手机自带软件(安卓手机自带软件怎么卸载)
  14. 服务器上网站文件无法删除不了怎么办啊,Windows服务器上文件夹删不掉怎么办...
  15. 好用的菜单栏翻译软件Bob使用教程,Bob怎么打开录屏权限
  16. 【电力系统】基于凸松弛算法的电力市场策略(Matlab代码实现)
  17. 项目一:CRM(客户关系管理系统)--9---自定制action
  18. OpenCV C++开发 第一节:Win7开发环境搭建
  19. html+css+js简单实现图片轮播效果
  20. 【MacOS】虚拟机Vmware安装MacOS

热门文章

  1. 通过ipmitool监控机房内服务器温度
  2. 手机安装青龙面板,低功耗,随时随地的薅羊毛(无需服务器)
  3. 【C++】Lambda 表达式详解
  4. python白噪声检验_时间序列 平稳性检验 白噪声 峰度 偏度
  5. Gitlab-runner(一)安装
  6. 【Qt】动态刷新lcdNumber显示的值
  7. 在编程中常见的一些英语词汇
  8. MonkeyRunner_MonkeyRunner,MonkeyDevice,MonkeyImage可以调用的方法
  9. Mac 使用Charles后,退出Charles后,不能浏览网页,提示:未连接到互联网代理服务器出现问题,或者地址有误。
  10. GEE|假彩色目视解译山东省玉米、水稻、小麦等样本集制作代码