1.通过阅读产品手册可知其是一枚工作在50mhz(最高)下的flash芯片,编写控制器的过程中需要输出分频时钟来确保数据的稳定。(FPGA的时钟频率也只有50MHZ,低一点好控制一些)
2.其操作命令如下:
需要进行BE,SE,PP指令的时候,需要先发送写指令,并等待一段时间,之后再发送需要使用的指令+地址+使用数据,原文:
如果需要发送指令+地址+数据,数据可以使用RAM或FIFO来存储,提前写入。
代码:
擦除:SE = 8'hd8
首先需要先拉低CS_N,然后发送WR = 8'h06命令,发送完成后等待100ns(至少),发送SE命令+作用的地址,SE的擦除对应的是bank擦除,范围非常大。
细节:
虽然M25P64支持50mhz,但是这款FPGA芯片(SP6)仅有50MHZ,为此进行了分频至12.5MHZ处理。
一开始:Slave_data_out <= WR_DATA_COMMAND[7],在div_cnt == 'd3的时候将WR_DATA_COMMAND向左移位的操作,对于SPI而言,上升沿锁存数据,下降沿写入数据,所以每一位数据在div_cnt == 'd1(上升沿)的适合锁存,我们在div_cnt == 'd3的适合改变是合理的。
always @(*) begin
if(STATE == STATE_WR) begin
Slave_data_out <= WR_DATA_COMMAND[7];
end else if(STATE == STATE_SE) begin
Slave_data_out <= WR_DATA_ADDR[31];
end else begin
Slave_data_out <= 'd0;
end
end
完整代码:
module Flash_SE #(
// parameter tSE = 1_500_000_000,//3s
parameter tSHWL = 16 //100ns
) (
input wire Sys_clk,
input wire Rst_n ,
//spi
input wire SE_flag,
// input wire Slave_data_in ,
input wire [23:0] SE_ADDR ,
output reg Slave_data_out,
output reg Slave_CS_N ,
output reg Slave_CLK
);
//command
localparam COMMAND_WREN = 8'b0000_0110;
localparam COMMAND_SE = 8'hD8 ;
//state
localparam STATE_IDLE = 4'b0001;
localparam STATE_WR = 4'b0010;
localparam STATE_PROTECT = 4'b0100;
localparam STATE_SE = 4'b1000;
//cnt
reg [1:0] div_cnt ;
reg [7:0] bit_cnt ;
reg [3:0] STATE ;
reg [3:0] tSHWL_cnt;
//WR_DATA
reg [7:0] WR_DATA_COMMAND;
reg [31:0] WR_DATA_ADDR ;
//Slave_CS_N
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
Slave_CS_N <= 1'b1;
end else if(STATE == STATE_IDLE && SE_flag == 1'b1) begin
Slave_CS_N <= 1'b0;
end else if(STATE == STATE_WR && bit_cnt == 'd8 && div_cnt == 'd3) begin
Slave_CS_N <= 1'b1;
end else if(STATE == STATE_PROTECT && tSHWL_cnt == tSHWL -1'b1) begin
Slave_CS_N <= 1'b0;
end else if(STATE == STATE_SE && bit_cnt == 'd32 && div_cnt == 'd3) begin
Slave_CS_N <= 1'b1;
end else begin
Slave_CS_N <= Slave_CS_N;
end
end
//div_cnt
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
div_cnt <= 'd0;
end else if(STATE == STATE_WR || STATE == STATE_SE) begin
if(div_cnt == 'd3) begin
div_cnt <= 'd0;
end else begin
div_cnt <= div_cnt + 1'b1;
end
end else begin
div_cnt <= 'd0;
end
end
//Slave_CLK
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
Slave_CLK <= 'd0;
end else if(STATE == STATE_WR && bit_cnt <= 'd7) begin
if(bit_cnt == 'd7 && div_cnt == 'd3) begin
Slave_CLK <= 'd0;
end else if(div_cnt == 'd1 || div_cnt == 'd3) begin
Slave_CLK <= ~Slave_CLK;
end else begin
Slave_CLK <= Slave_CLK;
end
end else if(STATE == STATE_SE && bit_cnt <= 'd31) begin
if(bit_cnt == 'd31 && div_cnt == 'd3) begin
Slave_CLK <= 'd0;
end else if(div_cnt == 'd1 || div_cnt == 'd3) begin
Slave_CLK <= ~Slave_CLK;
end else begin
Slave_CLK <= Slave_CLK;
end
end else begin
Slave_CLK <= 'd0;
end
end
//tSHWL_cnt
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
tSHWL_cnt <= 'd0;
end else if(tSHWL_cnt == tSHWL -1'b1) begin
tSHWL_cnt <= 'd0;
end else if(STATE == STATE_PROTECT) begin
tSHWL_cnt <= tSHWL_cnt + 1'b1;
end else begin
tSHWL_cnt <= tSHWL_cnt;
end
end
//bit_cnt
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
bit_cnt <= 'd0;
end else if(STATE == STATE_WR && bit_cnt == 'd8 && div_cnt == 'd3) begin
bit_cnt <= 'd0;
end else if(STATE == STATE_SE && bit_cnt == 'd32 && div_cnt == 'd3) begin
bit_cnt <= 'd0;
end else if(div_cnt == 'd3) begin
bit_cnt <= bit_cnt + 1'b1;
end else begin
bit_cnt <= bit_cnt;
end
end
//WR_DATA_COMMAND
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
WR_DATA_COMMAND <= 'd0;
end else if(STATE == STATE_IDLE && SE_flag) begin
WR_DATA_COMMAND <= COMMAND_WREN;
end else if(STATE == STATE_WR && div_cnt == 'd3 && bit_cnt <= 'd7) begin
WR_DATA_COMMAND <= {WR_DATA_COMMAND[6:0],1'd0};
end else begin
WR_DATA_COMMAND <= WR_DATA_COMMAND;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
WR_DATA_ADDR <= 'd0;
end else if(STATE == STATE_IDLE && SE_flag) begin
WR_DATA_ADDR <= {COMMAND_SE,SE_ADDR};
end else if(STATE == STATE_SE && bit_cnt <= 'd31 && div_cnt == 'd3) begin
WR_DATA_ADDR <= {WR_DATA_ADDR[30:0],1'd0};
end else begin
WR_DATA_ADDR <= WR_DATA_ADDR;
end
end
always @(*) begin
if(STATE == STATE_WR) begin
Slave_data_out <= WR_DATA_COMMAND[7];
end else if(STATE == STATE_SE) begin
Slave_data_out <= WR_DATA_ADDR[31];
end else begin
Slave_data_out <= 'd0;
end
end
//state
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
STATE <= STATE_IDLE;
end else begin
case (STATE)
STATE_IDLE :
begin if(SE_flag)
begin
STATE <= STATE_WR;
end else begin
STATE <= STATE_IDLE;
end
end
STATE_WR :
begin if(bit_cnt == 'd8 && div_cnt == 'd3)
begin
STATE <= STATE_PROTECT;
end else begin
STATE <= STATE_WR;
end
end
STATE_PROTECT:
begin if(tSHWL_cnt == tSHWL -1'b1)
begin
STATE <= STATE_SE;
end else begin
STATE <= STATE_PROTECT;
end
end
STATE_SE :
begin
if(bit_cnt == 'd32 && div_cnt == 'd3) begin
STATE <= STATE_IDLE;
end else begin
STATE <= STATE_SE;
end
end
default:
begin
STATE <= STATE_IDLE;
end
endcase
end
end
//
// //ila
// wire [35:0] CONTROL0;
// wire [39:0] TRIG0 ;
// assign TRIG0 = {
// Slave_CS_N ,
// Slave_CLK ,
// Slave_data_out,
// SE_ADDR,//24
// STATE,
// SE_flag
// };
// CS_icon CS_icon_inst0 (
// .CONTROL0 ( CONTROL0 ) // INOUT BUS [35:0]
// );
// CS_ila CS_ila_insty0 (
// .CONTROL ( CONTROL0 ), // INOUT BUS [35:0]
// .CLK ( Sys_clk ), // IN
// .TRIG0 ( TRIG0 ) // IN BUS [39:0]
// );
endmodule
写入(页写入):PP = 8'h02
和SE类似,区别仅在于命令不同,此外需要在完成命令发送以后连续写入8x256位数据,即连续写入256字节。
所以写入的方法采取提前把数据写入FIFO,在即将完成PP指令的发送的时候读出(标准模式,卡时间的话可以采取先入先出模式。)数据,再分割后通过SPI发送即可。
WR命令,PP命令,写入数据的发送:
always @(*) begin
if(STATE == STATE_WR) begin
Slave_data_out <= WR_DATA_COMMAND[7];
end else if(STATE == STATE_PP
&& bit_cnt <= 'd31) begin
Slave_data_out <= WR_PP_SETING[31];
end else if(STATE == STATE_PP
&& bit_cnt > 'd31
&& bit_cnt <= PP_DATA_NUM - 1'd1)begin
Slave_data_out <= RD_REG[7];
end else begin
Slave_data_out <= 'd0;
end
end
读使能要在真正写入之前:
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
RD_EN_IN <= 'd0;
end else if(STATE == STATE_PP && bit_cnt == 31
&& div_cnt == 'd1) begin
RD_EN_IN <= 1'd1;
end else if(STATE == STATE_PP && shift_cnt == 'd7
&& div_cnt == 'd1 && bit_cnt < PP_DATA_NUM - 1'd1)begin
RD_EN_IN <= 1'd1;
end else begin
RD_EN_IN <= 1'd0;
end
end
因为是标准模式,所以实际数据可用时间要滞后。
always @(posedge Sys_clk) begin
RD_EN_IN_wait <= RD_EN_IN;
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
RD_REG <= 'd0;
end else if(RD_EN_IN_wait) begin
RD_REG <= RD_DATA_OUT;
end else if(bit_cnt > 31 && div_cnt == 'd3) begin
RD_REG <= {RD_REG[6:0],1'd0};
end else begin
RD_REG <= RD_REG;
end
end
完整代码:
module Flash_PP #(
parameter tSHWL = 'd16 , //100ns
parameter PP_DATA_NUM = 'd2080
) (
input wire Sys_clk,
input wire Rst_n ,
//spi
input wire PP_flag,
// input wire Slave_data_in ,
input wire [23:0] PP_ADDR ,
output reg Slave_data_out,
output reg Slave_CS_N ,
output reg Slave_CLK ,
//fifo
input wire WR_EN ,
input wire [7:0] WR_DATA
);
//command
localparam COMMAND_WREN = 8'b0000_0110;
localparam COMMAND_PP = 8'b0000_0010;
//state
localparam STATE_IDLE = 4'b0001;
localparam STATE_WR = 4'b0010;
localparam STATE_PROTECT = 4'b0100;
localparam STATE_PP = 4'b1000;
//cnt
reg [ 1:0] div_cnt ;
reg [11:0] bit_cnt ;
reg [ 3:0] STATE ;
reg [ 3:0] tSHWL_cnt;
//WR_DATA
reg [ 7:0] WR_DATA_COMMAND;
reg [ 31:0] WR_PP_SETING ;
//fifo
reg RD_EN_IN ;
reg RD_EN_IN_wait ;
wire [7:0] RD_DATA_OUT ;
reg [7:0] RD_REG ;
wire full ;
wire empty ;
reg [2:0] shift_cnt ;
//
S_FIFO_8x256 S_FIFO_8x256_INST1 (
.clk ( Sys_clk ), // input clk
.din ( WR_DATA ), // input [7 : 0] din
.wr_en ( WR_EN ), // input wr_en
.rd_en ( RD_EN_IN ), // input rd_en
.dout ( RD_DATA_OUT), // output [7 : 0] dout
.full ( full ), // output full
.empty ( empty ) // output empty
);
//
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
RD_EN_IN <= 'd0;
end else if(STATE == STATE_PP && bit_cnt == 31 && div_cnt == 'd1) begin
RD_EN_IN <= 1'd1;
end else if(STATE == STATE_PP && shift_cnt == 'd7 && div_cnt == 'd1 && bit_cnt < PP_DATA_NUM - 1'd1)begin
RD_EN_IN <= 1'd1;
end else begin
RD_EN_IN <= 1'd0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
shift_cnt <= 'd0;
end else if(STATE == STATE_PP && bit_cnt > 31) begin
if(shift_cnt == 'd7 && div_cnt == 'd3) begin
shift_cnt <= 'd0;
end else if(div_cnt == 'd3) begin
shift_cnt <= shift_cnt + 1'b1;
end
end else begin
shift_cnt <= 'd0;
end
end
always @(posedge Sys_clk) begin
RD_EN_IN_wait <= RD_EN_IN;
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
RD_REG <= 'd0;
end else if(RD_EN_IN_wait) begin
RD_REG <= RD_DATA_OUT;
end else if(bit_cnt > 31 && div_cnt == 'd3) begin
RD_REG <= {RD_REG[6:0],1'd0};
end else begin
RD_REG <= RD_REG;
end
end
//
//Slave_CS_N
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
Slave_CS_N <= 1'b1;
end else if(STATE == STATE_IDLE && PP_flag == 1'b1) begin
Slave_CS_N <= 1'b0;
end else if(STATE == STATE_WR && bit_cnt == 'd8 && div_cnt == 'd3) begin
Slave_CS_N <= 1'b1;
end else if(STATE == STATE_PROTECT && tSHWL_cnt == tSHWL -1'b1) begin
Slave_CS_N <= 1'b0;
end else if(STATE == STATE_PP && bit_cnt == PP_DATA_NUM && div_cnt == 'd3) begin
Slave_CS_N <= 1'b1;
end else begin
Slave_CS_N <= Slave_CS_N;
end
end
//div_cnt
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
div_cnt <= 'd0;
end else if(STATE == STATE_WR || STATE == STATE_PP) begin
if(div_cnt == 'd3) begin
div_cnt <= 'd0;
end else begin
div_cnt <= div_cnt + 1'b1;
end
end else begin
div_cnt <= 'd0;
end
end
//Slave_CLK
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
Slave_CLK <= 'd0;
end else if(STATE == STATE_WR && bit_cnt <= 'd7) begin
if(bit_cnt == 'd7 && div_cnt == 'd3) begin
Slave_CLK <= 'd0;
end else if(div_cnt == 'd1 || div_cnt == 'd3) begin
Slave_CLK <= ~Slave_CLK;
end else begin
Slave_CLK <= Slave_CLK;
end
end else if(STATE == STATE_PP && bit_cnt <= PP_DATA_NUM - 1'd1) begin
if(bit_cnt == PP_DATA_NUM - 1'd1 && div_cnt == 'd3) begin
Slave_CLK <= 'd0;
end else if(div_cnt == 'd1 || div_cnt == 'd3) begin
Slave_CLK <= ~Slave_CLK;
end else begin
Slave_CLK <= Slave_CLK;
end
end else begin
Slave_CLK <= 'd0;
end
end
//tSHWL_cnt
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
tSHWL_cnt <= 'd0;
end else if(tSHWL_cnt == tSHWL -1'b1) begin
tSHWL_cnt <= 'd0;
end else if(STATE == STATE_PROTECT) begin
tSHWL_cnt <= tSHWL_cnt + 1'b1;
end else begin
tSHWL_cnt <= tSHWL_cnt;
end
end
//bit_cnt
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
bit_cnt <= 'd0;
end else if(STATE == STATE_WR && bit_cnt == 'd8 && div_cnt == 'd3) begin
bit_cnt <= 'd0;
end else if(STATE == STATE_PP && bit_cnt == PP_DATA_NUM && div_cnt == 'd3) begin
bit_cnt <= 'd0;
end else if(div_cnt == 'd3) begin
bit_cnt <= bit_cnt + 1'b1;
end else begin
bit_cnt <= bit_cnt;
end
end
//WR_DATA_COMMAND
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
WR_DATA_COMMAND <= 'd0;
end else if(STATE == STATE_IDLE && PP_flag) begin
WR_DATA_COMMAND <= COMMAND_WREN;
end else if(STATE == STATE_WR && div_cnt == 'd3 && bit_cnt <= 'd7) begin
WR_DATA_COMMAND <= {WR_DATA_COMMAND[6:0],1'd0};
end else begin
WR_DATA_COMMAND <= WR_DATA_COMMAND;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
WR_PP_SETING <= 'd0;
end else if(STATE == STATE_IDLE && PP_flag) begin
WR_PP_SETING <= {COMMAND_PP,PP_ADDR};
end else if(STATE == STATE_PP && bit_cnt <= 'd31 && div_cnt == 'd3) begin
WR_PP_SETING <= {WR_PP_SETING[30:0],1'd0};
end else begin
WR_PP_SETING <= WR_PP_SETING;
end
end
always @(*) begin
if(STATE == STATE_WR) begin
Slave_data_out <= WR_DATA_COMMAND[7];
end else if(STATE == STATE_PP && bit_cnt <= 'd31) begin
Slave_data_out <= WR_PP_SETING[31];
end else if(STATE == STATE_PP && bit_cnt > 'd31 && bit_cnt <= PP_DATA_NUM - 1'd1)begin
Slave_data_out <= RD_REG[7];
end else begin
Slave_data_out <= 'd0;
end
end
//state
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
STATE <= STATE_IDLE;
end else begin
case (STATE)
STATE_IDLE :
begin if(PP_flag)
begin
STATE <= STATE_WR;
end else begin
STATE <= STATE_IDLE;
end
end
STATE_WR :
begin if(bit_cnt == 'd8 && div_cnt == 'd3)
begin
STATE <= STATE_PROTECT;
end else begin
STATE <= STATE_WR;
end
end
STATE_PROTECT:
begin if(tSHWL_cnt == tSHWL -1'b1)
begin
STATE <= STATE_PP;
end else begin
STATE <= STATE_PROTECT;
end
end
STATE_PP :
begin
if(bit_cnt == PP_DATA_NUM && div_cnt == 'd3) begin
STATE <= STATE_IDLE;
end else begin
STATE <= STATE_PP;
end
end
default:
begin
STATE <= STATE_IDLE;
end
endcase
end
end
endmodule
读取:RD = 8'h03
读取是一个很特殊的状态,它的读取长度是没有限制的,读取完一页会再读取下一页。所以必须人为定义其读取的长度,例如:
此代码通过将输入的字节长度转为比特长度作为一个参数使用。
COMMAND_ADDR_length是本身读需要的命令+地址长度。
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
bit_cnt_end <= 'd0;
end else if(RD_flag == 'd1) begin
bit_cnt_end <= ((RD_data_length)<<3'd3) + COMMAND_ADDR_length;
end else begin
bit_cnt_end <= bit_cnt_end;
end
end
数据接收
读取操作还需要缓存在发送完COMMAND_ADDR_length以后对数据进行接收的问题。
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
WR_DATA <= 'd0;
end else if(bit_cnt > COMMAND_ADDR_length - 1'b1
&& Div_cnt == DIV_NUM - 2'd2
&& bit_cnt <= bit_cnt_end - 1'b1) begin
WR_DATA <= {WR_DATA[6:0],Slave_data_in};
end else begin
WR_DATA <= WR_DATA;
end
end
这个数据会被写入到FIFO中,FIFO的写使能也需要每8bits一次产生。
FIFO的写使能和写数据同步变化也能写入正确的数据,很省心。
//DATA_IN
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
shift_cnt <= 'd0;
end else if(bit_cnt > COMMAND_ADDR_length - 1'b1
&& bit_cnt <= bit_cnt_end - 1'b1) begin
if(shift_cnt == 'd7 && Div_cnt == DIV_NUM - 1'b1) begin
shift_cnt <= 'd0;
end else if(Div_cnt == DIV_NUM - 1'b1) begin
shift_cnt <= shift_cnt + 1'b1;
end
end else begin
shift_cnt <= 'd0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
WR_EN <= 'd0;
end else if(bit_cnt > COMMAND_ADDR_length - 1'b1
&& shift_cnt == 'd7
&& Div_cnt == DIV_NUM - 2'd2
&& bit_cnt <= bit_cnt_end - 1'b1) begin
WR_EN <= 1'b1;
end else begin
WR_EN <= 1'b0;
end
end
完整代码:
module Flash_RD #(
parameter DIV_NUM = 'd4 ,
parameter COMMAND_ADDR_length = 'd32
)(
input wire Sys_clk,
input wire Rst_n ,
//slave
input wire RD_flag,
input wire [23:0] RD_ADDR,
input wire [10:0] RD_data_length,
output reg Slave_CLK ,
output reg Slave_CS_N ,
input wire Slave_data_in ,
output reg Slave_data_out,
//fifo
input wire FIFO_RD_EN ,
output wire FIFO_RD_ready,
output wire [ 7:0] RD_DATA
);
localparam COMMAND_RD = 8'b0000_0011;
reg [31:0] Read_data ;
reg [ 1:0] Div_cnt ;
reg [15:0] bit_cnt ;
reg [ 3:0] shift_cnt ;
reg [15:0] bit_cnt_end;
//fifo
reg FIFO_RD_AVAI;
reg [ 7:0] WR_DATA ;
reg WR_EN ;
wire [ 7:0] RD_DATA_REG;
// reg FIFO_RD_EN_delay;p
wire full ;
wire empty ;
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
bit_cnt_end <= 'd0;
end else if(RD_flag == 'd1) begin
bit_cnt_end <= ((RD_data_length)<<3'd3) + COMMAND_ADDR_length;
end else begin
bit_cnt_end <= bit_cnt_end;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
Slave_CLK <= 'd0;
end else if(Slave_CS_N == 'd0 && bit_cnt <= bit_cnt_end - 1'b1) begin
if((Div_cnt == ((DIV_NUM - 1'b1)>>1)) || (Div_cnt == (DIV_NUM - 1'b1))) begin
Slave_CLK <= ~Slave_CLK;
end else begin
Slave_CLK <= Slave_CLK;
end
end else begin
Slave_CLK <= 'd0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
Slave_CS_N <= 'd1;
end else if(RD_flag == 1'b1) begin
Slave_CS_N <= 'd0;
end else if(bit_cnt == bit_cnt_end && Div_cnt == DIV_NUM - 1'b1) begin
Slave_CS_N <= 'd1;
end else begin
Slave_CS_N <= Slave_CS_N;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
Div_cnt <= 'd0;
end else if(Slave_CS_N == 'd0) begin
if(Div_cnt == DIV_NUM - 1'b1) begin
Div_cnt <= 'd0;
end else begin
Div_cnt <= Div_cnt + 1'b1;
end
end else begin
Div_cnt <= 'd0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
bit_cnt <= 'd0;
end else if(Slave_CS_N == 'd0) begin
if(bit_cnt == bit_cnt_end && Div_cnt == DIV_NUM - 1'b1) begin
bit_cnt <= 'd0;
end else if(Div_cnt == DIV_NUM - 1'b1) begin
bit_cnt <= bit_cnt + 1'b1;
end else begin
bit_cnt <= bit_cnt;
end
end else begin
bit_cnt <= 'd0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
Read_data <= 'd0;
end else if(RD_flag == 1'b1) begin
Read_data <= {COMMAND_RD,RD_ADDR};
end else if(Slave_CS_N == 'd0 && bit_cnt <= 'd31 && Div_cnt == DIV_NUM - 1'b1) begin
Read_data <= {Read_data[30:0],1'b0};
end else begin
Read_data <= Read_data;
end
end
always @(*) begin
if(Slave_CS_N == 'd0 && bit_cnt <= 'd31) begin
Slave_data_out <= Read_data[31];
end else begin
Slave_data_out <= 'd0;
end
end
//DATA_IN
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
shift_cnt <= 'd0;
end else if(bit_cnt > COMMAND_ADDR_length - 1'b1
&& bit_cnt <= bit_cnt_end - 1'b1) begin
if(shift_cnt == 'd7 && Div_cnt == DIV_NUM - 1'b1) begin
shift_cnt <= 'd0;
end else if(Div_cnt == DIV_NUM - 1'b1) begin
shift_cnt <= shift_cnt + 1'b1;
end
end else begin
shift_cnt <= 'd0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
WR_DATA <= 'd0;
end else if(bit_cnt > COMMAND_ADDR_length - 1'b1
&& Div_cnt == DIV_NUM - 2'd2
&& bit_cnt <= bit_cnt_end - 1'b1) begin
WR_DATA <= {WR_DATA[6:0],Slave_data_in};
end else begin
WR_DATA <= WR_DATA;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
WR_EN <= 'd0;
end else if(bit_cnt > COMMAND_ADDR_length - 1'b1
&& shift_cnt == 'd7
&& Div_cnt == DIV_NUM - 2'd2
&& bit_cnt <= bit_cnt_end - 1'b1) begin
WR_EN <= 1'b1;
end else begin
WR_EN <= 1'b0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(Rst_n == 'd0) begin
FIFO_RD_AVAI <= 'd0;
end else if(bit_cnt == bit_cnt_end && Div_cnt == DIV_NUM - 1'b1) begin
FIFO_RD_AVAI <= 'd1;
end else if(FIFO_RD_AVAI == 'd1 && empty == 'd1)begin
FIFO_RD_AVAI <= 'd0;
end else begin
FIFO_RD_AVAI <= FIFO_RD_AVAI;
end
end
assign FIFO_RD_ready = FIFO_RD_AVAI && (!empty);
// always @(posedge Sys_clk) begin
// FIFO_RD_EN_delay <= FIFO_RD_EN;
// end
// always @(posedge Sys_clk or negedge Rst_n) begin
// if(Rst_n == 'd0) begin
// RD_DATA <= 'd0;
// end else if(FIFO_RD_EN) begin
// RD_DATA <= RD_DATA_REG;
// end else begin
// RD_DATA <= RD_DATA;
// end
// end
//
S_FIFO_1024x8 S_FIFO_1024x8_INST1 (
.clk ( Sys_clk ), // input clk
.din ( WR_DATA ), // input [7 : 0] din
.wr_en ( WR_EN ), // input wr_en
.rd_en ( FIFO_RD_EN ), // input rd_en
.dout ( RD_DATA ), // output [7 : 0] dout
.full ( full ), // output full
.empty ( empty ) // output empty
);
endmodule
[1]威三学院FPGA教程
[2]小梅哥AC620V2教程