基于FPGA的APS6404L-3SQR QSPI PSRAM驱动设计(4)

1.摘要:

这里记录一下顶层文件的框架,主要是对命令的控制。具体详情看前面三篇博客记录的内容。

2.FPGA设计

2.1、时序图

具体流程和状态机跳转如下图所示:

注意:这个状态主要是为了这款芯片各个命令的功能,纯验证使用的。感觉验证完之后最简单的框架应该是:上电-复位-写-读,都是用SPI QUAD模式最为简单明了方便,更适合项目使用。

代码如下:

根据spi和qspi两个模块输出的ready的上升沿信号来作为状态机跳转的条件。

复制代码
wire				w_spi_data_ready 	= 	w_spi_ready && !r_spi_ready;		//SPI/QSPI数据处理完成标志	
wire				w_qspi_data_ready	=	w_qspi_ready && !r_qspi_ready	;

always @(*)
begin
	if (!rstn_i)
		r_fsm_next	=	'd0	;
	else begin
		case (r_fsm_current)
			FSM_PSRAM_IDLE				:
				r_fsm_next	=	(w_power_up_flag)?FSM_POWER_UP:FSM_PSRAM_IDLE;//等待200us启动
			FSM_POWER_UP				:
				r_fsm_next	=	(r_fsm_cnt >= 'd10)?FSM_RSTEN:FSM_POWER_UP	;//增加等待延时
			FSM_RSTEN					:
				r_fsm_next	=	(w_spi_data_ready)?FSM_RST:FSM_RSTEN	;
			FSM_RST						:
				r_fsm_next	=	(w_spi_data_ready)?FSM_READ_ID:FSM_RST	;
			FSM_READ_ID					:
				r_fsm_next	=	(w_spi_data_ready)?FSM_MODE_QPI:FSM_READ_ID	;
			FSM_MODE_QPI				:
				r_fsm_next	=	(w_spi_data_ready)?FSM_WRITE:FSM_MODE_QPI	;
			FSM_WRITE					:
				r_fsm_next	=	(w_qspi_data_ready)?FSM_READ:FSM_WRITE	;
			FSM_READ					:
				r_fsm_next	=	(w_qspi_data_ready)?FSM_MODE_QPI_EXIT:FSM_READ	;
			FSM_MODE_QPI_EXIT			:
				r_fsm_next	=	(w_qspi_data_ready)?FSM_READ_END:FSM_MODE_QPI_EXIT	;
			FSM_READ_END				:
				r_fsm_next	=	FSM_RSTEN	;
			default						:
				r_fsm_next	=	FSM_PSRAM_IDLE	;
		endcase 
	end 
end 

2.2、写命令/地址/数据

对于写入的命令是预制的,外部接口只能决定读写和地址。对于命令则根据状态机来控制:

复制代码
always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)	begin	
		r_spi_driver_valin		<=	1'b0	;
		r_spi_driver_cmdin		<=	'd0	;
	end	else if ((r_fsm_current == FSM_RSTEN) && w_spi_ready && (r_fsm_cnt == 'd0))	begin
		r_spi_driver_valin		<=	1'b1	;
		r_spi_driver_cmdin		<=	PSRAM_RESET_ENABLE	;
	end else if ((r_fsm_current == FSM_RST) && w_spi_ready && (r_fsm_cnt == 'd0))	begin
		r_spi_driver_valin		<=	1'b1	;
		r_spi_driver_cmdin		<=	PSRAM_RESET	;
	end else if ((r_fsm_current == FSM_READ_ID) && w_spi_ready && (r_fsm_cnt == 'd0))	begin
		r_spi_driver_valin		<=	1'b1	;
		r_spi_driver_cmdin		<=	PSRAM_READ_ID	;
	end else if ((r_fsm_current == FSM_WRAP_BOUNDARY_TOGGLE) && w_spi_ready && (r_fsm_cnt == 'd0))	begin
		r_spi_driver_valin		<=	1'b1	;
		r_spi_driver_cmdin		<=	PSRAM_WRAP_BOUNDARY_TOGGLE	;
	end else if ((r_fsm_current == FSM_MODE_QPI) && w_spi_ready && (r_fsm_cnt == 'd0))	begin
		r_spi_driver_valin		<=	1'b1	;
		r_spi_driver_cmdin		<=	PSRAM_ENTER_QUAD_MODE	;
	end else		begin 
		r_spi_driver_valin		<=	1'b0	;
		r_spi_driver_cmdin		<=	r_spi_driver_cmdin	;
	end 
end 

always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)	begin	
		r_qspi_driver_valin		<=	1'b0;
		r_qspi_driver_cmdin		<=	'd0	;
	end	else if ((r_fsm_current == FSM_WRITE) && w_qspi_ready && (r_fsm_cnt == 'd0))	begin
		r_qspi_driver_valin		<=	1'b1	;
		r_qspi_driver_cmdin		<=	PSRAM_QUAD_WRITE	;
	end else if ((r_fsm_current == FSM_READ) && w_qspi_ready && (r_fsm_cnt == 'd0))	begin
		r_qspi_driver_valin		<=	1'b1	;
		r_qspi_driver_cmdin		<=	PSRAM_FAST_READ_QUAD	;
	end else if ((r_fsm_current == FSM_MODE_QPI_EXIT) && w_qspi_ready && (r_fsm_cnt == 'd0))	begin
		r_qspi_driver_valin		<=	1'b1	;
		r_qspi_driver_cmdin		<=	PSRAM_EXIT_QUAD_MODE	;
	end else 	begin
		r_qspi_driver_valin		<=	'd0;
		r_qspi_driver_cmdin		<=	r_qspi_driver_cmdin;
	end 
end 

实际效果如下:

如果是写地址和写数据,这个是要由上层模块提供,我这里是自己整个计数器模拟真实数据的。纯属作为测试数据使用。

复制代码
`timescale 1ns / 1ns
module TOP(
	input		wire			clk_i				,	
	
	inout		wire			QSPI_SI_SIO0		,
	inout		wire			QSPI_SO_SIO1		,
	inout		wire			QSPI_SIO2			,
	inout		wire			QSPI_SIO3			,
	output		wire			QSPI_CLK			,
	output 		wire			QSPI_CS				
   );
   
wire			w_clk_80m		;
wire			w_locked		;

localparam		DATA_LEN	=	8'd128	;

(* PAP_MARK_DEBUG="1" *)reg		[7:0]	cnt				;
reg		[7:0]	cnt_1d				;
reg		[7:0]	cnt_2d				;
reg		[7:0]	cnt_3d				;
reg		[23:0]	PsRamCtrAddr = 24'h01050F	;
(* PAP_MARK_DEBUG="1" *)reg				PsRamCtrWr		;
(* PAP_MARK_DEBUG="1" *)reg		[31:0]	PsRamCtrWrDat	;
(* PAP_MARK_DEBUG="1" *)wire			PsRamCtrBusy	;
reg				r_PsRamCtrBusy	;
wire	[7:0]	PsRamCtrBrust 	;
reg		[1:0]	cnt_4freq	;
reg		[1:0]	r_cnt_4freq	;

(* PAP_MARK_DEBUG="1" *)reg		[2:0]	fsm_current	;
reg		[2:0]	fsm_next	;
//*****************************************************************************************//

clock_rst_n#(
	.RST_CNT 	('d100		)
)clock_rst_n_inst(
	.i_clk		(w_clk_80m	),
	
	.o_rst_n	(rst_n		)
);

always @(posedge w_clk_80m, negedge rst_n)	begin
	if (!rst_n)
		fsm_current	<=	'd0	;
	else 
		fsm_current	<=	fsm_next	;
end 

always @(*)	begin
	case (fsm_current)
		0	:
			if (!PsRamCtrBusy && r_PsRamCtrBusy)
				fsm_next	=	'd1	;
			else 
				fsm_next	=	'd0	;
		1	:
			if (cnt == DATA_LEN*4 - 1)
				fsm_next	=	'd2	;
			else 
				fsm_next	=	'd1	;
		2	:
			fsm_next	=	'd0	;
		default	:
			fsm_next	=	'd0	;
	endcase 
end 

always @(posedge w_clk_80m, negedge rst_n)	begin
	if (!rst_n)
		r_PsRamCtrBusy	<=	'd0	;
	else 
		r_PsRamCtrBusy	<=	PsRamCtrBusy	;
end 

always @(posedge w_clk_80m, negedge rst_n)	begin
	if (!rst_n)
		cnt	<=	'd0	;
	else if (cnt == DATA_LEN*4 - 1)
		cnt	<=	'd0	;
	else if (fsm_current == 'd1 && !PsRamCtrBusy)
		cnt	<=	cnt + 'd1	;
	else 
		cnt	<=	'd0	;
end 

always @(posedge w_clk_80m, negedge rst_n)	begin
	if (!rst_n)
		cnt_4freq	<=	'd0	;
	else if (cnt_4freq == 2'b11)
		cnt_4freq	<=	'd0	;
	else if (fsm_current == 'd1 && !PsRamCtrBusy)
		cnt_4freq	<=	cnt_4freq + 'd1	;
	else 
		cnt_4freq	<=	'd0	;
end 

always @(posedge w_clk_80m, negedge rst_n)	begin
	if (!rst_n)
		r_cnt_4freq	<=	'd0	;
	else 
		r_cnt_4freq	<=	cnt_4freq	;
end 

always @(posedge w_clk_80m, negedge rst_n)	begin
	if (!rst_n)	begin
		cnt_1d	<=	'd0	;
		cnt_2d	<=	'd0	;
		cnt_3d	<=	'd0	;
	end else  begin
		cnt_1d	<=	cnt	;
		cnt_2d	<=	cnt_1d	;
		cnt_3d	<=	cnt_2d	;
	end 
end 

always @(posedge w_clk_80m, negedge rst_n)	begin
	if (!rst_n)	begin
		PsRamCtrWrDat	<=	'd0	;
		PsRamCtrWr		<=	'd0	;
	end else if (cnt_4freq == 2'b11)	begin
		PsRamCtrWrDat	<=	{cnt,cnt_1d,cnt_2d,cnt_3d}	;
		PsRamCtrWr		<=	1'b1	;
	end else begin
		PsRamCtrWrDat	<=	'd0	;
		PsRamCtrWr		<=	'd0	;
	end 
end 
   
Clock_Generater Clock_Generater_inst (
	.clkin1				(clk_i			),// input
	.pll_lock			(w_locked		),// output
	.clkout0			(w_clk_80m		) // output
);

APS6404L_PSRAM_Driver	APS6404L_PSRAM_Driver_inst(
	.clk_i				(w_clk_80m		),	//
	.rstn_i				(rst_n			),
			
	//QSPI		
	.QSPI_SI_SIO0		(QSPI_SI_SIO0	),
	.QSPI_SO_SIO1		(QSPI_SO_SIO1	),
	.QSPI_SIO2			(QSPI_SIO2		),
	.QSPI_SIO3			(QSPI_SIO3		),
	.QSPI_CLK			(QSPI_CLK		),
	.QSPI_CS			(QSPI_CS		),
			
	//**********************User port*********************************	
	//Ctr模块接口  				
	.PsRamCtrCs			(PsRamCtrWr		),	//
	.PsRamCtrWr			(PsRamCtrWr		),	//Valid
	.PsRamCtrRd			(1'b1			),	//Valid
	.PsRamCtrAddr		(PsRamCtrAddr	),	//0001:{8'b0,wr_addr},0010:{8'b0,rd_addr},0100:wr_data
	.PsRamCtrWrDat		(PsRamCtrWrDat	),
	.PsRamCtrBrust		(DATA_LEN		),
	
	.PsRamCtrBusy		(PsRamCtrBusy	),	//PSRAM就绪(可写)
	.PsRamCtrRdDat		(),	//{d3,d2,d1,d0}
	.PsRamCtrDatValid	()
);
   
endmodule

然后就没有了,就剩个FIFO缓存模块,没有任何技巧就是存个数据,注意别满别空,深度注意一下就行。

2.3、输出端口

输出端口是inout类型,我这里写的纯属是因为验证两种时序,不属于inout赋值,电路综合出来AND电路了,但是问题不大。

复制代码
(* PAP_MARK_DEBUG="1" *)wire		spi_mosi	= (spi_data_flag)?QSPI_SO_SIO1:1'b0;
(* PAP_MARK_DEBUG="1" *)wire		w_spi_miso	;
wire	w_qspi_si0	= (qspi_rddata_flag)?QSPI_SI_SIO0 :1'b0;
wire	w_qspi_si1	= (qspi_rddata_flag)?QSPI_SO_SIO1 :1'b0;
wire	w_qspi_si2	= (qspi_rddata_flag)?QSPI_SIO2		:1'b0;
wire	w_qspi_si3	= (qspi_rddata_flag)?QSPI_SIO3		:1'b0;
assign	QSPI_SI_SIO0 = (spi_cmd_flag | spi_addr_flag)?w_spi_miso:((qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so0:1'bz);
assign	QSPI_SO_SIO1 = (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so1:1'bz;
assign	QSPI_SIO2	= (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so2:1'bz;
assign	QSPI_SIO3	= (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so3:1'bz;
/*************output************************************/
assign 	QSPI_CLK	 		= 	w_spi_clk | w_qspi_clk		;
assign 	QSPI_CS		 		=	w_spi_cs & w_qspi_cs	;
assign	PsRamCtrBusy		=	r_busy | w_fifo_wr_ready | r_wrfull_flag	;	//w_fifo_wr_ready低有效
assign 	PsRamCtrRdDat		=	w_qspi_rddata	;	
assign 	PsRamCtrDatValid	=	w_qspi_rdval	;

3.顶层源代码

顶层比较简单,没有复杂东西,就是控制命令跳转。

复制代码
`timescale 1ns/1ns

module APS6404L_PSRAM_Driver(
	input		wire			clk_i				,	//100M
	input		wire			rstn_i				,
			
	//QSPI		
	/*synthesis PAP_MARK_DEBUG="1"*/inout		wire			QSPI_SI_SIO0		,
	/*synthesis PAP_MARK_DEBUG="1"*/inout		wire			QSPI_SO_SIO1		,
	/*synthesis PAP_MARK_DEBUG="1"*/inout		wire			QSPI_SIO2			,
	/*synthesis PAP_MARK_DEBUG="1"*/inout		wire			QSPI_SIO3			,
	/*synthesis PAP_MARK_DEBUG="1"*/output		wire			QSPI_CLK			,
	/*synthesis PAP_MARK_DEBUG="1"*/output 		wire			QSPI_CS				,
			
	//**********************User port*********************************	
	//Ctr模块接口  		
	input  		wire			PsRamCtrCs			,	//
	input  		wire			PsRamCtrWr			,	//Valid
	input  		wire			PsRamCtrRd			,	//Valid
	input  		wire	[23:0] 	PsRamCtrAddr		,	//0001:{8'b0,wr_addr},0010:{8'b0,rd_addr},0100:wr_data
	input  		wire	[31:0] 	PsRamCtrWrDat		,
	input		wire	[7:0]	PsRamCtrBrust		,
	
	output  		wire		 	PsRamCtrBusy		,	//PSRAM就绪(可写)
	output  		wire	[7:0] 	PsRamCtrRdDat		,	//
	output  		wire  			PsRamCtrDatValid	
);

localparam		PSRAM_READ					=	8'h03	,
				PSRAM_FAST_READ				=	8'h0B	,
				PSRAM_FAST_READ_QUAD		=	8'hEB	,
				PSRAM_WRITE					=	8'h02	,
				PSRAM_QUAD_WRITE			=	8'h38	,
				PSRAM_ENTER_QUAD_MODE		=	8'h35	,
				PSRAM_EXIT_QUAD_MODE		=	8'hF5	,
				PSRAM_RESET_ENABLE			=	8'h66	,
				PSRAM_RESET					=	8'h99	,
				PSRAM_WRAP_BOUNDARY_TOGGLE	=	8'hC0	,
				PSRAM_READ_ID				=	8'h9F	,
				KGD_ID						=	8'h5D	;
				
parameter		FSM_PSRAM_IDLE				=	5'd0	,
				FSM_POWER_UP				=	5'd1	,
				FSM_RSTEN					=	5'd2	,
				FSM_RST						=	5'd3	,
				FSM_READ_ID					=	5'd4	,
				FSM_WRAP_BOUNDARY_TOGGLE	=	5'd5	,
				FSM_MODE_QPI				=	5'd6	,
				FSM_WRITE					=	5'd7	,
				FSM_READ					=	5'd8	,
				FSM_READ_END				=	5'd9	,
				FSM_MODE_QPI_EXIT			=	5'd10	;

/*************FSM***************************************/
(* PAP_MARK_DEBUG="1" *)reg			[4:0]	r_fsm_current		;
reg			[4:0]	r_fsm_next			;
(* PAP_MARK_DEBUG="1" *)reg			[9:0]	r_fsm_cnt			;
reg			[19:0]	r_power_up_cnt		;
/************READ ID************************************/
(* PAP_MARK_DEBUG="1" *)reg				r_read_id_KGD		;
/************DATA***************************************/
(* PAP_MARK_DEBUG="1" *)reg				r_spi_driver_valin	;
(* PAP_MARK_DEBUG="1" *)reg		[7:0]	r_spi_driver_cmdin	;
(* PAP_MARK_DEBUG="1" *)reg				r_qspi_driver_valin	;
(* PAP_MARK_DEBUG="1" *)reg		[7:0]	r_qspi_driver_cmdin	;
reg					r_spi_ready		;
reg					r_qspi_ready	;
(* PAP_MARK_DEBUG="1" *)reg				r_busy				;
(* PAP_MARK_DEBUG="1" *)reg		[9:0]	r_wr_cnt			;
(* PAP_MARK_DEBUG="1" *)reg				r_wrfull_flag 		;
//*****************************************WIRE*************************************************//
wire	spi_cmd_flag	;
wire	spi_addr_flag	;
wire	spi_data_flag	;
wire	spi_wrcmd_8bit = (r_fsm_current == FSM_RSTEN) || (r_fsm_current == FSM_RST)|| (r_fsm_current == FSM_WRAP_BOUNDARY_TOGGLE) || (r_fsm_current == FSM_MODE_QPI);
wire	qspi_cmd_flag		;
wire	qspi_addr_flag		;
wire	qspi_wrdata_flag	;
wire	qspi_rddata_flag	;
wire	w_qspi_so0	;				
wire	w_qspi_so1	;				
wire	w_qspi_so2	;				
wire	w_qspi_so3	;				
wire	exit_qspi_flag = (r_fsm_current == FSM_MODE_QPI_EXIT);
wire	qspi_wr_en	=	(r_fsm_current == FSM_WRITE);
wire	qspi_rd_en	=	(r_fsm_current == FSM_READ);

(* PAP_MARK_DEBUG="1" *)wire				w_spi_ready			;
(* PAP_MARK_DEBUG="1" *)wire				w_spi_clk			;
(* PAP_MARK_DEBUG="1" *)wire				w_spi_cs			;
(* PAP_MARK_DEBUG="1" *)wire				w_qspi_ready		;
(* PAP_MARK_DEBUG="1" *)wire				w_qspi_clk			;
(* PAP_MARK_DEBUG="1" *)wire				w_qspi_cs			;
wire	[7:0]		w_spi_rddata;
(* PAP_MARK_DEBUG="1" *)wire				w_spi_rdval			;
wire	[7:0]		w_qspi_rddata;
(* PAP_MARK_DEBUG="1" *)wire				w_qspi_rdval		;
(* PAP_MARK_DEBUG="1" *)wire				w_power_up_flag	=	(r_power_up_cnt >= 'd20000)	?	1'b1:1'b0	;
wire				w_spi_data_ready 	= 	w_spi_ready && !r_spi_ready;		//SPI/QSPI数据处理完成标志	
wire				w_qspi_data_ready	=	w_qspi_ready && !r_qspi_ready	;
wire				w_qspi_wr_requset	;
wire				w_fifo_wr_ready		;	
wire	[7:0]		w_qspi_wr_data		;
wire				w_qspi_wr_data_val	;
/*************************Decoder CMD&DATA*************************************/
(* PAP_MARK_DEBUG="1" *)wire		spi_mosi	= (spi_data_flag)?QSPI_SO_SIO1:1'b0;
(* PAP_MARK_DEBUG="1" *)wire		w_spi_miso	;
wire	w_qspi_si0	= (qspi_rddata_flag)?QSPI_SI_SIO0 :1'b0;
wire	w_qspi_si1	= (qspi_rddata_flag)?QSPI_SO_SIO1 :1'b0;
wire	w_qspi_si2	= (qspi_rddata_flag)?QSPI_SIO2		:1'b0;
wire	w_qspi_si3	= (qspi_rddata_flag)?QSPI_SIO3		:1'b0;
assign	QSPI_SI_SIO0 = (spi_cmd_flag | spi_addr_flag)?w_spi_miso:((qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so0:1'bz);
assign	QSPI_SO_SIO1 = (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so1:1'bz;
assign	QSPI_SIO2	= (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so2:1'bz;
assign	QSPI_SIO3	= (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so3:1'bz;
/*************output************************************/
assign 	QSPI_CLK	 		= 	w_spi_clk | w_qspi_clk		;
assign 	QSPI_CS		 		=	w_spi_cs & w_qspi_cs	;
assign	PsRamCtrBusy		=	r_busy | w_fifo_wr_ready | r_wrfull_flag	;	//w_fifo_wr_ready低有效
assign 	PsRamCtrRdDat		=	w_qspi_rddata	;	
assign 	PsRamCtrDatValid	=	w_qspi_rdval	;

always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)
		r_fsm_current	<=	'd0	;
	else 
		r_fsm_current	<=	r_fsm_next	;
end 

always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)
		r_fsm_cnt	<=	'd0	;
	else if (r_fsm_current != r_fsm_next)
		r_fsm_cnt	<=	'd0	;
	else 
		r_fsm_cnt	<=	r_fsm_cnt + 'd1	;
end 

always @(*)
begin
	if (!rstn_i)
		r_fsm_next	=	'd0	;
	else begin
		case (r_fsm_current)
			FSM_PSRAM_IDLE				:
				r_fsm_next	=	(w_power_up_flag)?FSM_POWER_UP:FSM_PSRAM_IDLE;//等待200us启动
			FSM_POWER_UP				:
				r_fsm_next	=	(r_fsm_cnt >= 'd10)?FSM_RSTEN:FSM_POWER_UP	;//增加等待延时
			FSM_RSTEN					:
				r_fsm_next	=	(w_spi_data_ready)?FSM_RST:FSM_RSTEN	;
			FSM_RST						:
				r_fsm_next	=	(w_spi_data_ready)?FSM_READ_ID:FSM_RST	;
			FSM_READ_ID					:
				r_fsm_next	=	(w_spi_data_ready)?FSM_MODE_QPI:FSM_READ_ID	;
			FSM_MODE_QPI				:
				r_fsm_next	=	(w_spi_data_ready)?FSM_WRITE:FSM_MODE_QPI	;
			FSM_WRITE					:
				r_fsm_next	=	(w_qspi_data_ready)?FSM_READ:FSM_WRITE	;
			FSM_READ					:
				r_fsm_next	=	(w_qspi_data_ready)?FSM_MODE_QPI_EXIT:FSM_READ	;
			FSM_MODE_QPI_EXIT			:
				r_fsm_next	=	(w_qspi_data_ready)?FSM_READ_END:FSM_MODE_QPI_EXIT	;
			FSM_READ_END				:
				r_fsm_next	=	FSM_RSTEN	;
			default						:
				r_fsm_next	=	FSM_PSRAM_IDLE	;
		endcase 
	end 
end 

//达到稳定VDD至少150us以上
always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)
		r_power_up_cnt	<=	'd0	;
	else if (r_power_up_cnt >= 'd20_000)
		r_power_up_cnt	<=	r_power_up_cnt	;
	else 
		r_power_up_cnt	<=	r_power_up_cnt + 'd1	;
end 

always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)
		r_read_id_KGD	<=	1'b0	;
	else if (r_fsm_current == FSM_RSTEN || r_fsm_current == FSM_RST)
		r_read_id_KGD	<=	1'b0	;
	else if (w_spi_rdval && (w_spi_rddata == KGD_ID))
		r_read_id_KGD	<=	'd1	;
	else 
		r_read_id_KGD	<=	r_read_id_KGD	;
end 

always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)	
		r_wr_cnt	<=	'd0	;
	else if (!r_busy & !w_fifo_wr_ready & PsRamCtrWr & (r_wr_cnt == PsRamCtrBrust - 1))	
		r_wr_cnt	<=	'd0	;
	else if (!r_busy & !w_fifo_wr_ready & !r_wrfull_flag & PsRamCtrWr)	
		r_wr_cnt	<=	r_wr_cnt + 'd1	;
end 

always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)
		r_wrfull_flag	<=	'd0	;
	else if (w_spi_rdval && (w_spi_rddata == KGD_ID))
		r_wrfull_flag	<=	'd0	;
	else if (!r_busy & !w_fifo_wr_ready & PsRamCtrWr & (r_wr_cnt == PsRamCtrBrust - 1))	
		r_wrfull_flag	<=	'd1	;
	else 
		r_wrfull_flag	<=	r_wrfull_flag	;
end 
	
always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)
		r_busy	<=	'd1	;
	else if (w_spi_rdval && (w_spi_rddata == KGD_ID))
		r_busy	<=	'd0	;
	else if ((r_fsm_current == FSM_WRITE) & w_qspi_data_ready)
		r_busy	<=	'd1	;
	else 
		r_busy	<=	r_busy	;
end 

always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)
		r_spi_ready	<=	1'b0	;
	else 
		r_spi_ready	<=	w_spi_ready	;
end 


always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)	begin	
		r_spi_driver_valin		<=	1'b0	;
		r_spi_driver_cmdin		<=	'd0	;
	end	else if ((r_fsm_current == FSM_RSTEN) && w_spi_ready && (r_fsm_cnt == 'd0))	begin
		r_spi_driver_valin		<=	1'b1	;
		r_spi_driver_cmdin		<=	PSRAM_RESET_ENABLE	;
	end else if ((r_fsm_current == FSM_RST) && w_spi_ready && (r_fsm_cnt == 'd0))	begin
		r_spi_driver_valin		<=	1'b1	;
		r_spi_driver_cmdin		<=	PSRAM_RESET	;
	end else if ((r_fsm_current == FSM_READ_ID) && w_spi_ready && (r_fsm_cnt == 'd0))	begin
		r_spi_driver_valin		<=	1'b1	;
		r_spi_driver_cmdin		<=	PSRAM_READ_ID	;
	end else if ((r_fsm_current == FSM_WRAP_BOUNDARY_TOGGLE) && w_spi_ready && (r_fsm_cnt == 'd0))	begin
		r_spi_driver_valin		<=	1'b1	;
		r_spi_driver_cmdin		<=	PSRAM_WRAP_BOUNDARY_TOGGLE	;
	end else if ((r_fsm_current == FSM_MODE_QPI) && w_spi_ready && (r_fsm_cnt == 'd0))	begin
		r_spi_driver_valin		<=	1'b1	;
		r_spi_driver_cmdin		<=	PSRAM_ENTER_QUAD_MODE	;
	end else		begin 
		r_spi_driver_valin		<=	1'b0	;
		r_spi_driver_cmdin		<=	r_spi_driver_cmdin	;
	end 
end 

//**************************************************SPI***********************************************//
spi_drive#(
	.P_DATA_WIDTH		(8						),
	.P_ADDR_WIDTH		(24						),
	.P_CPOL              	(0 						),
	.P_CPHL              	(0						)
)spi_drive_inst(                  
	.i_clk               	(clk_i					),
	.i_rst               	(!rstn_i				), 
			
	.o_spi_clk           	(w_spi_clk				),
	.o_spi_cs			(w_spi_cs				),

	.i_spi_mosi			(spi_mosi				),
	.o_spi_miso			(w_spi_miso				),
	.i_spi_8bit_cmd		(spi_wrcmd_8bit			),
	.o_spi_cmd_flag		(spi_cmd_flag			),
	.o_spi_addr_flag	(spi_addr_flag			),
	.o_spi_data_flag	(spi_data_flag			),
	
	.i_user_cmd			(r_spi_driver_cmdin		),
	.i_user_addr		(24'd0					),
	.i_user_valid        	(r_spi_driver_valin		),
	.o_user_ready        	(w_spi_ready			),

	.o_user_read_data	(w_spi_rddata			),
	.o_user_read_valid	(w_spi_rdval			)
);

//**************************************************QSPI***********************************************//
wire	fifo_rst = (r_fsm_current == FSM_RSTEN)?1'b1:1'b0	;
Data_PreProcessing	Data_PreProcessing_inst(
	.clk_i				(clk_i					),	//100M
	.rstn_i				(rstn_i					),	//

	.PsRamCtrCs			(PsRamCtrCs				),	//
	.PsRamCtrWr			(PsRamCtrWr				),	//Valid
	.PsRamCtrRd			(PsRamCtrRd				),	//Valid
	.PsRamCtrAddr		(PsRamCtrAddr			),	//0001:{8'b0,wr_addr},0010:{8'b0,rd_addr},0100:wr_data
	.PsRamCtrWrDat		(PsRamCtrWrDat			),
	.PsRamCtrBrust		(PsRamCtrBrust - 1		),

	.i_fifo_rst			(fifo_rst				),
	.i_qspi_wr_req		(w_qspi_wr_requset		),
	.o_qspi_wr_data		(w_qspi_wr_data			),
	.o_fifo_wr_ready	(w_fifo_wr_ready		),	//Active Hign
	.o_qspi_wr_val		(w_qspi_wr_data_val		)
);

always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)
		r_qspi_ready	<=	1'b0	;
	else 
		r_qspi_ready	<=	w_qspi_ready	;
end 

always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)	begin	
		r_qspi_driver_valin		<=	1'b0;
		r_qspi_driver_cmdin		<=	'd0	;
	end	else if ((r_fsm_current == FSM_WRITE) && w_qspi_ready && (r_fsm_cnt == 'd0))	begin
		r_qspi_driver_valin		<=	1'b1	;
		r_qspi_driver_cmdin		<=	PSRAM_QUAD_WRITE	;
	end else if ((r_fsm_current == FSM_READ) && w_qspi_ready && (r_fsm_cnt == 'd0))	begin
		r_qspi_driver_valin		<=	1'b1	;
		r_qspi_driver_cmdin		<=	PSRAM_FAST_READ_QUAD	;
	end else if ((r_fsm_current == FSM_MODE_QPI_EXIT) && w_qspi_ready && (r_fsm_cnt == 'd0))	begin
		r_qspi_driver_valin		<=	1'b1	;
		r_qspi_driver_cmdin		<=	PSRAM_EXIT_QUAD_MODE	;
	end else 	begin
		r_qspi_driver_valin		<=	'd0;
		r_qspi_driver_cmdin		<=	r_qspi_driver_cmdin;
	end 
end 

reg			[23:0]		r_psram_wr_addr	;

always @(posedge clk_i, negedge rstn_i)
begin
	if (!rstn_i)
		r_psram_wr_addr	<=	'd0	;
	else if (PsRamCtrWr)
		r_psram_wr_addr	<=	PsRamCtrAddr	;
end 

qspi_drive#(
	.P_DATA_WIDTH		(8						),
	.P_ADDR_WIDTH		(24						),
	.P_CPOL              	(0 						),
	.P_CPHL              	(0						)
)qspi_drive_inst(                  
	.i_clk               	(clk_i					),
	.i_rst               	(!rstn_i				), 
			
	.o_spi_clk           	(w_qspi_clk				),
	.o_spi_cs			(w_qspi_cs				),
	
	.i_qspi_sio0		(w_qspi_si0				),
	.i_qspi_sio1		(w_qspi_si1				),
	.i_qspi_sio2		(w_qspi_si2				),
	.i_qspi_sio3		(w_qspi_si3				),
	.o_qspi_sio0		(w_qspi_so0				),
	.o_qspi_sio1		(w_qspi_so1				),
	.o_qspi_sio2		(w_qspi_so2				),
	.o_qspi_sio3		(w_qspi_so3				),
	.o_qspi_cmd_flag	(qspi_cmd_flag			),
	.o_qspi_addr_flag	(qspi_addr_flag			),
	.o_qspi_wrdata_flag	(qspi_wrdata_flag		),
	.o_qspi_rddata_flag	(qspi_rddata_flag		),

	.i_fifo_full		(w_fifo_wr_ready		),
	.i_exit_qpi_mode	(exit_qspi_flag			),
	.i_qspi_wren		(qspi_wr_en				),
	.i_qspi_rden		(qspi_rd_en				),
	.i_write_length		(PsRamCtrBrust - 1		),
	.i_read_length		(PsRamCtrBrust - 1		),
	.o_wr_requset		(w_qspi_wr_requset		),
	
	.i_user_cmd			(r_qspi_driver_cmdin	),
	.i_user_wr_addr		(r_psram_wr_addr		),
	.i_user_data         	(w_qspi_wr_data			),
	.i_user_data_val	(w_qspi_wr_data_val		),
	.i_user_cmd_valid	(r_qspi_driver_valin	),
	.o_user_ready        	(w_qspi_ready			),

	.o_user_read_data	(w_qspi_rddata			),
	.o_user_read_valid	(w_qspi_rdval			)
);

endmodule
相关推荐
421!7 小时前
ESP32学习笔记之GPIO
开发语言·笔记·单片机·嵌入式硬件·学习·算法·fpga开发
dMing`8 小时前
基于FPGA的简易数据采集系统
fpga开发·fpga·adc·dac
LCMICRO-1331084774612 小时前
长芯微LD9689完全P2P替代AD9689,是一款双通道、14位、2.0 GSPS/2.6 GSPS模数转换器(ADC)
网络·单片机·嵌入式硬件·网络协议·fpga开发·硬件工程·高速adc
萨文 摩尔杰1 天前
GPS原理学习
学习·fpga开发
Huangichin1 天前
跟着Gemini学System Verilog
fpga开发
LCMICRO-133108477461 天前
长芯微LDC90810完全P2P替代ADC128D818,是一款八通道系统监控器,专为监控复杂系统状态而设计。
stm32·单片机·嵌入式硬件·fpga开发·硬件工程·模数转换芯片adc
s09071361 天前
保姆级教程十二:USB摄像头接入!ZYNQ+OpenCV+FPGA硬件加速图像处理实战(视觉终极篇)
图像处理·opencv·fpga开发·zynq·硬件加速
CoderIsArt1 天前
FPGA-based 量子电路仿真
fpga开发
碎碎思2 天前
升级版流水灯:用FPGA控制上千颗RGB LED
fpga开发
FPGA-ADDA2 天前
第二篇:Xilinx 7系列FPGA详解——从Spartan到Virtex
fpga开发·fpga·sdr·rfsoc