一、实验要求
要求使用SPI协议实现对flash芯片的页编程、读操作、页擦除等功能。
二、模块划分
大概的时序图:
三、程序设计
(1)接收端模块
`timescale 1ns / 1ps
module uart_rx(
input sys_clk ,
input rst_n ,
(* MARK_DEBUG="true" *)input rx_data ,
(* MARK_DEBUG="true" *)output reg[7:0] uart_data ,
(* MARK_DEBUG="true" *)output reg rx_done
);
parameter SYSCLK = 50_000_000 ;
parameter Baud = 115200 ;
parameter COUNT = SYSCLK/Baud;
parameter MID = COUNT/2 ;
///start_flag
reg rx_reg1 ;
reg rx_reg2 ;
(* MARK_DEBUG="true" *)wire start_flag ;
always@(posedge sys_clk )
if(!rst_n)begin
rx_reg1 <= 1 ;
rx_reg2 <= 1 ;
end
else
begin
rx_reg1 <= rx_data ;
rx_reg2 <= rx_reg1 ;
end
assign start_flag = ~rx_reg1 & rx_reg2 ;
/rx_flag
(* MARK_DEBUG="true" *)reg rx_flag ;
(* MARK_DEBUG="true" *)reg[4:0] cnt_bit ;
(* MARK_DEBUG="true" *)reg[9:0] cnt ;
always@(posedge sys_clk )
if(!rst_n)
rx_flag <= 0 ;
else if ( start_flag == 1 )
rx_flag <= 1 ;
else if ( cnt_bit == 10 && cnt == MID - 1 )
rx_flag <= 0 ;
else
rx_flag <= rx_flag ;
//cnt
always@(posedge sys_clk )
if(!rst_n)
cnt <= 0 ;
else if ( rx_flag == 1 )begin
if ( cnt == COUNT - 1 )
cnt <= 0 ;
else
cnt <= cnt +1 ;
end
else
cnt <= 0 ;
/cnt_bit
always@(posedge sys_clk )
if(!rst_n)
cnt_bit <= 0 ;
else if ( rx_flag == 1 )begin
if ( cnt == COUNT - 1 )begin
if( cnt_bit == 10 )
cnt_bit <= 0 ;
else
cnt_bit <= cnt_bit +1 ;
end
else
cnt_bit <= cnt_bit ;
end
else
cnt_bit <= 0 ;
///data_reg
(* MARK_DEBUG="true" *)reg[8:0] data_reg ; //data_reg:01234567 [8]
always@(posedge sys_clk ) //cnt_bit:[0]12345678[9][10]
if(!rst_n)
data_reg <= 0 ;
else if ( rx_flag == 1 )begin
if ( cnt_bit > 0 && cnt_bit < 10 && cnt == MID - 1)
data_reg[cnt_bit - 1 ] <= rx_data ;
else
data_reg <= data_reg ;
end
else
data_reg <= 0 ;
check
(* MARK_DEBUG="true" *)reg check ;
always@(posedge sys_clk )
if(!rst_n)
check <= 0 ;
else if ( rx_flag == 1 )begin
if ( cnt_bit == 10 )
check <= ^data_reg ;
else
check <= 0 ;
end
else
check <= 0 ;
uart_data
parameter MODE_CHECK = 0 ;
always@(posedge sys_clk )
if(!rst_n)
uart_data <= 0 ;
else if ( rx_flag == 1 )begin
if ( cnt_bit == 10 && cnt == 10 && check == MODE_CHECK)
uart_data <= data_reg[7:0] ;
else
uart_data <= uart_data ;
end
else
uart_data <= uart_data ;
rx_done
always@(posedge sys_clk )
if(!rst_n)
rx_done <= 0 ;
else if ( rx_flag == 1 )begin
if ( cnt_bit == 10 && cnt == MID/2 - 1 )
rx_done <= 1 ;
else
rx_done <= 0 ;
end
else
rx_done <= 0 ;
endmodule
(2)cmd模块
`timescale 1ns / 1ps
长度 指令 地址 数据
/* 这个模块的功能是把接收到的数据放在寄存器里,这个模块的功能也可以由fifo和ram完成
*/
module cmd_data(
input clk ,
input rst_n ,
(* MARK_DEBUG="true" *)input [7:0] data_in ,
(* MARK_DEBUG="true" *)input rx_done ,
(* MARK_DEBUG="true" *)output reg spi_start,
(* MARK_DEBUG="true" *)output reg [7:0] cmd ,
(* MARK_DEBUG="true" *)output reg [7:0] length ,//长度
(* MARK_DEBUG="true" *)output reg [23:0] addr ,//地址
(* MARK_DEBUG="true" *)output reg [7:0] data_out
);
parameter idle = 1 ;
parameter s0 = 2 ;//长度
parameter s1 = 3 ;//指令
parameter s2 = 4 ;//地址
parameter s3 = 5 ;//地址
parameter s4 = 6 ;//地址
parameter s5 = 7 ;//数据
(* MARK_DEBUG="true" *)reg[3:0] cur_state ;
(* MARK_DEBUG="true" *)reg[3:0] next_state ;
state1
always@(posedge clk)
if(!rst_n)
cur_state <= idle ;
else
cur_state <= next_state ;
///state2
always@(*)
case(cur_state)
idle :
begin