flash的指定扇区擦除实验。
先发写指令,再进入写锁存周期等待500ns,进入写扇区擦除指令,然后写扇区地址,页地址,字节地址。即可完成扇区擦除。
模块框图:
时序图:
代码:
module spi (
input wire sys_clk ,
input wire sys_rst_n ,
input wire key_start ,
output wire miso ,
output reg mosi ,
output reg cs_n ,
output reg sck
);
// parameter
parameter COMD_W = 8'h06 , // 写指令
COMD_B = 8'hc7 , // 全擦除指令
COMD_S = 8'hd8 ; // 扇区擦除指令
parameter ADR_SE = 8'h00 , // 扇区地址 adress secter
ADR_PA = 8'h04 , // 页地址 adress page
ADR_BY = 8'h25 ; // 字节地址 adress byte
parameter IDLE = 4'b0001 ,
WREN = 4'b0010 ,
WEL = 4'b0100 ,
SE = 4'b1000 ;
// wire signal degine
wire IDLEtoWREN;
wire WRENtoWEL ;
wire WRENtoSE ;
wire SEtoIDLE ;
// reg signal define
reg [3:0] state_c ;
reg [3:0] state_n ;
reg [3:0] cnt_20ns ;
reg [3:0] cnt_bit ;
reg [3:0] cnt_byte ;
reg flag_bit ;
reg f_b_reg ; // flag_bit_reg的缩写
/****************************************************************************/
// 三段式状态机
// 现态与次态描述
// state_c
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
state_c <= IDLE ;
else
state_c <= state_n ;
end
// state_n
always @(*) begin
case (state_c)
IDLE :if(IDLEtoWREN)
state_n <= WREN ;
else
state_n <= IDLE ;
WREN :if(WRENtoWEL)
state_n <= WEL ;
else
state_n <= WREN ;
WEL :if(WRENtoSE)
state_n <= SE ;
else
state_n <= WEL ;
SE :if(SEtoIDLE)
state_n <= IDLE ;
else
state_n <= SE ;
default: state_n <= IDLE ;
endcase
end
// 状态转移描述
assign IDLEtoWREN = ( state_c == IDLE) && ( key_start ) ;
assign WRENtoWEL = ( state_c == WREN) && ( f_b_reg ) ;
assign WRENtoSE = ( state_c == WEL ) && ( cnt_20ns == 6 ) ;
assign SEtoIDLE = ( state_c == SE ) && ( f_b_reg ) ;
// 相关信号描述
// reg [3:0] cnt_20ns ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_20ns <= 4'd0 ;
else
case (state_c)
IDLE : cnt_20ns <= 4'd0 ;
WREN : if(cnt_20ns || f_b_reg)
cnt_20ns <= 4'd0 ;
else
cnt_20ns <= cnt_20ns + 1'b1 ;
WEL : if(cnt_20ns == 6) // 60x20ns==120ns
cnt_20ns <= 4'd0 ;
else
cnt_20ns <= cnt_20ns + 1'b1 ;
SE : if(cnt_20ns || f_b_reg)
cnt_20ns <= 4'd0 ;
else
cnt_20ns <= cnt_20ns + 1'b1 ;
default: cnt_20ns <= 4'd0 ;
endcase
end
// reg [3:0] cnt_bit ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_bit <= 4'd0 ;
else
case (state_c)
IDLE : cnt_bit <= 4'd0 ;
WREN : if(!cnt_20ns && sck && cnt_bit == 7)
cnt_bit <= 4'd0 ;
else if(!cnt_20ns && sck)
cnt_bit <= cnt_bit + 1'b1 ;
WEL : cnt_bit <= 4'd0 ;
SE : if(!cnt_20ns && sck && cnt_bit == 7)
cnt_bit <= 4'd0 ;
else if(!cnt_20ns && sck)
cnt_bit <= cnt_bit + 1'b1 ;
default: cnt_bit <= 4'd0 ;
endcase
end
// reg [3:0] cnt_byte
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_byte <= 4'd0 ;
else if(cnt_bit == 7 && !cnt_20ns && sck && cnt_byte == 4)
cnt_byte <= 4'd0 ;
else if(cnt_bit == 7 && !cnt_20ns && sck)
cnt_byte <= cnt_byte + 1'b1 ;
else
cnt_byte <= cnt_byte ;
end
// reg flag_bit ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
flag_bit <= 1'b0 ;
else
case (state_c)
IDLE : flag_bit <= 1'b0 ;
WREN : if(cnt_bit == 7 && sck && !cnt_20ns)
flag_bit <= 1'b1 ;
else
flag_bit <= flag_bit ;
WEL : flag_bit <= 1'b0 ;
SE : if(cnt_bit == 7 && sck && !cnt_20ns && cnt_byte == 4)
flag_bit <= 1'b1 ;
else
flag_bit <= flag_bit ;
default: flag_bit <= 1'b0 ;
endcase
end
// reg f_b_reg ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
f_b_reg <= 1'b0 ;
end else begin
f_b_reg <= flag_bit ;
end
end
// output signal
// wire miso ,
assign miso = 1'bz ;
// mosi
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
mosi <= 1'b0 ;
else
case (state_c)
IDLE : mosi <= 1'b0 ;
WREN : if(!cnt_bit) // (cnt_bit == 0)
mosi <= COMD_W[7] ;
else if(cnt_20ns && sck)
mosi <= COMD_W[7 - cnt_bit] ;
else
mosi <= mosi ;
WEL : mosi <= 1'b0 ;
SE : case (cnt_byte)
1:
begin
if(!cnt_bit)
mosi <= COMD_S[7] ;
else if(cnt_20ns && sck)
mosi <= COMD_S[7 - cnt_bit] ;
else
mosi <= mosi ;
end
2:
begin
if(!cnt_bit)
mosi <= ADR_SE[7] ;
else if(cnt_20ns && sck)
mosi <= ADR_SE[7 - cnt_bit] ;
else
mosi <= mosi ;
end
3:
begin
if(!cnt_bit)
mosi <= ADR_PA[7] ;
else if(cnt_20ns && sck)
mosi <= ADR_PA[7 - cnt_bit] ;
else
mosi <= mosi ;
end
4:
begin
if(!cnt_bit)
mosi <= ADR_BY[7] ;
else if(cnt_20ns && sck)
mosi <= ADR_BY[7 - cnt_bit] ;
else
mosi <= mosi ;
end
default: mosi <= 1'b0 ;
endcase
default: mosi <= 1'b0 ;
endcase
end
// reg cs_n ,
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
cs_n <= 1'b1 ;
end else begin
case (state_c)
IDLE : if(key_start)
cs_n <= 1'b0 ;
else
cs_n <= 1'b1 ;
WREN : if(f_b_reg)
cs_n <= 1'b1 ;
else
cs_n <= cs_n ;
WEL : if(cnt_20ns == 6)
cs_n <= 1'b0 ;
else
cs_n <= cs_n ;
SE : if(f_b_reg)
cs_n <= 1'b1 ;
else
cs_n <= cs_n ;
default: cs_n <= 1'b1 ;
endcase
end
end
// reg sck
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
sck <= 1'b0 ;
else
case (state_c)
IDLE : sck <= 1'b0 ;
WREN : if(cnt_20ns)
sck <= ~sck ;
else
sck <= sck ;
WEL : sck <= 1'b0 ;
SE : if(cnt_20ns)
sck <= ~sck ;
else
sck <= sck ;
default: sck <= 1'b0 ;
endcase
end
endmodule
module top(
input wire sys_clk ,
input wire sys_rst_n ,
input wire key_in ,
output wire cs_n ,
output wire sck ,
output wire mosi
);
// 例化间连线
wire key_flag ;
key_filter key_filter_inst(
.sys_clk ( sys_clk ) ,
.sys_rst_n ( sys_rst_n ) ,
.key_in ( key_in ) ,
.key_out ( key_flag )
);
spi spi_inst(
.sys_clk ( sys_clk ) ,
.sys_rst_n ( sys_rst_n ) ,
.key_start ( key_flag ) ,
.mosi ( mosi ) ,
.miso ( ) ,
.cs_n ( cs_n ) ,
.sck ( sck )
);endmodule
module key_filter
#(
parameter MAX_CNT_20MS = 20'd100_0000
)(
input wire sys_clk ,
input wire sys_rst_n ,
input wire key_in ,
output wire key_out
);
reg key_r_0 ;
reg key_r_1 ;
wire nege ;
wire pose ;
reg [19:00] cnt_20ms ;
wire add_cnt_20ms ;
wire end_cnt_20ms ;
reg add_cnt_flag ;
// key_r_0 key_r_1
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
key_r_0 <= 1'b1 ;
end else begin
key_r_0 <= key_in ;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
key_r_1 <= 1'b1 ;
end else begin
key_r_1 <= key_r_0 ;
end
end
// nege pose
assign nege = ~key_r_0 && key_r_1 ;
assign pose = key_r_0 && ~key_r_1 ;
// add_cnt_flag
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
add_cnt_flag <= 1'b0 ;
end else begin
if(nege) begin
add_cnt_flag <= 1'b1 ;
end else begin
if( pose || end_cnt_20ms ) begin
add_cnt_flag <= 1'b0 ;
end else begin
add_cnt_flag <= add_cnt_flag ;
end
end
end
end
// cnt_20ms add_cnt_20ms end_cnt_20ms
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
cnt_20ms <= 20'd0 ;
end else begin
if(add_cnt_20ms) begin
if(end_cnt_20ms) begin
cnt_20ms <= 20'd0 ;
end else begin
cnt_20ms <= cnt_20ms + 20'd1 ;
end
end else begin
cnt_20ms <= 20'd0 ;
end
end
end
assign add_cnt_20ms = add_cnt_flag ;
assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == ( MAX_CNT_20MS - 1'b1 ) ;
// key_out
// always @(posedge sys_clk or negedge sys_rst_n) begin
// // always @(*) begin // 这样的话 会综合成 数据选择器
// if(~sys_rst_n) begin
// key_out <= 1'b0 ;
// end else begin
// if(end_cnt_20ms) begin
// key_out <= 1'b1 ;
// end else begin
// key_out <= 1'b0 ;
// end
// end
// end
assign key_out = end_cnt_20ms ;
endmodule
仿真图:忘记截屏了。
需要用到仿真模型。
上版验证通过。