基于fpga对ddr3的读写控制

1.很多情况下,fpga的内部ip ram的存储量较小,所以需要外挂容量大的芯片。内部的芯片ram称为静态ram,其读写简单,速率中等,缺点就是存储空间较小。spartan—6芯片的最小单元为9k;充电刷新保持数据的额sdram称为动态ram,其容量大,缺点就是高功耗,管脚多,操作时许复杂,占用面积大。无论是静态还是动态ram都是一种易失性器件。

2.当前比较常用的是ddr3,有关ddr3的介绍https://baike.baidu.com/item/DDR3/9505741?fr=aladdin;fpga的spartan6家族中,有一个IP称为MCB(存储控制模块),本文主要就是对控制模块的读写控制,然后通过读写模块对ddr3的数据进行写入与读取。

3.模块的数据流与读写时序如下:

     整个模块的基本数据流就是图所示,本文设计一个display的控制模块,对整个模块进行一个数据验证。而ddr3_rd_ctrl的模块中,申请了一个fifo_2048的fifoIP核,来对ddr3存储的数据进行读取与显示。而frame_start的信号等同于显示器的行列驱动同步,pixel_vaild_o相当于有效显示区域。这个模块需要2个不同频率的时钟,对ddr3的读模块需要125M的时钟,显示模块为50M时钟。

              这个ddr3的数据读取的模块控制时序,需要说明的是读模块要先发出读命令然后才可以读取数据,而写模块要写入数据才可以发出写命令。MCB的fifo的使能信号需要严格控制。

 

3.ddr3的读写主要控制模块程序

module	wr_ddr3_ctrl(

		input	wire			sclk,
		input	wire			rst,
		input	wire			P2_DATA_EMPTY,
		input	wire			c3_calib_done,
		
		output	wire[31:0] 		P2_DATA,		// P2_DATA
		output	wire			P2_DATA_WR_EN,			//P2_DATA_WR_EN
		output	wire[3:0]		P2_data_mask,		
		
		output	wire			P2_CMD_WR_EN,  		//P2_CMD_WR_EN
		output	wire[2:0]		P2_CMD_INSTR,		//P2_CMD_INSTR
		output	wire[5:0]		P2_CMD_BL,			//P2_CMD_BL
		output	wire[29:0]		P2_CMD_ADDR		//P2_CMD_ADDR

);

reg				wr_data_en;
reg		[5:0]	data_cnt=0;
reg		[31:0]	wr_data=0;
reg		[5:0]	burst_cnt=0;
reg				done_dely;
wire			wr_start_flag;
reg				wr_cmd_en;
reg				wr_cycle=0;
reg		[29:0]	wr_addr=0;


assign		P2_CMD_BL=6'd63;
assign		P2_CMD_INSTR=3'b000;
assign		P2_data_mask=4'b0000;
assign		P2_CMD_ADDR=wr_addr;
assign		P2_CMD_WR_EN=wr_cmd_en;	
assign		P2_DATA_WR_EN=wr_data_en;
assign		P2_DATA=wr_data;
	

always@(posedge	sclk)    
		if(rst==1)
		done_dely<=0;
		else done_dely<=c3_calib_done;
assign	wr_start_flag=~(done_dely)&(c3_calib_done);		

always@(posedge sclk )   //
		if(rst==1)
			wr_data_en<=1'b0;
		else if(wr_start_flag==1||(wr_cycle==1&&P2_DATA_EMPTY==1))
			wr_data_en<=1'b1;
		else if(data_cnt=='d63)
			wr_data_en<=1'b0;

always@(posedge sclk )   //
		if(rst==1)
				data_cnt<='d0;
		else if(wr_data_en==1)
				data_cnt<=data_cnt+1'b1;
		else 	data_cnt<='d0;
		
			
always@(posedge sclk)   //
		if(rst==1)
			wr_data<='d0;
		else if(wr_data_en==1&&data_cnt==63&&burst_cnt==63)
				wr_data<='d0;
		else if(wr_data_en==1)
			wr_data<=wr_data+1;
			
always@(posedge sclk)   //
		if(rst==1)
			burst_cnt<='d0;
		else if(wr_data_en==1&&data_cnt==63)
			burst_cnt<=burst_cnt+1'b1;

always@(posedge sclk)   //
		if(rst==1)
		 wr_cmd_en<=1'b0;
		else if(wr_data_en==1&&data_cnt==63)	
		 wr_cmd_en<=1'b1;
		else wr_cmd_en<=1'b0;
		
always@(posedge sclk)   //
		if(rst==1)
			wr_cycle<='d0;	
		else if(wr_data_en==1&&data_cnt==63&&burst_cnt==63)
				wr_cycle<='d0;	
		else if(wr_start_flag==1)	
				wr_cycle<=1;     
		
always@(posedge sclk)   //
		if(rst==1)
		wr_addr<='d0;
		else if(wr_cmd_en==1)
		wr_addr<=wr_addr+256;	
			
endmodule
module	ddr3_rd(

		input	wire			sclk,
		input	wire			wr_sclk,
		input	wire			rst,
		input	wire			c3_calib_done,
		input	wire			frame_start,  
        input	wire			pixel_vaild_o,
     	input	wire			p3_rd_full,
     	input	wire	[31:0]	p3_rd_data,
     	
   		output	reg				p3_cmd_en,
   		output	wire	[2:0]	p3_cmd_inst,
   		output	wire	[5:0]	p3_cmd_bl,
   		output	reg		[29:0]	p3_cmd_byte_addr,
   		output	reg				p3_rd_fifo_en,
   		output	wire	[31:0]	pixel_data	
);

reg  			ddr3_ready;
wire	[10:0]	wr_f_cnt;
reg				rd_ddr3_cycle;
reg		[5:0]	data_cnt;
reg				user_fifo_wr_en;
wire	[10:0]	r_f_cnt;
reg				fifo_enable_read;
wire			user_fifo_rd_en;

assign		p3_cmd_bl=63;
assign		p3_cmd_inst=001;

always@(posedge wr_sclk)
		if(rst==1)
			ddr3_ready<=0;
		else ddr3_ready<=c3_calib_done;
		
always@(posedge wr_sclk)
		if(rst==1)
			rd_ddr3_cycle<=0;
		else if(data_cnt==63) 
			rd_ddr3_cycle<=0;
		else if(ddr3_ready==1&&wr_f_cnt<1024)	
			rd_ddr3_cycle<=1;
			

always@(posedge wr_sclk)
		if(rst==1)
		p3_cmd_en<=0;
		else if(ddr3_ready==1&&wr_f_cnt<1024&&rd_ddr3_cycle==0)
			p3_cmd_en<=1;
		else p3_cmd_en<=0;
		

always@(posedge wr_sclk)
		if(rst==1)
		p3_rd_fifo_en<=1'b0;
		else if(data_cnt==63)
			p3_rd_fifo_en<=1'b0;
		else if(rd_ddr3_cycle==1&&p3_rd_full==1)
			p3_rd_fifo_en<=1'b1;
		
		
always@(posedge wr_sclk)
		if(rst==1)
		p3_cmd_byte_addr<=30'd0;
		else if(p3_cmd_en==1&&p3_cmd_byte_addr==30'h3f00)
				p3_cmd_byte_addr<=30'd0;
		else if(p3_cmd_en==1)	
				p3_cmd_byte_addr<=p3_cmd_byte_addr+256;	


			
always@(posedge wr_sclk)
		if(rst==1)
			data_cnt<=6'd0;
		else if(data_cnt==63)
			data_cnt<=6'd0;
		else if(rd_ddr3_cycle==1&&p3_rd_fifo_en==1)
			data_cnt<=data_cnt+1'b1;

always@(posedge wr_sclk)
		if(rst==1)
			user_fifo_wr_en<=1'b0;
		else if(rd_ddr3_cycle==1&&p3_rd_full==1)
			user_fifo_wr_en<=1'b1;
		else if(data_cnt==63)
			user_fifo_wr_en<=1'b0;

always@(posedge sclk)
		if(rst==1)			
		fifo_enable_read<=1'b0;
		else if(r_f_cnt>1024&&frame_start==1)	
		fifo_enable_read<=1'b1;	

assign	user_fifo_rd_en=fifo_enable_read&pixel_vaild_o;

fifo_wr2048_32 fifo_wr2048_32_inst (
  .wr_clk(wr_sclk), 					// input wr_clk  *125M
  .rd_clk(sclk), 					// input rd_clk   *50M
  .din(p3_rd_data), 						// input [31 : 0] din
  .wr_en(user_fifo_wr_en), 					// input wr_en
  .rd_en(user_fifo_rd_en), 					// input rd_en
  .dout(pixel_data), 						// output [31 : 0] dout
  .full(full),						// output full
  .empty(empty), 					// output empty
  .rd_data_count(r_f_cnt), // output [10 : 0] rd_data_count
  .wr_data_count(wr_f_cnt) // output [10 : 0] wr_data_count
);

endmodule

4.模块时序仿真需要很多时间,仿真才是关键。

猜你喜欢

转载自blog.csdn.net/Headogerz/article/details/82584700