所用到的软硬件环境为:
硬件:锆石A4plus开发板
软件:quartus II 13.1
从技术手册中我们可以得到如下信息:
从上述信息中我们可以得到:
1、一个读指令操作可以读取整个flash的数据。
2、所利用的时序仍为SPI时序
同样我们也对flash的擦除时序进行一定程度的更改如下:
这里的时序图画的稍微乱点,但相信同学们有了前面的基础肯定可以学会。接下来便直接上代码。
这里的传统不说废话,直接上代码:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// Website :
// Module Name : flash_read.v
// Create Time : 2020-01-09 12:52:26
// 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_read(
input sclk ,
input rst_n ,
input key_flag ,
output reg cs_n ,
output reg sck ,
output reg sdi ,
input sdo ,
output reg [ 7:0] data_out ,
output reg data_flag
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter READ_INST = 8'h03 ;
parameter READ_ADDR = 24'h00_03_21 ;
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(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)
cnt_32 <= 5'd0;
else if(cnt_32 == 'd31)
cnt_32 <= 5'd0;
else if(cs_n == 1'b0)
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(cnt_state == 'd6 && cnt_32 == 'd31)
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 <= 2'd0;
else if(cnt_state >= 'd1 && cnt_state <= 'd5)
cnt_4 <= cnt_4 + 1'b1;
else
cnt_4 <= 2'd0;
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(cnt_32 == 'd31 && cnt_state == 'd4)
sdi <= 1'b0;
else if(cnt_4 == 'd0 && cnt_state == 'd1)
sdi <= READ_INST[7-bit_cnt];
else if(cnt_4 == 'd0 &&cnt_state >= 3'd2 && cnt_state <= 3'd4)
sdi <= READ_ADDR[23-bit_cnt];
else
sdi <= sdi;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
bit_cnt <= 5'd0;
else if(cnt_32 == 'd30 && cnt_state == 3'd1)
bit_cnt <= 5'd0;
else if(cnt_32 == 'd30 && cnt_state == 3'd4)
bit_cnt <= 5'd0;
else if(cnt_4 == 'd2 && cnt_state >= 3'd1 && cnt_state <= 3'd4)
bit_cnt <= bit_cnt + 1'b1;
else
bit_cnt <= bit_cnt;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
data_out <= 8'd0;
else if(cnt_4 == 'd2 && cnt_state == 3'd5)
data_out <= {data_out[6:0],sdo};
else if(cnt_32 == 'd31 && cnt_state == 'd6)
data_out <= 8'd0;
else
data_out <= data_out;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
data_flag <= 1'b0;
else if(cnt_state == 'd5 && cnt_32 == 'd30)
data_flag <= 1'b1;
else
data_flag <= 1'b0;
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_read_tb();
reg sclk ;
reg rst_n ;
reg key_flag ;
wire cs_n ;
wire sck ;
wire sdi ;
wire [ 7:0] data_out ;
wire data_flag ;
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_read flash_read_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.key_flag (key_flag ),
.cs_n (cs_n ),
.sck (sck ),
.sdi (sdi ),
.sdo (1'b1 ),
.data_out (data_out ),
.data_flag (data_flag )
);
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 ,
input sdo ,
output reg [ 7:0] led
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
wire key_flag ;
wire [ 7:0] data_out ;
wire data_flag ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
led <= 8'd0;
else if(data_flag == 1'b1)
led <= data_out;
else
led <= led;
key key_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.key (~key ),
.key_o (key_flag )
);
flash_read flash_read_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.key_flag (key_flag ),
.cs_n (cs_n ),
.sck (sck ),
.sdi (sdi ),
.sdo (sdo ),
.data_out (data_out ),
.data_flag (data_flag )
);
endmodule
这里的实验结果就是我们把上一篇文章中写入flash的数据读出并且显示再led上面,实验结果证明了我们flash读写操作的正确性。
创作不易,认为文章有帮助的同学们可以收藏点赞支持。(工程也都在群中)对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群: