M25P128 PP操作的注意点
我们本次实验的内容是,对flash写一个字节的数据:
所用到的软硬件环境为:
硬件:锆石A4plus开发板
软件:quartus II 13.1
从技术手册中我们可以得到如下信息:
从上面的信息中我们提取如下信息:
1、PP操作之前必须有写使能操作被执行;
2、PP操作连续写只能对一页写,超过256个数据只保存最后256个数据到页中;
3、整个操作服从的协议是SPI协议
时序图设计
由手册中的时序图我们可以知道,该时序与flash的扇区擦除指令的时序几乎一摸一样,只是在擦除的指令上多了8个sck,所以设计的时序图如下:
相信同学们学会了扇区擦除指令,PP操作的指令可以很容易理解。
flash_write模块的书写
这里的传统不说废话,直接上代码:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : flash_write.v
// Create Time : 2020-01-09 11:14:30
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module flash_write(
input sclk ,
input rst_n ,
input key_flag ,
output reg cs_n ,
output reg sck ,
output reg sdi ,
input [ 7:0] data_in
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter IDLE = 4'b0001 ;
parameter WREN = 4'b0010 ;
parameter DELAT = 4'b0100 ;
parameter PP = 4'b1000 ;
parameter WREN_INST = 8'h06 ;
parameter WRITE_INST = 8'h02 ;
parameter WRITE_ADDR = 24'h00_03_21 ;
reg [ 3:0] state ;
reg [ 4:0] cnt_32 ;
reg [ 2:0] cnt_state ;
reg [ 1:0] cnt_4 ;
reg [ 5:0] bit_cnt ;
reg [ 7:0] data_in_reg ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
data_in_reg <= 7'd0;
else if(key_flag == 1'b1)
data_in_reg <= data_in;
else
data_in_reg <= data_in_reg;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
cs_n <= 1'b1;
else if(key_flag == 1'b1)
cs_n <= 1'b0;
else if(state == WREN && cnt_32 == 'd31 && cnt_state == 'd2)
cs_n <= 1'b1;
else if(state == DELAT && cnt_32 == 'd31)
cs_n <= 1'b0;
else if(state == PP && cnt_32 == 'd31 && cnt_state == 'd6)
cs_n <= 1'b1;
else
cs_n <= cs_n;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
state <= IDLE;
else case(state)
IDLE : if(key_flag == 1'b1)
state <= WREN;
else
state <= state;
WREN : if(cnt_32 == 'd31 && cnt_state == 'd2)
state <= DELAT;
else
state <= state;
DELAT : if(cnt_32 == 'd31)
state <= PP;
else
state <= state;
PP : if(cnt_32 == 'd31 && cnt_state == 'd6)
state <= IDLE;
else
state <= state;
default : state <= IDLE;
endcase
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
cnt_32 <= 5'd0;
else if(cnt_32 == 'd31)
cnt_32 <= 5'd0;
else if(state != IDLE)
cnt_32 <= cnt_32 + 1'b1;
else
cnt_32 <= 5'd0;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
cnt_state <= 3'd0;
else if(state == IDLE)
cnt_state <= 3'd0;
else if(state == WREN && cnt_32 == 'd31 && cnt_state == 'd2)
cnt_state <= 3'd0;
else if(state == DELAT && cnt_32 == 'd31)
cnt_state <= 3'd0;
else if(state == PP && cnt_32 == 'd31 && cnt_state == 'd6)
cnt_state <= 3'd0;
else if(cnt_32 == 'd31)
cnt_state <= cnt_state + 1'b1;
else
cnt_state <= cnt_state;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
cnt_4 <= 'd0;
else if(state == WREN && cnt_state == 'd1)
cnt_4 <= cnt_4 + 1'b1;
else if(state == PP && cnt_state >= 'd1 && cnt_state <= 'd5)
cnt_4 <= cnt_4 + 1'b1;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
sck <= 1'b0;
else if(cnt_4 == 'd0)
sck <= 1'b0;
else if(cnt_4 == 'd2)
sck <= 1'b1;
else
sck <= sck;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
sdi <= 1'b0;
else if(state == WREN && cnt_state == 'd1 && cnt_4 == 'd0)
sdi <= WREN_INST[7-bit_cnt];
else if(state == PP && cnt_state == 'd1 && cnt_4 == 'd0)
sdi <= WRITE_INST[7-bit_cnt];
else if(state == PP && cnt_4 == 'd0 && cnt_state > 'd1 && cnt_state <= 'd4)
sdi <= WRITE_ADDR[31-bit_cnt];
else if(state == PP && cnt_4 == 'd0 && cnt_state == 'd5)
sdi <= data_in_reg[39-bit_cnt];
else if(state == PP && cnt_32 == 'd31 && cnt_state == 'd5)
sdi <= 1'b0;
else
sdi <= sdi;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
bit_cnt <= 5'd0;
else if(state == WREN && bit_cnt == 'd7 && cnt_4 == 'd2)
bit_cnt <= 5'd0;
else if(state == PP && bit_cnt == 'd39 && cnt_4 == 'd2)
bit_cnt <= 5'd0;
else if(cnt_4 == 'd2)
bit_cnt <= bit_cnt + 1'b1;
else
bit_cnt <= bit_cnt;
endmodule
我们上面的代码就是在flash擦除模块的基础上稍作修改得到的。
flash_write测试模块的代码
这里为了方便同学们调试代码,直接给出该模块的测试代码:
`timescale 1ns / 1ps
`define CLOCK 20
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : flash_earse_tb.v
// Create Time : 2020-01-08 19:57:13
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module flash_write_tb();
reg sclk ;
reg rst_n ;
reg key_flag ;
wire cs_n ;
wire sck ;
wire sdi ;
initial begin
sclk <= 1'b0;
rst_n <= 1'b0;
key_flag <= 1'b0;
#(100*`CLOCK)
rst_n <= 1'b1;
#(100*`CLOCK)
key_flag <= 1'b1;
#(`CLOCK)
key_flag <= 1'b0;
#(1000*`CLOCK)
key_flag <= 1'b1;
#(`CLOCK)
key_flag <= 1'b0;
end
always #(`CLOCK/2) sclk <= ~sclk;
flash_write flash_write_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.key_flag (key_flag ),
.cs_n (cs_n ),
.sck (sck ),
.sdi (sdi ),
.data_in (8'haa )
);
endmodule
其他模块的代码
为了方便同学们可以直接使用该代码,这里我们将所有的代码复制如下,整体的工程也可以进群自取:
key模块代码:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : key.v
// Create Time : 2020-01-05 13:49:36
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module key(
input sclk ,
input rst_n ,
input key ,
output reg key_o
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter IDLE = 4'b0001 ;
parameter S1 = 4'b0010 ;
parameter S2 = 4'b0100 ;
parameter S3 = 4'b1000 ;
reg [ 3:0] state ;
reg [ 9:0] cnt ;
reg key_r1 ;
reg key_r2 ;
reg key_r3 ;
reg nege_flag ;
reg pose_flag ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
always @(posedge sclk)
key_r1 <= key;
always @(posedge sclk)
key_r2 <= key_r1;
always @(posedge sclk)
key_r3 <= key_r2;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
nege_flag <= 1'b0;
else if(key_r3 == 1'b1 && key_r2 == 1'b0)
nege_flag <= 1'b1;
else
nege_flag <= 1'b0;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
pose_flag <= 1'b0;
else if(key_r3 == 1'b0 && key_r2 == 1'b1)
pose_flag <= 1'b1;
else
pose_flag <= 1'b0;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
state <= IDLE;
else case(state)
IDLE : if(nege_flag == 1'b1)
state <= S1;
else
state <= IDLE;
S1 : if(cnt == 10'd999)
state <= S2;
else if(pose_flag == 1'b1)
state <= IDLE;
else
state <= S1;
S2 : if(pose_flag == 1'b1)
state <= S3;
else
state <= S2;
S3 : if(cnt == 10'd999)
state <= IDLE;
else if(nege_flag == 1'b1)
state <= S2;
else
state <= S3;
default : state <= IDLE;
endcase
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
cnt <= 10'd0;
else if(state != S1 && state != S3)
cnt <= 10'd0;
else
cnt <= cnt + 1'b1;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
key_o <= 1'b0;
else if(state == S1 && cnt == 10'd999)
key_o <= 1'b1;
else
key_o <= 1'b0;
endmodule
tiop模块的代码:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : nnzhang1996@foxmail.com
// Website :
// Module Name : top.v
// Create Time : 2020-01-08 21:18:52
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module top(
input sclk ,
input rst_n ,
input key ,
output wire cs_n ,
output wire sck ,
output wire sdi
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
wire key_flag ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
key key_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.key (~key ),
.key_o (key_flag )
);
flash_write flash_write_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.key_flag (key_flag ),
.cs_n (cs_n ),
.sck (sck ),
.sdi (sdi ),
.data_in (8'h30 )
);
endmodule
实验结果
这里由于没有什么现象,我们将在下篇文章的flash读操作中一起验证模块的正确性。在调试时,我也使用了逻辑分析仪进行调试,时序结果均正确。
结束语
创作不易,认为文章有帮助的同学们可以收藏点赞支持。(工程也都在群中)对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
来源:CSDN
作者:朽月
链接:https://blog.csdn.net/zhangningning1996/article/details/103935491