- spi_flash
- (
- input Clk10M,//Clk的180°反相
- input Clk,//10MHz
- input Rst,
- output F2M25p16SpiClk, //FPGA 输出至外部SPI时钟
- output F2M25p16SpiCsn, //FPGA输出至外部SPI片选
- output F2M25p16SpiDout, //FPGA输出至外部器件SPI数据
- input F2M25p16SpiDin, //外部器件输入到FPGASPI数据
- input UserFlash,
- input [23 : 0] UserFlashAddr,
- input UserRd,
- input [23 : 0] UserRdAddr,//UserRdAddr[23] is the msb
- input [15 : 0] UserRdSize,//in bytes
- output [7 : 0] UserDataRx,
- output UserDataRxVld,
- input UserWr,
- input [23 : 0] UserWrAddr,
- input [15 : 0] UserWrSize,//in bytes
- input [7 : 0] UserDataTx,
- output UserDataTxVld,
- output UserFlashBusy,
- output UserDataDone
- );
[payamount]5.00[/payamount]
[pay]
`timescale 1ns/1ps
// 在进行写操作的时候,需要的步骤为
// 1、写使能
// 2、擦除数据(可以是扇区,可以是整个芯片)
// 3、判断状态寄存器忙不忙(忙则阻塞等待不忙)
// 4、写使能(对于写禁止(04H)写禁止指令使得状态寄存器中的WEL 位为0。写禁止指令是以/CS 低电平开始的,然后在DI传输指令代码04H到芯片,最后是以/CS 拉高结束。
//当上电后,以及完成写状态寄存器,擦写安全寄存器,页写,QUAD 页写,扇区擦写,块擦写,芯片擦写指令后,WEL 位是自动清零的。)
// 5、然后写入指令 0x02是写指令,后边跟三个字节的地址,(在写操作的时候函数接口不需要偏移量)
// 读之前要
// 1、判断这个FLASH忙不忙 如果忙的话则一直等待着不忙。
// 2、然后进行才能进行读指令的操作。
//注意:如果想要更好的时序关系,spi输出的时钟,最好用二倍频的时钟去产生
//UserDataTxVld,相当于外部fifo的读使能,一个脉冲对应移走当前一个byte的数据,输出下一个byte的数据;
//UserDataRxVld,相当于外部fifo的写使能,一个脉冲对应一个byte的有效数据;
module spi_flash
(
input Clk10M,
input Clk,//10MHz
input Rst,
output F2M25p16SpiClk, //FPGA 输出至外部SPI时钟
output F2M25p16SpiCsn, //FPGA输出至外部SPI片选
output F2M25p16SpiDout, //FPGA输出至外部器件SPI数据
input F2M25p16SpiDin, //外部器件输入到FPGASPI数据
input UserFlash,
input [23 : 0] UserFlashAddr,
input UserRd,
input [23 : 0] UserRdAddr,//UserRdAddr[23] is the msb
input [15 : 0] UserRdSize,//in bytes
output [7 : 0] UserDataRx,
output UserDataRxVld,
input UserWr,
input [23 : 0] UserWrAddr,
input [15 : 0] UserWrSize,//in bytes
input [7 : 0] UserDataTx,
output UserDataTxVld,
output UserFlashBusy,
output UserDataDone,
output [31 : 0] TRIG0
);
//--------------------------------------------------------------------------------------------------
//------------------------------------work state----------------------------------------------------
parameter IDLE = 4'd0;
parameter RD_JUDGE_BUSY = 4'd1;
parameter RD = 4'd2;
parameter RD_DONE = 4'd3;
parameter WR_EN1 = 4'd4;
parameter DATA_FLASH = 4'd5;
parameter FLASH_DONE = 4'd6;
parameter WR_JUDGE_BUSY = 4'd7;
parameter WR_EN2 = 4'd8;
parameter WR = 4'd9;
parameter WR_DONE = 4'd10;
`define STS_REG_RD_CMD 8'h05
`define DATA_RD_CMD 8'h03
`define WR_EN_CMD 8'h06
`define PAGE_WR_CMD 8'h02
`define SECTOR_FLASH_CMD 8'h20
reg [3 : 0] WorkSts = 0;
reg [15 : 0] WorkCnt = 0;
reg UserFlashBusyReg = 0;
reg [23 : 0] Address = 0;
reg [15 : 0] UserSize = 0;
reg [7 : 0] F2M25p16SpiDoutReg = 0;
reg [2 : 0] WrLoopCnt = 0;
reg [7 : 0] UserDataRxReg = 0;
reg [2 : 0] RdLoopCnt = 0;
reg UserDataRxVldReg = 0;
reg F2M25p16SpiCsnReg = 1;
reg UserDataTxVldReg = 0;
reg UserDataDoneReg = 0;
always @ ( posedge Clk )
begin
if( Rst ) WorkSts <= IDLE;
else
case( WorkSts )
IDLE : if( UserRd ) WorkSts <= RD_JUDGE_BUSY;
else if( UserWr ) WorkSts <= WR_JUDGE_BUSY;
else if( UserFlash ) WorkSts <= WR_EN1;
else WorkSts <= IDLE;
RD_JUDGE_BUSY : if( WorkCnt == 16'd17 )
begin
if( UserFlashBusy ) WorkSts <= RD_JUDGE_BUSY;
else WorkSts <= RD;
end
RD : if( WorkCnt == {UserSize[12:0],3'b0} + 6'd33 ) WorkSts <= RD_DONE;
RD_DONE : WorkSts <= IDLE;
WR_EN1 : if( WorkCnt == 16'd9 ) WorkSts <= DATA_FLASH;
DATA_FLASH : if( WorkCnt == 16'd33 ) WorkSts <= FLASH_DONE;
FLASH_DONE : WorkSts <= IDLE;
WR_JUDGE_BUSY : if( WorkCnt == 16'd17 )
begin
if( UserFlashBusy ) WorkSts <= WR_JUDGE_BUSY;
else WorkSts <= WR_EN2;
end
WR_EN2 : if( WorkCnt == 16'd9 ) WorkSts <= WR;
WR : if( WorkCnt == {UserSize[12:0],3'b0} + 6'd33 ) WorkSts <= WR_DONE;
WR_DONE : WorkSts <= IDLE;
default : ;
endcase
end
always @ ( posedge Clk )
begin
case( WorkSts )
IDLE : WorkCnt <= 16'b0;
RD_JUDGE_BUSY, WR_JUDGE_BUSY : if( WorkCnt == 16'd17 ) WorkCnt <= 16'b0;
else WorkCnt <= WorkCnt + 1'b1;
RD,WR : WorkCnt <= WorkCnt + 1'b1;
WR_EN1,WR_EN2 : if( WorkCnt == 16'd9 ) WorkCnt <= 16'b0;
else WorkCnt <= WorkCnt + 1'b1;
DATA_FLASH : if( WorkCnt == 16'd33 ) WorkCnt <= 16'b0;
else WorkCnt <= WorkCnt + 1'b1;
default : ;
endcase
end
always @ ( posedge Clk )
begin
if( UserRd ) Address <= UserRdAddr;
else if( UserWr ) Address <= UserWrAddr;
else if( UserFlash ) Address <= UserFlashAddr;
end
always @ ( posedge Clk )
begin
if( UserRd ) UserSize <= UserRdSize;
else if( UserWr ) UserSize <= UserWrSize;
end
assign UserDataDone = UserDataDoneReg;
always @ ( posedge Clk )
begin
case( WorkSts )
FLASH_DONE, RD_DONE, WR_DONE : UserDataDoneReg <= 1'b1;
default : UserDataDoneReg <= 1'b0;
endcase
end
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//-------------------------------------------data transmit------------------------------------------
assign F2M25p16SpiDout = F2M25p16SpiDoutReg[7];
always @ ( posedge Clk )
begin
case( WorkSts )
IDLE : F2M25p16SpiDoutReg <= 8'b0;
RD_JUDGE_BUSY, WR_JUDGE_BUSY : case( WorkCnt )
16'd0 : F2M25p16SpiDoutReg <= `STS_REG_RD_CMD;
default : F2M25p16SpiDoutReg <= {F2M25p16SpiDoutReg[6:0],1'b0};
endcase
DATA_FLASH : case( WorkCnt )
16'd0 : F2M25p16SpiDoutReg <= `SECTOR_FLASH_CMD;
16'd8 : F2M25p16SpiDoutReg <= Address[23:16];
16'd16 : F2M25p16SpiDoutReg <= Address[15:8];
16'd24 : F2M25p16SpiDoutReg <= Address[7:0];
default : F2M25p16SpiDoutReg <= {F2M25p16SpiDoutReg[6:0],1'b0};
endcase
WR_EN1,WR_EN2 : case( WorkCnt )
16'd0 : F2M25p16SpiDoutReg <= `WR_EN_CMD;
default : F2M25p16SpiDoutReg <= {F2M25p16SpiDoutReg[6:0],1'b0};
endcase
RD : case( WorkCnt )
16'd0 : F2M25p16SpiDoutReg <= `DATA_RD_CMD;
16'd8 : F2M25p16SpiDoutReg <= Address[23:16];
16'd16 : F2M25p16SpiDoutReg <= Address[15:8];
16'd24 : F2M25p16SpiDoutReg <= Address[7:0];
default : F2M25p16SpiDoutReg <= {F2M25p16SpiDoutReg[6:0],1'b0};
endcase
WR : case( WorkCnt )
16'd0 : F2M25p16SpiDoutReg <= `PAGE_WR_CMD;
16'd8 : F2M25p16SpiDoutReg <= Address[23:16];
16'd16 : F2M25p16SpiDoutReg <= Address[15:8];
16'd24 : F2M25p16SpiDoutReg <= Address[7:0];
default : begin
if( ( WorkCnt > 16'd31 ) & ( WrLoopCnt == 3'd0 ) ) F2M25p16SpiDoutReg <= UserDataTx;
else F2M25p16SpiDoutReg <= {F2M25p16SpiDoutReg[6:0],1'b0};
end
endcase
default : F2M25p16SpiDoutReg <= 8'b0;
endcase
end
always @ ( posedge Clk )
begin
case( WorkSts )
WR : WrLoopCnt <= WrLoopCnt + 1'b1;
default : WrLoopCnt <= 3'b0;
endcase
end
always @ ( posedge Clk )
begin
case( WorkSts )
RD : RdLoopCnt <= RdLoopCnt + 1'b1;
default : RdLoopCnt <= 3'b0;
endcase
end
assign UserDataTxVld = UserDataTxVldReg;
always @ ( posedge Clk )
begin
case( WorkSts )
WR : if( ( WorkCnt > 16'd31 ) & ( WrLoopCnt == 3'd3 ) ) UserDataTxVldReg <= 1'b1;
else UserDataTxVldReg <= 1'b0;
default : UserDataTxVldReg <= 1'b0;
endcase
end
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//-----------------------------------------data receive---------------------------------------------
assign UserDataRx = UserDataRxReg;
assign UserDataRxVld = UserDataRxVldReg;
always @ ( negedge Clk )
begin
case( WorkSts )
RD : begin
if( WorkCnt > 16'd32 )
begin
UserDataRxReg <= {UserDataRxReg[6:0],F2M25p16SpiDin};
if ( RdLoopCnt == 3'd0 ) UserDataRxVldReg <= 1'b1;
else UserDataRxVldReg <= 1'b0;
end
else
begin
UserDataRxReg <= 8'b0;
UserDataRxVldReg <= 1'b0;
end
end
default : begin
UserDataRxReg <= 8'b0;
UserDataRxVldReg <= 1'b0;
end
endcase
end
assign UserFlashBusy = UserFlashBusyReg;
always @ ( negedge Clk )
begin
case( WorkSts )
RD_JUDGE_BUSY, WR_JUDGE_BUSY : if( WorkCnt > 16'd16 ) UserFlashBusyReg <= F2M25p16SpiDin;
default : UserFlashBusyReg <= 1'b0;
endcase
end
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//-------------------------------------SPI CS-------------------------------------------------------
assign F2M25p16SpiCsn = F2M25p16SpiCsnReg;
always @ ( posedge Clk )
begin
case( WorkSts )
IDLE : F2M25p16SpiCsnReg <= 1'b1;
RD_JUDGE_BUSY, WR_JUDGE_BUSY
: case( WorkCnt )
16'd0 : F2M25p16SpiCsnReg <= 1'b0;
16'd17 : F2M25p16SpiCsnReg <= 1'b1;
default : ;
endcase
WR_EN1, WR_EN2 : case( WorkCnt )
16'd0 : F2M25p16SpiCsnReg <= 1'b0;
16'd9 : F2M25p16SpiCsnReg <= 1'b1;
default : ;
endcase
DATA_FLASH : case( WorkCnt )
16'd0 : F2M25p16SpiCsnReg <= 1'b0;
16'd33 : F2M25p16SpiCsnReg <= 1'b1;
default : ;
endcase
WR, RD : if( WorkCnt == 16'd0 ) F2M25p16SpiCsnReg <= 1'b0;
else if( WorkCnt == {UserSize[12:0],3'b0} + 6'd33 ) F2M25p16SpiCsnReg <= 1'b1;
default : F2M25p16SpiCsnReg <= 1'b1;
endcase
end
//--------------------------------------------------------------------------------------------------
assign F2M25p16SpiClk = ( ( ( WorkCnt > 16'b0 ) & ( WorkCnt < 16'd9 ) & ( WorkSts == WR_EN1 ) ) |
( ( WorkCnt > 16'b0 ) & ( WorkCnt < 16'd9 ) & ( WorkSts == WR_EN2 ) ) |
( ( WorkCnt > 16'b0 ) & ( WorkCnt < 16'd33 ) & ( WorkSts == DATA_FLASH ) ) |
( ( WorkCnt > 16'b0 ) & ( WorkCnt < 16'd17 ) & ( WorkSts == RD_JUDGE_BUSY ) ) |
( ( WorkCnt > 16'b0 ) & ( WorkCnt < 16'd17 ) & ( WorkSts == WR_JUDGE_BUSY ) ) |
( ( WorkCnt > 16'b0 ) & ( WorkCnt < {UserSize[12:0],3'b0} + 6'd33 ) & ( WorkSts == WR ) ) |
( ( WorkCnt > 16'b0 ) & ( WorkCnt < {UserSize[12:0],3'b0} + 6'd33 ) & ( WorkSts == RD ) )
) ? Clk10M : 1'b0 ;
endmodule
[/pay]