基于SPI协议的SPI-FLASH(M25P16V/W25Q16JV)控制器-全擦除

本文基于【野火】FPGA开发板视频教程及资料,首先对野火公司表示衷心感谢,我认为原波形图有进一步便于理解和整齐的画法,代码也有可以精简的地方,在这里分享给大家,代码通过Modelsim行为级验证。

目录

波形图

代码

行为级仿真


 波形图

基于SPI协议的SPI-FLASH(M25P16V/W25Q16JV)控制器-全擦除_第1张图片


代码

`timescale  1ns/1ns

// Author        : NSSC_小天
// Create Date   : 2022/11/20
// Module Name   : flash_be_ctrl
// Project Name  : spi_flash_be
// Target Devices: 黑金 AX309
// Tool Versions : ISE 14.7
// Description   : flash全擦除模块
// Revision      : V1.0


module  flash_be_ctrl
(
    input   wire            sys_clk     ,   //系统时钟,频率50MHz
    input   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 ,   		//等待状态
            BE      =   4'b1000 ;   		//全擦除状态
parameter   WR_EN_INST  =   8'b0000_0110,   //写使能指令
            BE_INST     =   8'b1100_0111;   //全擦除指令

//reg   define
reg     [4:0]   cnt_clk ;   //系统时钟计数器
reg     [3:0]   state   ;   //状态机状态
reg     [2:0]   cnt_byte;   //字节计数器
reg     [1:0]   cnt_sck ;   //串行时钟计数器
reg     [2:0]   cnt_bit ;   //比特计数器

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//cnt_clk:系统时钟计数器-640ns,即作为单个byte的发送周期,也作为t_SLCH,t_CHSH,t_SLCH的等待时间
//2的5次方=32,计数0-31,自动溢出
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    <=  3'd0;
    else    if((cnt_clk == 5'd31) && (cnt_byte == 3'd6))
        cnt_byte    <=  3'd0;
    else    if(cnt_clk == 31)
        cnt_byte    <=  cnt_byte + 1'b1;

//cnt_sck:串行时钟计数器,用以生成串行时钟,4分频,12.5Mhz
//2的2次方=4,计数0-3,自动溢出
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_sck <=  2'd0;
    else    if(cnt_byte == 3'b1)
        cnt_sck <=  cnt_sck + 1'b1;
    else    if(cnt_byte == 3'd5)
        cnt_sck <=  cnt_sck + 1'b1;		

//cnt_bit:控制mosi输出指令的哪一位
//2的3次方=8,计数0-7,自动溢出
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_bit <=  3'd0;
    else    if(cnt_sck == 2'd1)
        cnt_bit <=  cnt_bit + 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'd3)
        sck <=  1'b0;
    else    if(cnt_sck == 2'd1)
        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 == 3'd2) && (cnt_clk == 5'd31))
        cs_n    <=  1'b1;
    else    if((cnt_byte == 3'd3) && (cnt_clk == 5'd31))
        cs_n    <=  1'b0;
    else    if((cnt_byte == 3'd6) && (cnt_clk == 5'd31))
        cs_n    <=  1'b1;

//state:两段式状态机第一段,状态跳转
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        state   <=  IDLE;
    else
    case(state)
        IDLE:   if(key == 1'b1)
                state   <=  WR_EN;
        WR_EN:  if((cnt_byte == 3'd2) && (cnt_clk == 5'd31))
                state   <=  DELAY;
        DELAY:  if((cnt_byte == 3'd3) && (cnt_clk == 5'd31))
                state   <=  BE;
        BE:     if((cnt_byte == 3'd6) && (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((cnt_byte == 3'd0) && (cnt_clk == 5'd31))
        mosi    <=  WR_EN_INST[7];    			//写使能指令[7]
    else    if((cnt_byte == 3'd1) && (cnt_sck == 2'd3) && (cnt_clk != 5'd31))
        mosi    <=  WR_EN_INST[7 - cnt_bit];    //写使能指令[6-0]
	else    if((cnt_byte == 3'd1) && (cnt_clk == 5'd31))
        mosi    <=  1'b0;
	else    if((cnt_byte == 3'd4) && (cnt_clk == 5'd31))
        mosi    <=  BE_INST[7];    				//全擦除指令[7]
    else    if((cnt_byte == 3'd5) && (cnt_sck == 2'd3) && (cnt_clk != 5'd31))
        mosi    <=  BE_INST[7 - cnt_bit];       //全擦除指令[6-0]
    else    if((cnt_byte == 3'd5) && (cnt_clk == 5'd31))
        mosi    <=  1'b0;
endmodule

行为级仿真波形

你可能感兴趣的:(FPGA_软件,fpga开发)