目录
Flash的全擦除
实现原理
- 首先查看数据手册查询全擦除指令,全擦除指令把Flash中所有位都置1,Flash为空时,所有位默认为1;
- 在写入全擦除指令之前需要写入写使能指令WREN,写入时拉低片选信号,写入完成拉高片选信号,写入写使能指令后便会变为写锁存状态,在此状态下才能进行全擦除指令写入;
- 写入全擦除指令BE,全擦除指令写入时片选信号为低电平,通过MOSI端口写入指令,写入完成则将片选信号拉高,若不拉高,则此指令不会执行;
- 全擦除指令写入后要等待一个全擦除周期完成擦除操作,周期时间可查看数据手册中的
;
- 以上步骤需要遵循串行输入时序,可在数据手册中查看,见下图;
- 需要查看数据手册中Flash读写操作对时钟频率的要求。
片选信号建立时间
:片选信号拉低到第一个bit数据开始输入的时间,大于5ns;
片选信号保持时间
:最后一个bit数据输入完成到片选信号拉高的时间,大于5ns;
两指令间的等待时间
:写使能指令写入后需要等待固定时间才能写入全擦除指令,大于100ns。
verilog设计代码
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 [2:0] cnt_byte; //字节计数器
reg [3:0] state ; //状态机状态
reg [4:0] cnt_clk ; //系统时钟计数器
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 <= 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:串行时钟计数器,用以生成串行时钟
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 == BE) && (cnt_byte == 3'd5))
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 == 3'd2) && (cnt_clk == 5'd31) && (state == WR_EN))
cs_n <= 1'b1;
else if((cnt_byte == 3'd3) && (cnt_clk == 5'd31) && (state == DELAY))
cs_n <= 1'b0;
else if((cnt_byte == 3'd6) && (cnt_clk == 5'd31) && (state == BE))
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;
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((state == WR_EN) && (cnt_byte == 3'd2))
mosi <= 1'b0;
else if((state == BE) && (cnt_byte == 3'd6))
mosi <= 1'b0;
else if((state == WR_EN) && (cnt_byte == 3'd1) && (cnt_sck == 5'd0))
mosi <= WR_EN_INST[7 - cnt_bit]; //写使能指令
else if((state == BE) && (cnt_byte == 3'd5) && (cnt_sck == 5'd0))
mosi <= BE_INST[7 - cnt_bit]; //全擦除指令
endmodule
verilog测试代码
module tb_flash_be_ctrl();
//wire define
wire cs_n ; //Flash片选信号
wire sck ; //Flash串行时钟
wire mosi ; //Flash主输出从输入信号
//reg define
reg sys_clk ; //模拟时钟信号
reg sys_rst_n ; //模拟复位信号
reg key ; //模拟全擦除触发信号
//时钟、复位信号、模拟按键信号
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
key <= 1'b0;
#100
sys_rst_n <= 1'b1;
#1000
key <= 1'b1;
#20
key <= 1'b0;
end
always #10 sys_clk <= ~sys_clk; //模拟时钟,频率50MHz
//写入Flash仿真模型初始值(全F)
defparam memory.mem_access.initfile = "initmemory.txt";
//------------- flash_be_ctrl_inst -------------
flash_be_ctrl flash_be_ctrl_inst
(
.sys_clk (sys_clk ), //输入系统时钟,频率50MHz,1bit
.sys_rst_n (sys_rst_n ), //输入复位信号,低电平有效,1bit
.key (key ), //按键输入信号,1bit
.sck (sck ), //输出串行时钟,1bit
.cs_n (cs_n ), //输出片选信号,1bit
.mosi (mosi ) //输出主输出从输入数据,1bit
);
//------------- 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