本次实验所使用的软硬件环境如下:
硬件:锆石A4plus开发板
软件:quartus II 13.1
这里吐槽一句,个人感觉锆石的开发板还是做的不错的(虽然配套代码垃圾),就是搞不懂为什么公司倒闭了。
M25P128芯片的结构图如下,整个芯片被细分了扇区和页。该芯片总共128Mbit总容量,每个扇区512Kbit空间,每页256Bytes空间。支持整块擦出和扇区擦除。
该芯片的存储信息可以总结为:芯片包括256个扇区,每个扇区包括256页,每页包括256Bytes。具体的换算信息大家可以自我换算得到。
每个操作的指令代码如下:
从该扇区擦出的技术手册中我们需要得到的信息是:
1:扇区擦出是把整个扇区写成1;
2:扇区擦出指令之前,写使能指令必须被执行;
3:扇区擦出的地址只要是该扇区的任意一个地址即可;
所以我们还得观察写使能部分的技术手册:
从写使能部分的说明来看,就是简单的SPI协议没有任何特殊。
接下来我们需要找到几个重要的参量。
1、SCK的时钟频率;
2、片选拉低到第一个时钟上升沿的最小时间, t S L C H t_{SLCH} tSLCH;
3、最后一个时钟上升沿到片选拉高所需要的最低时间, t C H S H t_{CHSH} tCHSH;
4、片选拉低距离上一次片选拉高的最低时间, t S H S L t_{SHSL} tSHSL;
具体情况如下图:
从该表中我们查询信息可以知道:
SCK的时钟频率:不同操作不一样,有的命令是50Mhz,有的是20Mhz,所以我们这里选择12.5Mhz。
片选拉低到第一个时钟上升沿的最小时间:5ns
最后一个时钟上升沿到片选拉高所需要的最低时间:5ns
片选拉低距离上一次片选拉高的最低时间:100ns
所以设计需要知道的信息,我们均从技术手册中获得,接下来开始设计时序。
本次实验的内容是,按键按下,一个扇区擦出指令被执行。系统框图如下:
这里不多说废话,直接贴上时序图,相信大家从时序图中可以知道具体的设计方法。
由上面设计的时序图可以很轻松的得到下面的代码:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// Website :
// Module Name : flash_earse.v
// Create Time : 2020-01-08 18:57:42
// 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_earse(
input sclk ,
input rst_n ,
input key_flag ,
output reg cs_n ,
output reg sck ,
output reg sdi
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter IDLE = 4'b0001 ;
parameter WREN = 4'b0010 ;
parameter DELAT = 4'b0100 ;
parameter SE = 4'b1000 ;
parameter WREN_INST = 8'h06 ;
parameter SE_INST = 8'hd8 ;
parameter SE_ADDR = 24'h00_a1_12 ;
reg [ 3:0] state ;
reg [ 4:0] cnt_32 ;
reg [ 2:0] cnt_state ;
reg [ 1:0] cnt_4 ;
reg [ 4:0] bit_cnt ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
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 == SE && cnt_32 == 'd31 && cnt_state == 'd5)
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 <= SE;
else
state <= state;
SE : if(cnt_32 == 'd31 && cnt_state == 'd5)
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 == SE && cnt_32 == 'd31 && cnt_state == 'd5)
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 == SE && cnt_state >= 'd1 && cnt_state <= 'd4)
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 == SE && cnt_state == 'd1 && cnt_4 == 'd0)
sdi <= SE_INST[7-bit_cnt];
else if(state == SE && cnt_4 == 'd0 && cnt_state > 'd1 && cnt_state <= 'd4)
sdi <= SE_ADDR[31-bit_cnt];
else if(state == SE && cnt_32 == 'd31 && cnt_state == 'd4)
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 == SE && bit_cnt == 'd31 && cnt_4 == 'd2)
bit_cnt <= 5'd0;
else if(cnt_4 == 'd2)
bit_cnt <= bit_cnt + 1'b1;
else
bit_cnt <= bit_cnt;
endmodule
大家应该已经知道我的风格,给出测试代码一定会给出测试代码:
`timescale 1ns / 1ps
`define CLOCK 20
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// 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_earse_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_earse flash_earse_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.key_flag (key_flag ),
.cs_n (cs_n ),
.sck (sck ),
.sdi (sdi )
);
endmodule
这里为了防止同学们麻烦,我们直接把其他模块的代码也贴上:
key模块
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// 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
top模块:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// 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_earse flash_earse_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.key_flag (key_flag ),
.cs_n (cs_n ),
.sck (sck ),
.sdi (sdi )
);
endmodule
这里说明本次实验的正确性,先将一个程序烧录到flash中,然后再将该程序下载进去,按下按键原程序无法正常运行。
创作不易,认为文章有帮助的同学们可以收藏点赞支持。(工程也都在群中)对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群: