基于intel(altera)FPGA OV5640摄像头 图像采集系统(完整代码)

 此项目一共分为摄像头配置模块,图像采集模块,异步FIFO控制模块,SDRAM控制模块,SDRAM端口模块,VGA显示模块。

摄像头配置模块

        直接采用IIC接口对摄像头进行配置:模块分化:IIC端口模块,IIC控制模块,和LUT查找表模块;配置图像像素输出为1280*720

摄像头配置参数

//涉嫌头参数配置-LUT模块
module  lut_da(
	input 				clk 		,
	input 				rst_n		,
	input 				redy 		, //反馈信号,1可以发数据,0 不能读写
	output 	reg	   		data_en  	,  
	output 	[24:0]   	data_out 	,
	output 				config_done 	  //1代表配置完成
);
parameter  		RW_CTRL=1'b0;  //1代表写模式+读模式  ;0代表只写

localparam 		WAIT_TIME =1000_000,//上电等待时间
				MAX       =253-2  	 ,
		 		WAIT 	  =3'b001,
		   		WRITE	  =3'b010,
		   		IDLE 	  =3'b100;

reg [19:0]		cnt  ;
wire			add_cnt ;
wire			end_cnt ;

reg  [24:0] 	lut_data;
reg    			cnt_flag;

reg [2:0]  		state;
reg [2:0]  		state_next;
wire 			wait_write	;
wire 			write_idle	;
 
always@(posedge clk or negedge rst_n)  begin
	if(!rst_n)  begin
		state<=WAIT;	
	end
	else 	begin
		state<=state_next;
	end
end
always @(*)begin 
	case(state)
		WAIT :begin
			if(wait_write)  begin
				state_next=WRITE;
			end
			else begin
				state_next=WAIT;
			end
		end
		WRITE:begin
			if(write_idle)  begin
				state_next=IDLE;
			end
			else begin
				state_next=WRITE;
			end
		end
		IDLE :begin
			state_next=IDLE;
		end
		default:state=WAIT;
	endcase
end
assign  wait_write=state==WAIT && end_cnt;
assign  write_idle=state==WRITE&& end_cnt;

always @(posedge clk or negedge rst_n)begin 
	if(!rst_n)begin
		cnt <= 0;
	end 
	else if(add_cnt)begin 
		if(end_cnt)begin 
			cnt <= 0;
		end
		else begin 
			cnt <= cnt + 1'b1;
		end 
	end
end 
assign add_cnt = state==WAIT|| (state==WRITE&&cnt_flag);
assign end_cnt = add_cnt && cnt==(  (state==WAIT) ? (WAIT_TIME-1 ): (MAX+1) ) ;
//data_en
always @(posedge clk or negedge rst_n)begin 
	if(!rst_n)begin
		data_en <= 0;
	end 
	else  if( data_en==1 && state==WRITE   ) begin 
		data_en <= 0; 
	end
	else if( state==WRITE  && redy==1 )begin   //redy==1模块空闲中,可以读写操作
		data_en<=1;
	end
end
assign  config_done= state==IDLE;
assign data_out= (state==WRITE) ? lut_data : 1'b0;
always @(posedge clk or negedge rst_n)begin 
	if(!rst_n)begin
		cnt_flag <= 0;
	end 
	else if(data_en)begin 
		cnt_flag<=1'b1;
	end 
	else begin 
		cnt_flag<=0;
	end 
end
//lut_data   
    always@(*)begin
	    case( cnt )			    //2个字节地址,一个字节数据
		 //15fps VGA YUV output
		 // 24MHz input clock, 24MHz PCLK
		 0  :   	 lut_data	= 	{RW_CTRL,24'h3103_11}; // system clock from pad, bit[1]
		 1  :   	 lut_data	= 	{RW_CTRL,24'h3008_82}; // software reset, bit[7]
		 2  :   	 lut_data	= 	{RW_CTRL,24'h3008_42}; // software power down, bit[6]
		 3  :   	 lut_data	= 	{RW_CTRL,24'h3103_03}; // system clock from PLL, bit[1]
		 4  :   	 lut_data	= 	{RW_CTRL,24'h3017_ff}; // FREX, Vsync, HREF, PCLK, D[9:6] output enable
		 5  :   	 lut_data	= 	{RW_CTRL,24'h3018_ff}; // D[5:0], GPIO[1:0] output enable
		 6  :   	 lut_data	= 	{RW_CTRL,24'h3034_1a}; // MIPI 10-bit
		 7  :   	 lut_data	= 	{RW_CTRL,24'h3037_13}; // PLL root divider, bit[4], PLL pre-divider, bit[3:0]
		 8  :   	 lut_data	= 	{RW_CTRL,24'h3108_01}; // PCLK root divider, bit[5:4], SCLK2x root divider, bit[3:2]
		 9  :   	 lut_data	= 	{RW_CTRL,24'h3630_36};// SCLK root divider, bit[1:0]
		 10 :   	 lut_data	= 	{RW_CTRL,24'h3631_0e};
		 11 :   	 lut_data	= 	{RW_CTRL,24'h3632_e2};
		 12 :   	 lut_data	= 	{RW_CTRL,24'h3633_12};
		 13 :   	 lut_data	= 	{RW_CTRL,24'h3621_e0};
		 14 :   	 lut_data	= 	{RW_CTRL,24'h3704_a0};
		 15 :   	 lut_data	= 	{RW_CTRL,24'h3703_5a};
		 16 :   	 lut_data	= 	{RW_CTRL,24'h3715_78};
		 17 :   	 lut_data	= 	{RW_CTRL,24'h3717_01};
		 18 :   	 lut_data	= 	{RW_CTRL,24'h370b_60};
		 19 :   	 lut_data	= 	{RW_CTRL,24'h3705_1a};
		 20 :   	 lut_data	= 	{RW_CTRL,24'h3905_02};
		 21 :   	 lut_data	= 	{RW_CTRL,24'h3906_10};
		 22 :   	 lut_data	= 	{RW_CTRL,24'h3901_0a};
		 23 :   	 lut_data	= 	{RW_CTRL,24'h3731_12};
		 24 :   	 lut_data	= 	{RW_CTRL,24'h3600_08}; // VCM control
		 25 :   	 lut_data	= 	{RW_CTRL,24'h3601_33}; // VCM control
		 26 :   	 lut_data	= 	{RW_CTRL,24'h302d_60}; // system control
		 27 :   	 lut_data	= 	{RW_CTRL,24'h3620_52};
		 28 :   	 lut_data	= 	{RW_CTRL,24'h371b_20};
		 29 :   	 lut_data	= 	{RW_CTRL,24'h471c_50};
		 30 :   	 lut_data	= 	{RW_CTRL,24'h3a13_43}; // pre-gain = 1.047x
		 31 :   	 lut_data	= 	{RW_CTRL,24'h3a18_00}; // gain ceiling
		 32 :   	 lut_data	= 	{RW_CTRL,24'h3a19_f8}; // gain ceiling = 15.5x
		 33 :   	 lut_data	= 	{RW_CTRL,24'h3635_13};
		 34 :   	 lut_data	= 	{RW_CTRL,24'h3636_03};
		 35 :   	 lut_data	= 	{RW_CTRL,24'h3634_40};
		 36 :   	 lut_data	= 	{RW_CTRL,24'h3622_01};
		// 50/60Hz detection 50/60Hz 灯光条纹过滤
		 37 :   	 lut_data	= 	{RW_CTRL,24'h3c01_34}; // Band auto, bit[7]
		 38 :   	 lut_data	= 	{RW_CTRL,24'h3c04_28}; // threshold low sum
		 39 :   	 lut_data	= 	{RW_CTRL,24'h3c05_98}; // threshold high sum
		 40 :   	 lut_data	= 	{RW_CTRL,24'h3c06_00}; // light meter 1 threshold[15:8]
		 41 :   	 lut_data	= 	{RW_CTRL,24'h3c07_08}; // light meter 1 threshold[7:0]
		 42 :   	 lut_data	= 	{RW_CTRL,24'h3c08_00}; // light meter 2 threshold[15:8]
		 43 :   	 lut_data	= 	{RW_CTRL,24'h3c09_1c}; // light meter 2 threshold[7:0]
		 44 :   	 lut_data	= 	{RW_CTRL,24'h3c0a_9c}; // sample number[15:8]
		 45 :   	 lut_data	= 	{RW_CTRL,24'h3c0b_40}; // sample number[7:0]
		 46 :   	 lut_data	= 	{RW_CTRL,24'h3810_00}; // Timing Hoffset[11:8]
		 47 :   	 lut_data	= 	{RW_CTRL,24'h3811_10}; // Timing Hoffset[7:0]
		 48 :   	 lut_data	= 	{RW_CTRL,24'h3812_00}; // Timing Voffset[10:8]
		 49 :   	 lut_data	= 	{RW_CTRL,24'h3708_64};
		 50 :   	 lut_data	= 	{RW_CTRL,24'h4001_02}; // BLC start from line 2
		 51 :   	 lut_data	= 	{RW_CTRL,24'h4005_1a}; // BLC always update
		 52 :   	 lut_data	= 	{RW_CTRL,24'h3000_00}; // enable blocks
		 53 :   	 lut_data	= 	{RW_CTRL,24'h3004_ff}; // enable clocks
		 54 :   	 lut_data	= 	{RW_CTRL,24'h300e_58}; // MIPI power down, DVP enable
		 55 :   	 lut_data	= 	{RW_CTRL,24'h302e_00};
		 56 :   	 lut_data	= 	{RW_CTRL,24'h4300_61}; // RGB,
		 57 :   	 lut_data	= 	{RW_CTRL,24'h501f_01}; // ISP RGB
		 58 :   	 lut_data	= 	{RW_CTRL,24'h440e_00};
		 59 :   	 lut_data	= 	{RW_CTRL,24'h5000_a7}; // Lenc on, raw gamma on, BPC on, WPC on, CIP on
		// AEC target 自动曝光控制
		 60 :   	 lut_data	= 	{RW_CTRL,24'h3a0f_30}; // stable range in high
		 61 :   	 lut_data	= 	{RW_CTRL,24'h3a10_28}; // stable range in low
		 62 :   	 lut_data	= 	{RW_CTRL,24'h3a1b_30}; // stable range out high
		 63 :   	 lut_data	= 	{RW_CTRL,24'h3a1e_26}; // stable range out low
		 64 :   	 lut_data	= 	{RW_CTRL,24'h3a11_60}; // fast zone high
		 65 :   	 lut_data	= 	{RW_CTRL,24'h3a1f_14}; // fast zone low
		// Lens correction for ? 镜头补偿
		 66 :   	 lut_data	= 	{RW_CTRL,24'h5800_23};
		 67 :   	 lut_data	= 	{RW_CTRL,24'h5801_14};
		 68 :   	 lut_data	= 	{RW_CTRL,24'h5802_0f};
		 69 :   	 lut_data	= 	{RW_CTRL,24'h5803_0f};
		 70 :   	 lut_data	= 	{RW_CTRL,24'h5804_12};
		 71 :   	 lut_data	= 	{RW_CTRL,24'h5805_26};
		 72 :   	 lut_data	= 	{RW_CTRL,24'h5806_0c};
		 73 :   	 lut_data	= 	{RW_CTRL,24'h5807_08};
		 74 :   	 lut_data	= 	{RW_CTRL,24'h5808_05};
		 75 :   	 lut_data	= 	{RW_CTRL,24'h5809_05};
		 76 :   	 lut_data	= 	{RW_CTRL,24'h580a_08};
		 77 :   	 lut_data	= 	{RW_CTRL,24'h580b_0d};
		 78 :   	 lut_data	= 	{RW_CTRL,24'h580c_08};
		 79 :   	 lut_data	= 	{RW_CTRL,24'h580d_03};
		 80 :   	 lut_data	= 	{RW_CTRL,24'h580e_00};
		 81 :   	 lut_data	= 	{RW_CTRL,24'h580f_00};
		 82 :   	 lut_data	= 	{RW_CTRL,24'h5810_03};
		 83 :   	 lut_data	= 	{RW_CTRL,24'h5811_09};
		 84 :   	 lut_data	= 	{RW_CTRL,24'h5812_07};
		 85 :   	 lut_data	= 	{RW_CTRL,24'h5813_03};
		 86 :   	 lut_data	= 	{RW_CTRL,24'h5814_00};
		 87 :   	 lut_data	= 	{RW_CTRL,24'h5815_01};
		 88 :   	 lut_data	= 	{RW_CTRL,24'h5816_03};
		 89 :   	 lut_data	= 	{RW_CTRL,24'h5817_08};
		 90 :   	 lut_data	= 	{RW_CTRL,24'h5818_0d};
		 91 :   	 lut_data	= 	{RW_CTRL,24'h5819_08};
		 92 :   	 lut_data	= 	{RW_CTRL,24'h581a_05};
		 93 :   	 lut_data	= 	{RW_CTRL,24'h581b_06};
		 94 :   	 lut_data	= 	{RW_CTRL,24'h581c_08};
		 95 :   	 lut_data	= 	{RW_CTRL,24'h581d_0e};
		 96 :   	 lut_data	= 	{RW_CTRL,24'h581e_29};
		 97 :   	 lut_data	= 	{RW_CTRL,24'h581f_17};
		 98 :   	 lut_data	= 	{RW_CTRL,24'h5820_11};
		 99 :   	 lut_data	= 	{RW_CTRL,24'h5821_11};
		 100:   	 lut_data	= 	{RW_CTRL,24'h5822_15};
		 101:   	 lut_data	= 	{RW_CTRL,24'h5823_28};
		 102:   	 lut_data	= 	{RW_CTRL,24'h5824_46};
		 103:   	 lut_data	= 	{RW_CTRL,24'h5825_26};
		 104:   	 lut_data	= 	{RW_CTRL,24'h5826_08};
		 105:   	 lut_data	= 	{RW_CTRL,24'h5827_26};
		 106:   	 lut_data	= 	{RW_CTRL,24'h5828_64};
		 107:   	 lut_data	= 	{RW_CTRL,24'h5829_26};
		 108:   	 lut_data	= 	{RW_CTRL,24'h582a_24};
		 109:   	 lut_data	= 	{RW_CTRL,24'h582b_22};
		 110:   	 lut_data	= 	{RW_CTRL,24'h582c_24};
		 111:   	 lut_data	= 	{RW_CTRL,24'h582d_24};
		 112:   	 lut_data	= 	{RW_CTRL,24'h582e_06};
		 113:   	 lut_data	= 	{RW_CTRL,24'h582f_22};
		 114:   	 lut_data	= 	{RW_CTRL,24'h5830_40};
		 115:   	 lut_data	= 	{RW_CTRL,24'h5831_42};
		 116:   	 lut_data	= 	{RW_CTRL,24'h5832_24};
		 117:   	 lut_data	= 	{RW_CTRL,24'h5833_26};
		 118:   	 lut_data	= 	{RW_CTRL,24'h5834_24};
		 119:   	 lut_data	= 	{RW_CTRL,24'h5835_22};
		 120:   	 lut_data	= 	{RW_CTRL,24'h5836_22};
		 121:   	 lut_data	= 	{RW_CTRL,24'h5837_26};
		 122:   	 lut_data	= 	{RW_CTRL,24'h5838_44};
		 123:   	 lut_data	= 	{RW_CTRL,24'h5839_24};
		 124:   	 lut_data	= 	{RW_CTRL,24'h583a_26};
		 125:   	 lut_data	= 	{RW_CTRL,24'h583b_28};
		 126:   	 lut_data	= 	{RW_CTRL,24'h583c_42};
		 127:   	 lut_data	= 	{RW_CTRL,24'h583d_ce}; // lenc BR offset
		// AWB 自动白平衡
		 128:   	 lut_data	= 	{RW_CTRL,24'h5180_ff}; // AWB B block
		 129:   	 lut_data	= 	{RW_CTRL,24'h5181_f2}; // AWB control
		 130:   	 lut_data	= 	{RW_CTRL,24'h5182_00}; // [7:4] max local counter, [3:0] max fast counter
		 131:   	 lut_data	= 	{RW_CTRL,24'h5183_14}; // AWB advanced
		 132:   	 lut_data	= 	{RW_CTRL,24'h5184_25};
		 133:   	 lut_data	= 	{RW_CTRL,24'h5185_24};
		 134:   	 lut_data	= 	{RW_CTRL,24'h5186_09};
		 135:   	 lut_data	= 	{RW_CTRL,24'h5187_09};
		 136:   	 lut_data	= 	{RW_CTRL,24'h5188_09};
		 137:   	 lut_data	= 	{RW_CTRL,24'h5189_75};
		 138:   	 lut_data	= 	{RW_CTRL,24'h518a_54};
		 139:   	 lut_data	= 	{RW_CTRL,24'h518b_e0};
		 140:   	 lut_data	= 	{RW_CTRL,24'h518c_b2};
		 141:   	 lut_data	= 	{RW_CTRL,24'h518d_42};
		 142:   	 lut_data	= 	{RW_CTRL,24'h518e_3d};
		 143:   	 lut_data	= 	{RW_CTRL,24'h518f_56};
		 144:   	 lut_data	= 	{RW_CTRL,24'h5190_46};
		 145:   	 lut_data	= 	{RW_CTRL,24'h5191_f8}; // AWB top limit
		 146:   	 lut_data	= 	{RW_CTRL,24'h5192_04}; // AWB bottom limit
		 147:   	 lut_data	= 	{RW_CTRL,24'h5193_70}; // red limit
		 148:   	 lut_data	= 	{RW_CTRL,24'h5194_f0}; // green limit
		 149:   	 lut_data	= 	{RW_CTRL,24'h5195_f0}; // blue limit
		 150:   	 lut_data	= 	{RW_CTRL,24'h5196_03}; // AWB control
		 151:   	 lut_data	= 	{RW_CTRL,24'h5197_01}; // local limit
		 152:   	 lut_data	= 	{RW_CTRL,24'h5198_04};
		 153:   	 lut_data	= 	{RW_CTRL,24'h5199_12};
		 154:   	 lut_data	= 	{RW_CTRL,24'h519a_04};
		 155:   	 lut_data	= 	{RW_CTRL,24'h519b_00};
		 156:   	 lut_data	= 	{RW_CTRL,24'h519c_06};
		 157:   	 lut_data	= 	{RW_CTRL,24'h519d_82};
		 158:   	 lut_data	= 	{RW_CTRL,24'h519e_38}; // AWB control
		// Gamma 伽玛曲线
		 159:   	 lut_data	= 	{RW_CTRL,24'h5480_01}; // Gamma bias plus on, bit[0]
		 160:   	 lut_data	= 	{RW_CTRL,24'h5481_08};
		 161:   	 lut_data	= 	{RW_CTRL,24'h5482_14};
		 162:   	 lut_data	= 	{RW_CTRL,24'h5483_28};
		 163:   	 lut_data	= 	{RW_CTRL,24'h5484_51};
		 164:   	 lut_data	= 	{RW_CTRL,24'h5485_65};
		 165:   	 lut_data	= 	{RW_CTRL,24'h5486_71};
		 166:   	 lut_data	= 	{RW_CTRL,24'h5487_7d};
		 167:   	 lut_data	= 	{RW_CTRL,24'h5488_87};
		 168:   	 lut_data	= 	{RW_CTRL,24'h5489_91};
		 169:   	 lut_data	= 	{RW_CTRL,24'h548a_9a};
		 170:   	 lut_data	= 	{RW_CTRL,24'h548b_aa};
		 171:   	 lut_data	= 	{RW_CTRL,24'h548c_b8};
		 172:   	 lut_data	= 	{RW_CTRL,24'h548d_cd};
		 173:   	 lut_data	= 	{RW_CTRL,24'h548e_dd};
		 174:   	 lut_data	= 	{RW_CTRL,24'h548f_ea};
		 175:   	 lut_data	= 	{RW_CTRL,24'h5490_1d};
		// color matrix 色彩矩阵
		 176:   	 lut_data	= 	{RW_CTRL,24'h5381_1e}; // CMX1 for Y
		 177:   	 lut_data	= 	{RW_CTRL,24'h5382_5b}; // CMX2 for Y
		 178:   	 lut_data	= 	{RW_CTRL,24'h5383_08}; // CMX3 for Y
		 179:   	 lut_data	= 	{RW_CTRL,24'h5384_0a}; // CMX4 for U
		 180:   	 lut_data	= 	{RW_CTRL,24'h5385_7e}; // CMX5 for U
		 181:   	 lut_data	= 	{RW_CTRL,24'h5386_88}; // CMX6 for U
		 182:   	 lut_data	= 	{RW_CTRL,24'h5387_7c}; // CMX7 for V
		 183:   	 lut_data	= 	{RW_CTRL,24'h5388_6c}; // CMX8 for V
		 184:   	 lut_data	= 	{RW_CTRL,24'h5389_10}; // CMX9 for V
		 185:   	 lut_data	= 	{RW_CTRL,24'h538a_01}; // sign[9]
		 186:   	 lut_data	= 	{RW_CTRL,24'h538b_98}; // sign[8:1]
		// UV adjust UV 色彩饱和度调整
		 187:   	 lut_data	= 	{RW_CTRL,24'h5580_06}; // saturation on, bit[1]
		 188:   	 lut_data	= 	{RW_CTRL,24'h5583_40};
		 189:   	 lut_data	= 	{RW_CTRL,24'h5584_10};
		 190:   	 lut_data	= 	{RW_CTRL,24'h5589_10};
		 191:   	 lut_data	= 	{RW_CTRL,24'h558a_00};
		 192:   	 lut_data	= 	{RW_CTRL,24'h558b_f8};
		 193:   	 lut_data	= 	{RW_CTRL,24'h501d_40}; // enable manual offset of contrast
		// CIP 锐化和降噪
		 194:   	 lut_data	= 	{RW_CTRL,24'h5300_08}; // CIP sharpen MT threshold 1
		 195:   	 lut_data	= 	{RW_CTRL,24'h5301_30}; // CIP sharpen MT threshold 2
		 196:   	 lut_data	= 	{RW_CTRL,24'h5302_10}; // CIP sharpen MT offset 1
		 197:   	 lut_data	= 	{RW_CTRL,24'h5303_00}; // CIP sharpen MT offset 2
		 198:   	 lut_data	= 	{RW_CTRL,24'h5304_08}; // CIP DNS threshold 1
		 199:   	 lut_data	= 	{RW_CTRL,24'h5305_30}; // CIP DNS threshold 2
		 200:   	 lut_data	= 	{RW_CTRL,24'h5306_08}; // CIP DNS offset 1
		 201:   	 lut_data	= 	{RW_CTRL,24'h5307_16}; // CIP DNS offset 2
		 202:   	 lut_data	= 	{RW_CTRL,24'h5309_08}; // CIP sharpen TH threshold 1
		 203:   	 lut_data	= 	{RW_CTRL,24'h530a_30}; // CIP sharpen TH threshold 2
		 204:   	 lut_data	= 	{RW_CTRL,24'h530b_04}; // CIP sharpen TH offset 1
		 205:   	 lut_data	= 	{RW_CTRL,24'h530c_06}; // CIP sharpen TH offset 2
		 206:   	 lut_data	= 	{RW_CTRL,24'h5025_00};
		 207:   	 lut_data	= 	{RW_CTRL,24'h3008_02}; // wake up from standby, bit[6]
		 
		// input clock 24Mhz, PCLK 84Mhz
		 208:   	 lut_data	= 	{RW_CTRL,24'h3035_21}; // PLL
		 209:   	 lut_data	= 	{RW_CTRL,24'h3036_69}; // PLL
		 210:   	 lut_data	= 	{RW_CTRL,24'h3c07_07}; // lightmeter 1 threshold[7:0]
		 211:   	 lut_data	= 	{RW_CTRL,24'h3820_47}; // flip
		 212:   	 lut_data	= 	{RW_CTRL,24'h3821_01}; // no mirror
		 213:   	 lut_data	= 	{RW_CTRL,24'h3814_31}; // timing X inc
		 214:   	 lut_data	= 	{RW_CTRL,24'h3815_31}; // timing Y inc
		 215:   	 lut_data	= 	{RW_CTRL,24'h3800_00}; // HS
		 216:   	 lut_data	= 	{RW_CTRL,24'h3801_00}; // HS
		 217:   	 lut_data	= 	{RW_CTRL,24'h3802_00}; // VS
		 218:   	 lut_data	= 	{RW_CTRL,24'h3803_fa}; // VS
		 219:   	 lut_data	= 	{RW_CTRL,24'h3804_0a}; // HW  :   	 lut_data	= 	HE}
		 220:   	 lut_data	= 	{RW_CTRL,24'h3805_3f}; // HW  :   	 lut_data	= 	HE}
		 221:   	 lut_data	= 	{RW_CTRL,24'h3806_06}; // VH  :   	 lut_data	= 	VE}
		 222:   	 lut_data	= 	{RW_CTRL,24'h3807_a9}; // VH  :   	 lut_data	= 	VE}
		 223:   	 lut_data	= 	{RW_CTRL,24'h3808_05}; // DVPHO 1280
		 224:   	 lut_data	= 	{RW_CTRL,24'h3809_00}; // DVPHO
		 225:   	 lut_data	= 	{RW_CTRL,24'h380a_02}; // DVPVO 720
		 226:   	 lut_data	= 	{RW_CTRL,24'h380b_d0}; // DVPVO
		 227:   	 lut_data	= 	{RW_CTRL,24'h380c_07}; // HTS
		 228:   	 lut_data	= 	{RW_CTRL,24'h380d_64}; // HTS
		 229:   	 lut_data	= 	{RW_CTRL,24'h380e_02}; // VTS
		 230:   	 lut_data	= 	{RW_CTRL,24'h380f_e4}; // VTS
		 231:   	 lut_data	= 	{RW_CTRL,24'h3813_04}; // timing V offset
		 232:   	 lut_data	= 	{RW_CTRL,24'h3618_00};
		 233:   	 lut_data	= 	{RW_CTRL,24'h3612_29};
		 234:   	 lut_data	= 	{RW_CTRL,24'h3709_52};
		 235:   	 lut_data	= 	{RW_CTRL,24'h370c_03};
		 236:   	 lut_data	= 	{RW_CTRL,24'h3a02_02}; // 60Hz max exposure
		 237:   	 lut_data	= 	{RW_CTRL,24'h3a03_e0}; // 60Hz max exposure
		 238:   	 lut_data	= 	{RW_CTRL,24'h3a14_02}; // 50Hz max exposure
		 239:   	 lut_data	= 	{RW_CTRL,24'h3a15_e0}; // 50Hz max exposure
		 240:   	 lut_data	= 	{RW_CTRL,24'h4004_02}; // BLC line number
		 241:   	 lut_data	= 	{RW_CTRL,24'h3002_1c}; // reset JFIFO, SFIFO, JPG
		 242:   	 lut_data	= 	{RW_CTRL,24'h3006_c3}; // disable clock of JPEG2x, JPEG
		 243:   	 lut_data	= 	{RW_CTRL,24'h4713_03}; // JPEG mode 3
		 244:   	 lut_data	= 	{RW_CTRL,24'h4407_04}; // Quantization scale
		 245:   	 lut_data	= 	{RW_CTRL,24'h460b_37};
		 246:   	 lut_data	= 	{RW_CTRL,24'h460c_20};
		 247:   	 lut_data	= 	{RW_CTRL,24'h4837_16}; // MIPI global timing
		 248:   	 lut_data	= 	{RW_CTRL,24'h3824_04}; // PCLK manual divider
		 249:   	 lut_data	= 	{RW_CTRL,24'h5001_83}; // SDE on, CMX on, AWB on
		 250:   	 lut_data	= 	{RW_CTRL,24'h3503_00}; // AEC/AGC on                  
		 251:   	 lut_data	= 	{RW_CTRL,24'h4740_20}; // VS 1
		 //252:   	 lut_data	= 	{RW_CTRL,24'h503d_80}; // color bar 选择彩条输出
		 //253:   	 lut_data	= 	{RW_CTRL,24'h4741_00}; //
		default	:	 lut_data	=	0;
	    endcase
    end
	 endmodule 

 IIC端口模块

//IIC端口模块
`include "param.v"
module  i2c_itfc(
    input             clk         ,
    input             rst_n       ,
    input       [4:0] cmd         ,
    input       [7:0] wr_din      ,
        
    input             sda_in      ,
    output  reg       sda_en      ,
    output  reg       sda_out     ,
    output  reg       scl         ,
        
    output  reg  [7:0]rd_out      , 
    output  reg       rd_out_vld  ,
    output  reg       done0       ,
    output  reg       ack              
);
//高位先发msb
parameter   PAN=150,
            DOW_TIME=75,
            WR_TIME =15, //发送数据不管
				RD_TIME =90;//采集数据   
localparam    IDLE      = 7'b000_0001,
              START     = 7'b000_0010,
              WRITE     = 7'b000_0100,
              ACTACK    = 7'b000_1000,
              READ      = 7'b001_0000,
              SENDACK   = 7'b010_0000,
              STOP      = 7'b100_0000;
reg [6:0]           state;
reg [6:0]           state_next;
wire                idle_start   ;
wire                start_write  ;
wire                write_actack ;
wire                actack_start ;
wire                actack_write ;
wire                actack_read  ;
wire                read_sendack ;
wire                sendack_read ;
wire                sendack_stop ;
wire                stop_idle    ;
wire                actack_stop  ;

reg  [15:0] max;
reg  [15:0] cnt_bit;  
wire        add_cnt_bit;
wire        end_cnt_bit;
reg  [3:0]  cnt_byte;  
wire        add_cnt_byte;
wire        end_cnt_byte;
reg  [7:0]  data_flag   ;  //接收数据暂存

always@(posedge  clk  or  negedge  rst_n)  begin
    if(!rst_n) begin
        state<=IDLE;
    end
    else begin
        state<=state_next;
    end
end
always@(*)  begin
    case(state)
        IDLE : begin
            if(idle_start)  begin
                state_next=START;
            end
            else  begin
                state_next<=state;
            end
        end
        START: begin
            if(start_write)  begin
                state_next=WRITE;
            end
            else begin
                state_next<=state;
            end
        end
        WRITE: begin
            if(write_actack)  begin
                state_next=ACTACK;
            end
            else begin
                state_next<=state;
            end
        end
        ACTACK:  begin
            if(actack_start)  begin
                state_next=START;
            end
            else if(actack_write)  begin
                state_next=WRITE;
            end
            else if(actack_read)   begin
                state_next=READ;
            end
            else if(actack_stop)   begin
                state_next=STOP;
            end
            else begin
                state_next<=state;
            end
        end
        READ : begin
            if(read_sendack)  begin
                state_next=SENDACK;
            end
            else  begin
                state_next<=state;
            end
        end
        SENDACK: begin
            if(sendack_stop)  begin
               state_next=STOP; 
            end
            else if(sendack_read)  begin
                state_next=READ;
            end
            else  begin
                state_next<=state;
            end
        end
        STOP : begin
           if(stop_idle)  begin
                state_next=IDLE;
            end
            else  begin
                state_next<=state;
            end
        end
		  default:state_next<=IDLE;
		  endcase
end
assign idle_start  =state==IDLE   && (cmd==`CMD_EN                          )  ;  //开始工作 
assign start_write =state==START  && (end_cnt_byte                          )  ;   
assign write_actack=state==WRITE  && (end_cnt_byte                          )  ;   
assign actack_start=state==ACTACK && (cmd==`CMD_RDST &&end_cnt_byte         )  ;   //读数据的时候发起始位1次
assign actack_write=state==ACTACK && (cmd==`CMD_WR   &&end_cnt_byte         )  ;  //写数据 
assign actack_read =state==ACTACK && (cmd==`CMD_RD   &&end_cnt_byte         )  ;   //接收数据
assign actack_stop =state==ACTACK && ((cmd==`CMD_NO  &&end_cnt_byte)||ack==1)  ;   //写完数据接发停止位 或者ack无应答
assign read_sendack=state==READ   && ( end_cnt_byte                         )  ;   
assign sendack_read=state==SENDACK&& ( end_cnt_byte                         )  ;       
assign sendack_stop=state==SENDACK&& (cmd==`CMD_NO &&end_cnt_byte           )  ; //发停止位      
assign stop_idle   =state==STOP   && (end_cnt_byte                          )  ;   
//一个字节周期
always@(posedge  clk   or negedge  rst_n)  begin
    if(!rst_n)  begin
        cnt_bit<=0;
    end
    else  if(end_cnt_bit) begin
        cnt_bit<=0;
    end
    else  if(add_cnt_bit) begin
        cnt_bit<=cnt_bit+1'b1;
    end
end
assign add_cnt_bit=state!=IDLE;
assign end_cnt_bit=add_cnt_bit && cnt_bit==PAN-1;
//cnt_byte多少个字节周期
always@(posedge  clk  or  negedge  rst_n)  begin
    if(!rst_n)  begin
        cnt_byte<=0;
    end
    else  if(end_cnt_byte) begin
        cnt_byte<=0;
    end
    else  if(add_cnt_byte) begin
        cnt_byte<=cnt_byte+1'b1;
    end
end
assign add_cnt_byte=state!=IDLE && end_cnt_bit;
assign end_cnt_byte=add_cnt_byte && cnt_byte==max-1;  //cnt_byte==MAX-1之后等下个周期add_cnt_byte到了才为零
///max
always@(  *   )  begin
    if(!rst_n)  begin
        max=0;
    end
    else   begin
        case(state)
            START  :  max=1;
            WRITE  :  max=8;
            ACTACK :  max=1;
            READ   :  max=8;
            SENDACK:  max=1;
            STOP   :  max=1;
            default:max=0;
        endcase    
    end
end
//scl
always@(posedge  clk  or  negedge  rst_n)  begin
    if(!rst_n)  begin
        scl<=1;
    end
    else if( cnt_bit==DOW_TIME-1 ) begin  //
        scl<=1;
    end
    else  if( start_write|| ( (state==WRITE||state==READ||state==ACTACK||state==SENDACK)&&cnt_bit==PAN-1&&actack_stop==0 ) ) begin
        scl<=0;   //数据传输状态scl先低电平再高电平 
    end 
    else  if(state==START ||state==STOP) begin  //起始状态,stop状态高电平
        scl<=1;
    end
end
//ack
always@(posedge  clk  or  negedge  rst_n)  begin
    if(!rst_n)  begin
        ack<=0;
    end
    else if(state==ACTACK && cnt_bit==RD_TIME) begin   
        ack<=sda_in;      //发数据时,反馈ack是否应答
    end
    else  if(  stop_idle ) begin     //一次数据发送结束,反馈一个信号
        ack<=1;
    end
    else  begin
         ack<=0;
    end
end 
//sda_en   
always@(posedge  clk or negedge  rst_n)  begin
    if(!rst_n)  begin
        sda_en<=1;
    end
    else if(actack_read||write_actack||sendack_read) begin   //接收应答信号 和 读数据时候  为低电平
        sda_en<=0;
    end
    else  if( read_sendack ||actack_start||actack_write||actack_stop) begin
        sda_en<=1;
    end
end
//sda_out 
always@(posedge  clk  or  negedge  rst_n)  begin
    if(!rst_n)  begin
        sda_out<=1;   //空闲为1
    end
    else if(state==START&& cnt_bit==DOW_TIME )  begin    //起始状态,sda由高拉低
        sda_out<=0;
    end
    else if(state==WRITE && cnt_bit==WR_TIME ) begin   //写数据状态,scl低电平写数据
        sda_out<=wr_din[7-cnt_byte];  //高字节先发
    end
    else  if(read_sendack&&cmd==`CMD_NO) begin   //发送应答信号状态, NO_ACK
        sda_out<=1;
    end
    else  if(   read_sendack    ) begin   //发送应答信号状态,ACK
        sda_out<=0;
    end
    else if( actack_stop|| sendack_stop  )  begin    //停止状态先拉低
        sda_out<=0;
    end
    else if( state==STOP && cnt_bit==DOW_TIME )  begin    //停止状态又由低拉高
        sda_out<=1;
    end
end
//sda_in  data_flag
always@(posedge  clk  or  negedge  rst_n)  begin
    if(!rst_n)  begin
        data_flag<=0;
    end
    else if(state==READ && cnt_bit==RD_TIME-1 ) begin   
        data_flag[8-cnt_byte]<=sda_in;
    end
end
//done
always@(posedge  clk or  negedge  rst_n)  begin
    if(!rst_n)  begin
        done0<=0;
    end
    else if( ((state==ACTACK|| state==READ )&&cnt_bit==PAN-4 && cnt_byte==max-1)||stop_idle) begin   
        //done信号提前3个周期给出去,或者状态结束(反馈到控制模块)
        done0<=1;
    end
    else   begin
        done0<=0;
    end
end
//rd_out  rd_out_vld
always@(posedge  clk  or  negedge  rst_n)  begin
    if(!rst_n)  begin
        rd_out<=0;
        rd_out_vld<=0;
    end
    else if( state==READ &&cnt_bit==PAN-1 ) begin   
        rd_out<=data_flag;
        rd_out_vld<=1;
    end
    else  begin
        rd_out_vld<=0;
    end
end
endmodule 

IIC控制模块

//IIC控制模块
`include "param.v"
module   sio_drive(
    input               clk          ,
    input               rst_n        ,
    output reg          redy         ,   //写数据进来要求。1代表空闲中,0代表工作中
    input               data_en      ,   //lut数据传输开始使能
    input      [24:0]   data_l       ,   //lut数据模块
    output     [7:0]    dout         , //读出的数据
    output              dout_vld     , //读出有效数据
    output    reg       no_ack       , //无应答
//端口模块
    output reg [4:0]    cmd          ,
    output reg [7:0]    data_i2c     ,   //传给端口模块数据
    input      [7:0]    i2c_din      , //端口模块传回数据
    input               i2c_din_vld  ,     
    input               done         ,  //上次数据传输完成标志  
    input               ack              //端口模块        
);
//
parameter       WR_NUM=3'd4,   //读操作一共周期数
                RD_NUM=3'd5,   //写操作一共周期数
                WR_ID =8'h78,  //摄像头写ID
                RD_ID =8'h79;  //摄像头读ID

reg [2:0]       cnt_byte        ;
wire            add_cnt_byte    ;
wire            end_cnt_byte    ;
reg  [2:0]      MAX             ;
wire            rw_ctrl         ;
reg  [23:0]     data_lut        ; //数据暂存
reg             wr_rd           ;
reg  [1:0]      per             ;  

assign  rw_ctrl = data_en ? data_l[24]:1'b0;       //是写+读  或者只写
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        data_lut<=0;
    end 
    else if(data_en)begin 
        data_lut<=data_l[23:0] ;
    end  
end
//wr_rd   per
always@(posedge clk or negedge rst_n)  begin
    if(!rst_n)  begin
        per<=0;
        wr_rd<=0;   //0代表读,1代表写
    end
    else if( rw_ctrl==1  && data_en ) begin   //写模式+读模式
        per<=2;   
        wr_rd<=1;
    end
    else if(rw_ctrl==0 && data_en)  begin  //只写模式
        per<=1;   
        wr_rd<=1;
    end
    else if(cnt_byte==MAX && ack==1)  begin   //ack只有一个周期
        per<=per-1'b1;
        wr_rd<=0;    //读数据
    end
end
//redy
always@(* )  begin
     if(  per==0  )  begin  //per==1 代表空闲状态
        redy=1'b1 ;
    end
    else     begin
        redy=0 ;
    end
end
//no_ack
always@(posedge  clk  or negedge  rst_n)  begin
    if(!rst_n)  begin
        no_ack<=0;
    end
    else  if(cnt_byte>0&&cnt_byte<MAX)  begin
        no_ack<=ack;    
    end
    else     begin
         no_ack<=0; 
    end
end
//cnt_byte
always@(posedge  clk  or negedge  rst_n)  begin
    if(!rst_n)  begin
        cnt_byte<=0;
    end
    else  if(end_cnt_byte && ack==1)  begin
        cnt_byte<=0;
    end
    else  if(end_cnt_byte  )  begin
        cnt_byte<=cnt_byte;
    end
    else if(add_cnt_byte)   begin
        cnt_byte<=cnt_byte+1'b1;
    end
end
assign  add_cnt_byte= done==1  ;    //提前一个周期给反馈信号
assign  end_cnt_byte=(add_cnt_byte && cnt_byte==MAX)||no_ack ;  //最后一个数据发完再接收一个done
//MAX
always@(posedge  clk  or negedge  rst_n)  begin
    if(!rst_n)  begin
        MAX<=0;
    end
    else  if(wr_rd==1 && cnt_byte==0)  begin
        MAX<=WR_NUM ;
    end
    else  if(wr_rd==0 && cnt_byte==0 )   begin
        MAX<=RD_NUM ;
    end
end
//输出给端口模块数据data_i2c
always@(posedge  clk  or negedge  rst_n)  begin
    if(!rst_n)  begin
        data_i2c<=0;
        cmd<=0;
    end
    else  if( wr_rd==1  )  begin  //write
        if( (per==1 ||per==2)&&cnt_byte==0 ) begin   //写模式
            cmd<=`CMD_EN;  //端口模块开始工作
            data_i2c<=WR_ID;
        end
        else 
            case(cnt_byte)
                1   :begin  
                    data_i2c<=data_lut[23:16];
                    cmd<=`CMD_WR;
                    end                        //地址
                2   :begin  
                    data_i2c<=data_lut[15:8] ;
                    cmd<=`CMD_WR;
                    end                             //数据
                3   :begin  
                    data_i2c<=data_lut[7:0]  ;
                    cmd<=`CMD_WR;
                    end  
                4   :begin
                     cmd<=`CMD_NO;   
                end                                           
            default:data_i2c<=0;
            endcase
    end
    else  if( wr_rd==0  )  begin   //read
        if( (per==1 ||per==2)&&cnt_byte==0 ) begin
            cmd<=`CMD_EN;    //端口模块开始工作
            data_i2c<=WR_ID;
        end
        else 
            case(cnt_byte)
                1   :begin 
                    data_i2c<=data_lut[23:16];
                    cmd<=`CMD_WR;
                end
                2   :begin 
                    data_i2c<=data_lut[15:8];
                    cmd<=`CMD_WR;
                end
                3   :begin 
                    data_i2c<=RD_ID;
                    cmd<=`CMD_RDST;
                end
                4   :begin 
                    cmd<=`CMD_RD;
                end
                5   :begin
                    cmd<=`CMD_NO;
                end
            default:begin 
                data_i2c<=0;
                cmd<=0;
            end
            endcase
    end
end
  assign dout    =i2c_din    ;
  assign dout_vld=i2c_din_vld;
endmodule

图像采集模块 

//图像采集模块
`include "param.v"
module  ov5640_capture(
    input                   clk             ,
    input                   rst_n           ,
    input                   href            ,//行同步
    input                   vsync           ,//帧同步
    input                   config_done     , //配置模块完成
    input            [7:0]  din             ,
//输出      
    output   reg     [15:0] dout            ,  //信号与数据和数据有效 在时钟周期内是同步的,
    output   reg            dout_vld        ,  //信号与数据和数据有效 在时钟周期内是同步的,
    output   reg            sop             ,  //信号与数据和数据有效 在时钟周期内是同步的,包头
    output   reg            eop             ,   //信号与数据和数据有效 在时钟周期内是同步的,包尾
	output   reg	 [23:0] cnt_dout_vld  

);
reg  [11:0]  cnt_col;   //行计数器 2560
wire        add_cnt_col;
wire        end_cnt_col;

reg  [9:0]  cnt_row;   //场计数器 720
wire        add_cnt_row;
wire        end_cnt_row;


reg         vsync_r; //一帧的起点
reg         href_flag;
reg         dout_lvd_en;




//帧起点同步
always@(posedge clk or negedge rst_n) begin
    if(!rst_n)  begin
        vsync_r<=0;
    end
    else if( vsync && config_done) begin   //摄像头配置完成
        vsync_r<=1'b1   ;
    end
    else if(dout_vld) begin  
        vsync_r<=0;
    end
end
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        href_flag <= 0;
    end 
    else  if(dout_lvd_en)  begin
        href_flag<=0; 
    end
    else if( href )begin 
        href_flag<=1'b1;
    end 
    else begin 
       href_flag<=0; 
    end 
end
//行计数
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cnt_col <= 0;
    end 
    else if(add_cnt_col)begin 
         if(end_cnt_col)begin 
            cnt_col <= 0;
        end
        else begin 
            cnt_col <= cnt_col + 1'b1;
        end 
    end
end 
assign add_cnt_col = href_flag ;  
assign end_cnt_col = add_cnt_col && cnt_col ==`COL_MAX-1  ;//1280
//场计数
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cnt_row <= 0;
    end 
    else if(add_cnt_row)begin 
        if(end_cnt_row)begin 
            cnt_row <= 0;
        end
        else begin 
            cnt_row <= cnt_row + 1'b1;
        end 
    end
end 
assign add_cnt_row = end_cnt_col;
assign end_cnt_row = add_cnt_row && cnt_row ==`ROW_MAX-1;  //720

always @(posedge clk or negedge rst_n)begin 
	if(!rst_n)  begin
		dout<=0;
	end
    else   begin 
        dout[15-cnt_col[0]*8 -:8] <= din;
    end 
end
//dout_vld   数据晚一个周期
always @(posedge clk or negedge rst_n)begin 
	if(!rst_n)  begin
		dout_vld<=0;
	end
    else if(add_cnt_col   && cnt_col[0]==1)begin 
        dout_vld<=1'b1;
    end 
    else begin 
        dout_vld<=0;
    end 
end
//sop 
always @(posedge clk or negedge rst_n)begin 
	  if(!rst_n)begin
        sop <= 0;
     end 
     else if( add_cnt_col && cnt_col[0]==1&& vsync_r  )begin  
        sop<=1'b1;
    end 
    else  begin 
        sop<=0;    
    end 
end
always @(*)begin 
	 if(end_cnt_row)begin 
       eop=1'b1; 
    end 
    else begin 
        eop=1'b0; 
    end 
end
 //可修改
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        dout_lvd_en <= 0;
    end 
    else if(eop)begin 
        dout_lvd_en<=1'b1;
    end
    else if( vsync    )begin   
        dout_lvd_en<=1'b0;
    end 
end

//仿真测试用
always@(posedge  clk or  negedge  rst_n)  begin
	if(!rst_n)   begin
		cnt_dout_vld<=0;
	end
	else if(eop)  begin
		cnt_dout_vld<=0;
	end
	else  if( add_cnt_col &&   dout_vld==1'b1)  begin
		cnt_dout_vld<=cnt_dout_vld+1'b1;
	end

end

endmodule 


 

异步FIFO控制模块

        此模块采用FIFO18位宽:数据+sop+eop判断

//异步FIFO处理跨时域问题,判断是否丢帧问题
`include "param.v"
//wrfifo 18位
//rdfifo 16位
module  fifo_ctrl (
    input               clk             , //100m
    input               rst_n           ,
    input               clk_in          ,  //84m
    input               clk_out         ,  //75m
          //采集模块数据
    input    [15:0]     din_pixel        ,
    input               din_pixel_vld    ,
    input               sop              ,
    input               eop              , 
         //vga模块
    input               req_vga          ,
    output  reg[15:0]   data_vga         ,
    output  reg         data_vga_vld     ,
         //wrfifo 读出给sdram数据
    output    [11:0]    wrfifo_rdusedw   ,
    output    [17:0]    wrfifo_q         , 
    input               wrfifo_rdreq     ,
         //rdfifo  sdram写进数据
    input     [15:0]    rdfifo_data      ,
    input               rdfifo_wrreq     ,  
    output  reg         sop_vld          , //一帧数据丢失,不能读wrfifo数据
    output    [10:0]    rdfifo_wrusedw   ,
	 output  reg[23:0]     cnt_num        ,
	 output  reg[23:0]     cnt_vld
);

//wrfifo
reg   [17:0]            wrfifo_data         ;
//reg                     eop_vld           ;
reg                     fail                ;
reg                     wrfifo_wrreq        ;
wire                    wrfifo_wrfull       ; 
//rdfifo
wire                    rdfifo_rdempty      ;
wire   [15:0]           rdfifo_q            ;  
wire                    rdfifo_rdreq        ;  
reg                     rdreq_flag          ;
wire    [11:0] 			wrfifo_wusedw	    ;
reg                     sop_flag            ;
wire 	[17:0]			wrfifo_qout		    ;//wrFIFO输出


    wrfifo     u_wrfifo(
    .aclr           (~rst_n             )   ,
	.data           (wrfifo_data        )   ,
	.rdclk          (clk                )   ,
	.rdreq          (rdreq_flag         )   ,
	.wrclk          (clk_in             )   ,
	.wrreq          (wrfifo_wrreq       )   ,
	.q              (wrfifo_qout        )   ,
	.rdusedw        (wrfifo_rdusedw     )   ,
	.wrfull         (wrfifo_wrfull      )   ,
	.wrusedw	    (wrfifo_wusedw	    )
    );
    
    //*****************************************WRFIFO*******************************************//
    always @(posedge clk_in or negedge rst_n)begin 
       if(!rst_n)begin
           wrfifo_data <= 0;
       end 
       else begin 
           wrfifo_data<={sop,eop,din_pixel} ;
       end 
   end
   //sop_vld为1代表这一帧数据丢失
	always @(posedge clk  or negedge rst_n)begin   //写时钟下
        if(!rst_n)begin 
           sop_vld<=1'b0;
       end 
       else   if(  wrfifo_rdusedw>4050  )begin 
           sop_vld <= 1'b1;
       end 
       else  if(  wrfifo_qout[17] /* sop */)  begin   //写数据时钟
           sop_vld<=1'b0;
       end
   end
   always @( * )begin 
        if(sop_vld )begin 
           rdreq_flag=1'b1;
       end 
       else   begin
            rdreq_flag = wrfifo_rdreq;
       end
   end
	always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
           cnt_num <= 0;
       end 
		 else if(wrfifo_qout[16])  begin
		     cnt_num<=0;
		end
       else if(sop_vld==0 &&rdreq_flag )begin 
           cnt_num<=cnt_num+1'b1;
       end
	 end
	assign  wrfifo_q=(sop_vld==0)?wrfifo_qout:0;
	
   always @(posedge clk_in or negedge rst_n)begin 
       if(!rst_n)begin
           sop_flag <= 0;
       end 
       else if(sop==1'b1)begin 
           sop_flag<=1'b1;
       end 
       else   if(eop)begin 
           sop_flag <= 0;
       end 
   end
   always @(posedge clk_in or negedge rst_n)begin 
       if(!rst_n)begin
           wrfifo_wrreq <= 0;
       end 
       else if(wrfifo_wrfull==1'b0)begin 
           wrfifo_wrreq<=(sop_flag&& din_pixel_vld )||sop ;
       end 
   end
   

    //tb测试用
   always @(posedge clk_in or negedge rst_n)begin 
       if(!rst_n)begin
           cnt_vld <= 0;
       end 
		 else  if(sop_flag==0)  begin
			cnt_vld<=0;
		 end
       else   if(wrfifo_wrreq)begin 
           cnt_vld<=cnt_vld+1'b1 ;
       end 
   end

	
	
	
	
//************************rdfifo****************************************//
    rdfifo    u_rdfifo(
    .aclr          (~rst_n             )  ,
	.data           (rdfifo_data        )  ,
	.rdclk          (clk_out            )  ,
	.rdreq          (rdfifo_rdreq       )  ,
	.wrclk          (clk               )  ,        
	.wrreq          (rdfifo_wrreq       )  ,
	.q              (rdfifo_q           )  ,
	.rdempty        (rdfifo_rdempty     )  ,
	.wrusedw        (rdfifo_wrusedw     )  
    );
    //data_vga   
    //data_vga_vld 
    always@(posedge clk_out or negedge rst_n)   begin
        if(!rst_n) begin
            data_vga<=0;
            data_vga_vld<=0;
        end
        else begin
            data_vga<=rdfifo_q;
            data_vga_vld<=rdfifo_rdreq;
        end
    end
    assign  rdfifo_rdreq= rdfifo_rdempty==1'b0 ? req_vga : 1'b0 ;

endmodule 

SDRAM控制模块

SDRAM控制模块

`include    "param.v"
module sdram_ctrl (
input                   clk                ,  
input                   rst_n              ,  
//wrfifo        
input           [1:0]   wrfifo_seop           ,       
input           [11:0]  wrfifo_rdusedw     ,
input                   sop_vld            ,
//rdfifo    
input           [10:0]   rdfifo_wrusedw    ,  
output  reg     [15:0]  dout_fifo          ,        
output  reg             dout_fifo_vld      ,   
//接收端口模块数据  
input           [2:0]   done               ,
input           [15:0]  din_ctrl           ,    
input                   din_ctrl_vld       ,    
//传给端口模块 
output  reg     [23:0]  addr_iftc          ,     
output  reg             wr_en_out          ,   
output  reg             rd_en_out          ,
output  reg          	sop          	    ,	
output	reg				eop	
);

//状态参数
localparam  IDLE  =5'b0000_1,
            ITFCEN=5'b0001_0,
            ADDR  =5'b0010_0,
            WRITE =5'b0100_0,
            READ  =5'b1000_0;
reg [4:0]   state;
reg [4:0]   state_next;
wire        idle_itfcen;
wire        itfcen_addr;
wire        idle_addr ;
wire        addr_write;
wire        addr_read ;
wire        write_idle;
wire        read_idle ;

//信号参数
wire [15:0]      din     ;
reg             wr_en   ;
reg             rd_en   ;


reg  [21:0]   addr_wr;  
wire          add_addr_wr;
wire          end_addr_wr;

reg  [21:0]   addr_rd;  
wire          add_addr_rd;
wire          end_addr_rd;


reg          flag       ;  


reg [1:0]    wr_bank    ;
reg [1:0]    rd_bank    ;
reg          seop       ;
reg          bank_turn  ;//bank翻转记录    
//打拍
	reg			sop_flag;
	wire			nedge;
	wire			pedge;
	reg			sop_vld_r0;
	reg			sop_vld_r1;
	


	


//********************************sop+打拍***************************************8/


always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        sop<=0;
        eop<=0;
		end
        else if(state==WRITE||write_idle)  begin
            eop<=wrfifo_seop[0];
            sop<=0;
        end
		else  if(addr_write ) begin
		    sop<=wrfifo_seop[1];
          eop<=0;
		end
        else begin
           sop<=0;
           eop<=0; 
        end
end



//**************************状态机**********************************************/
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        state <= IDLE;
    end 
     else begin 
            state <= state_next;
    end 
end 
always @(*)begin 
    case(state)
        IDLE :begin
            if(idle_itfcen)  begin
                state_next=ITFCEN;
            end
            else begin
                state_next=state;
            end
        end
        ITFCEN :begin
            if(itfcen_addr)  begin
                state_next=ADDR;
            end
            else begin
                 state_next=state;
            end
        end
        ADDR: begin
            if(addr_write)  begin
                state_next=WRITE;
            end
            else if(addr_read)  begin
                state_next=READ;
            end
            else begin
                state_next=state;
            end
        end
        WRITE:begin
            if(write_idle)  begin
                state_next=IDLE;
            end
            else begin
                state_next=state;
            end
        end
        READ :begin
            if(read_idle)  begin
                state_next=IDLE;
            end
            else begin
                state_next=state;
            end
        end
        default:state_next=IDLE;
    endcase
end
assign    idle_itfcen =state==IDLE  && (wr_en ||rd_en       );  //en必须只有一个周期
assign    itfcen_addr =state==ITFCEN &&(rd_en_out||wr_en_out) ;//仲裁后,判断读写
assign    addr_write=state==ADDR  && (flag==1'b1            ); //提示下一周期给数据
assign    addr_read =state==ADDR  && (flag==1'b0            );//读,给一次地址就行
assign    write_idle=state==WRITE && (done[2]==1'b0         );//提示下一周期停止给数据
assign    read_idle =state==READ  && (done[2]==1'b0         );//done[2]代表一次突发完成

//****************************地址*****************************************/

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        addr_wr <=1'b0;
    end 
    else if(add_addr_wr)begin 
         if(end_addr_wr)begin 
            addr_wr <=1'b0;
        end
        else begin 
            addr_wr <= addr_wr + `BUSRT_MAX;
        end 
    end
end 
assign add_addr_wr = write_idle; //突发完后再加一次
assign end_addr_wr = add_addr_wr && addr_wr ==`FPS-`BUSRT_MAX  ; //一帧像素-突发长度1800-1                                  
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        addr_rd <=1'b0;
    end 
    else if(add_addr_rd)begin 
        if(end_addr_rd)begin 
            addr_rd <=1'b0;
        end
        else begin 
            addr_rd <= addr_rd + `BUSRT_MAX;
        end 
    end
end 
assign add_addr_rd = read_idle;
assign end_addr_rd = add_addr_rd && addr_rd == `FPS-`BUSRT_MAX  ;

//*******************************************seop***************************************//

///
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        seop <= 1'b1;
    end 
    else   if( end_addr_wr )begin 
        seop <=1'b0;                                
    end 
    else if(bank_turn==0   )  begin  //seop突发写标志,1才能写。0 不能写
        seop <= 1'b1;
    end
end
// rd_bank, wr_bank, bank_turn状态  写模式翻转记录
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        wr_bank <= 2'b00;
        rd_bank <=2'b11;
        bank_turn<=1'b0;  //状态翻转记录    0代表已经翻转,可以写。1代表还未翻转等待翻转中
    end 
    else if(  seop==0 && end_addr_rd      )begin 
        wr_bank <=~wr_bank;
        rd_bank <=~rd_bank;
        bank_turn<=1'b0;   
    end 
    else if(   seop==1'b1 && wr_en  )  begin
        bank_turn<=1'b1;        //翻转后
    end
end
//bank_flag  第一个bank写完标志

//*****************************突发信号******************************/
always @(posedge clk or negedge rst_n)begin   
    if(!rst_n)begin
        sop_vld_r0 <=1'b0;
		  sop_vld_r1 <=1'b0;
    end 
    else    begin   //
        sop_vld_r0 <=sop_vld;
		  sop_vld_r1 <=sop_vld_r0;
    end
end
  assign  pedge=sop_vld_r0&& ~sop_vld_r1;
  assign  nedge=~sop_vld_r0&& sop_vld_r1;

  always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        sop_flag <=1'b0;
    end 
    else if(pedge)  begin
        sop_flag<=1'b1;
    end
	 else if(nedge)  begin
        sop_flag<=1'b0;
    end
  end
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        wr_en <=1'b0;
    end 
    else if(idle_itfcen)  begin
        wr_en<=1'b0;
    end
    else if( (wrfifo_rdusedw >=`BUSRT_MAX-1) && seop==1'b1 && state==IDLE && sop_flag==0  )begin 
        wr_en<=1'b1;  //代表一次突发写 
    end  
end
//rd_en//代表一次突发读
always @(posedge clk or negedge rst_n)begin  
    if(!rst_n)begin
        rd_en <=1'b0;
    end 
    else if(idle_itfcen)  begin   
        rd_en <=1'b0;
    end
    else if(/*rd_flag && */rdfifo_wrusedw<`FIFO_L && state==IDLE )begin  //读数据,rdfifo数据量小于300,且端口模块空闲中
        rd_en<=1'b1;
    end 
    else  if(rdfifo_wrusedw>`FIFO_H) begin    //读数据,rdfifo数据量大于1600,
        rd_en<=1'b0;
    end 
end
//读写仲裁标志
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        flag <=1'b0;
    end 
    else if(wr_en&&rd_en &&state==IDLE)  begin // 同时接到读请求、写请求. 
        flag<=~flag;
    end
    else if(wr_en)begin   //突发一次写,
        flag<=1'b1;
    end 
    else if(rd_en)begin   //突发一次读 
        flag<=1'b0;
    end 
end
 
//wr_en_out 传给端口模块的读写使能信号
//rd_en_out

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        wr_en_out <=0 ; 
        rd_en_out <=0 ;
    end 
	 else if( (wr_en_out||rd_en_out)&&state==ITFCEN)  begin
		  wr_en_out <=0 ; 
        rd_en_out <=0 ;
	 end
    else  if( state==ITFCEN)begin 
        wr_en_out <=flag ; 
        rd_en_out <=~flag ;
    end 
    else begin
        wr_en_out <=0 ; 
        rd_en_out <=0 ;
    end
end 

 //**************************输出*********************************************/
//addr_iftc
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
     addr_iftc <= 0;
    end 
    else  if(flag==1'b0)begin
     addr_iftc <= {rd_bank,addr_rd};
    end  
    else begin 
     addr_iftc <= {wr_bank,addr_wr};
    end 
end  

//输出 时序
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        dout_fifo <= 0;
		  dout_fifo_vld<=0;
    end 
    else  begin 
        dout_fifo <= din_ctrl;
		  dout_fifo_vld<=din_ctrl_vld;
    end 
end 


endmodule 

SDRAM端口模块

SDRAM端口模块

`include    "param.v"
module  sdram_itfc(
    input               clk         ,
    input               rst_n       ,
    input               wr_en       , //写使能 .同时地址数据有效
    input               rd_en       , //读使能
    input [23:0]        addr        ,  //12个地址加2个bank地址
	 
	 input 		[15:0]	dout_sdram  ,	
    output 		reg	   dout_sdram_req , 
	 
    output              sclk        ,
    output  reg         cke         ,
    output              cs_n        ,  //除时钟外,使能型号
    output              ras_n       ,  //
    output              cas_n       ,  //
    output              we_n        ,  //
    output reg[1:0]     ba_addr     ,  //bank地址
    output reg[12:0]    sdram_addr  , //输进sdram地址
    //DQM mask
    output reg[1:0]     dqm_out     ,
    inout 		[15:0]		dq       ,  
//接控制模块    
    output reg[2:0]     done        ,    //反馈信号。地址反馈 及一个数据写完了反馈
    output reg[15:0]    data_ctrl   ,
    output reg          data_ctrl_vld 

);

localparam  WAIT =8'b0000_0001, //上电等待20us
            PRECH=8'b0000_0010,//预充电
            AREF =8'b0000_0100,//刷新
            MRS  =8'b0000_1000,//模式设置
            IDLE =8'b0001_0000,//
            ACTI =8'b0010_0000,//bank+row激活  bank,block都是内部划分块名  
            WRITE=8'b0100_0000,//bank+列激活+写
            READ =8'b1000_0000;//bank+列激活+读

reg  [3:0]      cmd;
reg  [7:0]      state;
reg  [7:0]      state_next;
wire            wait_prech ;
wire            prech_aref ;
wire            prech_idle ;
wire            aref_mrs   ;
wire            aref_idle  ;
wire            mrs_idle   ;
wire            idle_aref  ;
wire            idle_acti  ;
wire            acti_write ;
wire            acti_read  ;
wire            write_prech;
wire            read_prech ;
reg   [15:0]    cnt0;
wire            add_cnt0;
wire            end_cnt0;

reg  [9:0]      cnt_ref;
reg             ref_flag;
  

reg  [15:0]      max;   //每个状态cnt0计数最大值
reg              flag; //PRECH标志信号
 
reg             wrrd_flag;
reg             data_vld_r0;  //CL为2的条件下
reg             data_vld_r1;
reg             data_vld_r2;  //列延时为3的情况下选

wire [1:0]      bank;
wire [12:0]     row ;
wire [8:0]      col ;
reg            work;


wire    [15:0]  dq_in           ;
reg    [15:0]  dq_out          ;
reg            dq_en           ;
assign  dq_in=dq; 
assign  dq=dq_en?dq_out:16'bz;


assign bank=addr[23:22];
assign row =addr[21:9] ;
assign col =addr[8:0]  ;

always@(posedge  clk  or  negedge  rst_n )  begin
    if(!rst_n) begin
        state<=WAIT;
    end
    else begin
        state<=state_next;
    end
end
always@(*)  begin
    case(state)
        WAIT  :begin
            if(wait_prech)  begin
                state_next=PRECH;
            end
            else begin
                state_next=state;
            end
        end  
        PRECH :begin
            if( prech_aref)  begin
                state_next=AREF;
            end
            else if(prech_idle) begin
                state_next=IDLE;
            end
            else begin
                state_next=state;
            end
        end   
        AREF  :begin
            if(aref_mrs)  begin
                state_next=MRS;
            end
            else if(aref_idle)  begin
                state_next=IDLE;
            end
            else begin
                state_next=state;
            end
        end   
        MRS   :begin
            if(mrs_idle)  begin
                state_next=IDLE;
            end
            else begin
                state_next=state;
            end
        end   
        IDLE  :begin
            if(idle_aref)  begin//优先
                state_next=AREF;
            end
            else if(idle_acti)  begin
                state_next=ACTI;
            end
            else begin
                state_next=state;
            end
        end   
        ACTI  :begin
            if(acti_write)  begin
                state_next=WRITE;
            end
            else if(acti_read)  begin
                state_next=READ;
            end
            else begin
                state_next=state;
            end
        end   
        WRITE :begin
            if(write_prech)  begin
                state_next=PRECH;
            end
            else begin
                state_next=state;
            end
        end   
        READ  :begin
            if(read_prech)  begin
                state_next=PRECH;
            end
            else begin
                state_next=state;
            end
        end   
        default:state_next=IDLE;
    endcase
end
assign   wait_prech  = state== WAIT  && ( end_cnt0                   );
assign   prech_aref  = state== PRECH && (  flag==0 && end_cnt0       );
assign   prech_idle  = state== PRECH && (  flag==1 && end_cnt0       );
assign   aref_mrs    = state== AREF  && (  flag==0  && end_cnt0      );
assign   aref_idle   = state== AREF  && (  flag==1  && end_cnt0      );
assign   mrs_idle    = state== MRS   && ( end_cnt0                   );    
assign   idle_aref   = state== IDLE  && ( ref_flag==1                );
assign   idle_acti   = state== IDLE  && ( work &&ref_flag==0         );  //ref_flag==1,done就不能发出信号,en就不能为1
assign   acti_write  = state== ACTI  && ( wrrd_flag==0 && end_cnt0   );  
assign   acti_read   = state== ACTI  && ( wrrd_flag==1 && end_cnt0   );
assign   write_prech = state== WRITE && ( end_cnt0                   );  //数据写完后还要延迟2个clk
assign   read_prech  = state== READ  && ( end_cnt0                   );  //数据读完都可以立即发下一命令
//cnt_max
always@( * )  begin
        case(state)
            WAIT  :  max =`TIME_WAIT       ;  //20us
            PRECH :  max =`TIME_TRP        ;  //预充电20ns
            AREF  :  max =`TIME_TRC        ;  //刷新70ns
            MRS   :  max =`TIME_TMRS       ;  //模式寄存器2clk
            IDLE  :  max = 0               ;  //
            ACTI  :  max =`TIME_TRCD       ;  //激活行20ns//2
            WRITE :  max =(`BUSRT_MAX+2) ;  //突发长度完+2clk恢复周期 
            READ  :  max = `BUSRT_MAX      ;  //突发长度+0clk 
            default:max =0;
        endcase
end

always@(posedge clk  or negedge rst_n)  begin
    if(!rst_n)  begin
        cnt0<=0;
    end
    else if(end_cnt0)  begin
        cnt0<=0;
    end
    else  if(add_cnt0)  begin
        cnt0<=cnt0+1'b1;
    end
end
assign   add_cnt0=state!=IDLE ;
assign   end_cnt0=add_cnt0 && cnt0==max-1;

//flag  //预充电下一状态标志//开机到idle后才开始计数
always@(posedge clk  or negedge rst_n)  begin
    if(!rst_n)  begin
         flag<=0;
    end
    else if(mrs_idle)  begin
         flag<=1;    //第一次模式寄存器标志
    end
end
//cnt_ref;  //定时刷新标志
//ref_flag;
always@(posedge clk  or negedge rst_n)  begin
    if(!rst_n)  begin
        cnt_ref<=0;
    end
    else if(cnt_ref==`TIME_REF-1)  begin   //780周期
        cnt_ref<=1;
    end
    else if( flag   )   begin
        cnt_ref<=cnt_ref+1'b1;
    end
end
//刷新标志
always@(posedge clk  or negedge rst_n)  begin
    if(!rst_n)  begin
        ref_flag<=0;
    end
    else if(cnt_ref==`TIME_REF-1)  begin   //780周期
        ref_flag<=1;
    end
    else  if(state==AREF)   begin
        ref_flag<=0;
    end
end
//wrrd_flag  //读或者写标志
always@(posedge clk  or negedge rst_n)  begin
    if(!rst_n)  begin
        wrrd_flag<=0;
    end
    else if(wr_en)  begin   //读写标志信号
        wrrd_flag<=0;
    end
    else  if(rd_en)   begin
        wrrd_flag<=1;
    end
end

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        work <= 0;
    end
	 else if(state==ACTI)begin 
        work <= 0;
    end 
    else if( wr_en||rd_en  )begin 
        work<=1'b1;
    end 
     
end

//命令cmd
assign      cs_n = cmd[3]    ;
assign      ras_n= cmd[2]    ;
assign      cas_n= cmd[1]    ;
assign      we_n = cmd[0]    ;
always@(posedge clk  or negedge rst_n)  begin
    if(!rst_n)  begin  
        cmd<=4'b1111;
    end
    else if(wait_prech) begin           //预充电 0010   同时外加  地址a10 为1
         cmd<=`CMD_PREC; //3
    end
    else if(prech_aref)  begin              //刷新0001
        cmd<=`CMD_AREF;  //7
    end
    else if(aref_mrs)  begin            //模式寄存器0000
        cmd<=`CMD_MRS; //2
    end
    else if(idle_aref)  begin               //刷新0001
        cmd<=`CMD_AREF; //7
    end
    else if(idle_acti)  begin                //激活行0011
        cmd<=`CMD_ACTI; //3
    end
    else if(acti_write)  begin              //写 0100
        cmd<=`CMD_WRITE;  
    end
    else if(acti_read)  begin               //读 0101
        cmd<=`CMD_RDAD; 
    end
    else if(read_prech||write_prech)  begin  //预充电0010
        cmd<=`CMD_PREC;    //同时外加  地址a10 为1
    end
    else    begin     //空命令
        cmd<=`CMD_NOP; 
    end
end
 
// sclk
 //cke
 always@(posedge clk  or negedge rst_n) begin
     if(!rst_n)  begin
         cke<=0;
     end
     else begin
         cke<=1;
     end
 end

 assign  sclk=~clk;//~sclk延迟半个周期                       

 //ba_addr    
//sdram_addr 
always@(posedge clk  or negedge rst_n)  begin
    if(!rst_n)  begin  
        ba_addr <= 2'b00;
        sdram_addr<= 13'b0;
    end
    else if(wait_prech||write_prech||read_prech)  begin     //预充电模式
        sdram_addr<=13'd1024;    //a10为1,所有预充电所有,不需要bank地址
    end
    else if(aref_mrs)   begin
        ba_addr <= 2'b00;
        sdram_addr<={ 3'b000 ,`OP , 2'b00 , `CAS_LTY , `BT , `BL};   //模式寄存器
    end
    else if(idle_acti)  begin //激活
        ba_addr <= bank;//bank
        sdram_addr<=row;   //行地址
    end
    else if(acti_write||acti_read)  begin
        ba_addr <= bank;//bank
        sdram_addr<= col; //列地址
    end
end


//done反馈信号
always@(*)  begin
    if(state!=IDLE||ref_flag ||work==1'b1 )  begin //780周期计数
        done=3'b100 ;   //正在工作中 ,不能给读写命令
    end
    else  begin
        done=3'b000;
    end
end
//写数据
//dout_sdram_req
always@( posedge clk  or negedge rst_n )  begin
    if(!rst_n)   begin
		dout_sdram_req<=0;
    end
	 else if(state==WRITE && cnt0==max-4) begin
		dout_sdram_req<=0;   //提示下下个周期停止给写数据,数据时序输出,打一拍
	 end
    else  if(state== ACTI&&wrrd_flag==0 && add_cnt0 && cnt0==max-2)  begin  
		dout_sdram_req<=1'b1;  //提示下下个周期给写数据+列地址,数据时序输出,打一拍
    end
end
always@( posedge clk  or negedge rst_n )  begin
    if(!rst_n)   begin
	 dq_out<=0;
    end
    else    begin  
	 dq_out<=dout_sdram; 
    end
end 

//读数据
always@(posedge clk  or negedge rst_n)  begin
    if(!rst_n)   begin
        data_vld_r0<=0;
    end
    else   if(read_prech) begin
        data_vld_r0<=0;
    end
    else  if(      acti_read    )  begin                               
        data_vld_r0<=1;  //突发写 ,经过CL列延迟个周期后,出数据
    end
end

//组合输出
always@(*)  begin
    if(!rst_n)  begin
        data_ctrl=0;
    end
    else  begin
         data_ctrl=dq_in;
    end
end


always@(posedge clk  or negedge rst_n)  begin  
    if(!rst_n)   begin
        data_ctrl_vld <=0;
        data_vld_r1<=0;
    end
    else    begin
        data_vld_r1<=data_vld_r0;
        //data_vld_r2<=data_vld_r1;   //列延时为3的情况下选
        data_ctrl_vld<=data_vld_r1;
    end
end


// dq_en /只在写的状态下拉高      

always@(posedge clk  or negedge rst_n)  begin
    if(!rst_n)   begin
        dq_en<=0;
    end
    else  if(acti_write)  begin 
        dq_en<=1;
    end
    else   if(state==WRITE&&cnt0==max-3  ) begin    
        dq_en<=0;
    end
end


always@(posedge clk  or negedge rst_n)  begin
    if(!rst_n)   begin
        dqm_out<=0;
    end
    else   if(state==WRITE&&cnt0==max-3  ) begin          //写后要拉高dqm_out
        dqm_out<=2'b11;
    end
    else if(state!=WRITE)  begin
         dqm_out<=0;
    end
end


endmodule 

VGA显示模块

VGA显示模块

`include "param.v"
module  vga_itfc(
    input           clk     ,
    input           rst_n   ,

    input   [15:0]  din     ,
    input           din_vld ,  //数据有效
    output  reg     req     ,//请求数据信号

    output  reg [15:0]dout_rgb,
    output  reg     hsync   ,
    output  reg     vhync   
);

reg  [11:0]         cnt_h;   //行计数器
wire                add_cnt_h;
wire                end_cnt_h;

reg  [9:0]          cnt_v;    //场计数器
wire                add_cnt_v;
wire                end_cnt_v;

reg                 h_vld    ;  //行有效数据
reg                 v_vld    ;  //场有效数据

reg                 rdreq       ;
wire                wrreq       ;
wire                empty       ;
wire                full        ;
wire  [15:0]        q           ;
wire  [9:0]         usedw       ;



 //    cnt_h  
 always @(posedge clk or negedge rst_n)begin 
     if(!rst_n)begin
         cnt_h <= 0;
     end 
     else if(add_cnt_h)begin 
          if(end_cnt_h)begin 
             cnt_h <= 0;
         end
         else begin 
             cnt_h <= cnt_h + 1'b1;
         end 
     end
 end 
 assign add_cnt_h = 1'b1;   //上电即开始
 assign end_cnt_h = add_cnt_h && cnt_h ==`H_TP-1  ;  //1650
                                         
 always @(posedge clk or negedge rst_n)begin 
     if(!rst_n)begin
         cnt_v <= 0;
     end 
     else if(add_cnt_v)begin 
         if(end_cnt_v)begin 
             cnt_v <= 0;
         end
         else begin 
             cnt_v <= cnt_v + 1'b1;
         end 
     end
 end 
 assign add_cnt_v = end_cnt_h;
 assign end_cnt_v = add_cnt_v && cnt_v == `V_TP-1;  //750        
//h_vld行有效数据
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        h_vld <= 0;
    end 
    else if(add_cnt_h && cnt_h==(`H_SW+`H_BP-1) )begin   //
       h_vld<=1'b1; 
    end 
    else if(add_cnt_h&&cnt_h== (`H_SW +`H_BP +`H_AP-1) )begin 
       h_vld<=0; 
    end 
end  
//v_vld
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        v_vld <= 0;
    end 
    else if(add_cnt_v &&cnt_v== (`V_SW +`V_BP-1 ) )begin 
        v_vld<=1'b1;
    end 
    else if(add_cnt_v && cnt_v==(`V_SW +`V_BP +`V_AP-1) )begin 
       v_vld<=0; 
    end 
end

//rdreq
always @(   *  )begin  
    if( v_vld && h_vld && empty==0 )begin 
        rdreq=1'b1;
    end 
    else begin 
        rdreq=0;  
    end 
end
//dout_rgb
always @(* )begin 
    if(!rst_n)begin
        dout_rgb = 0;
    end 
    else if( rdreq )begin 
        dout_rgb=q;
    end 
	 else  begin
		dout_rgb=0;
	 end
end  

//hsync 
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        hsync <= 0;
    end 
    else if( add_cnt_h && cnt_h== `H_SW-1 )begin 
        hsync<=1'b1;
    end 
    else if(end_cnt_h)begin 
        hsync<=0;
    end 
end  
//vhync 
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        vhync <= 0;
    end 
    else if( add_cnt_v && cnt_v== `V_SW-1 )begin 
        vhync<=1'b1;
    end 
    else if(end_cnt_v)begin 
        vhync<=0;
    end 
end   




buffer  u_buffer(
	.clock ( clk        ) ,
	.data  ( din        ) ,
	.rdreq ( rdreq      ) ,
	.wrreq ( wrreq      ) ,
	.empty ( empty      ) ,
	.full  ( full       ) ,
	.q     ( q          ) ,
	.usedw ( usedw      ) 
    );

//req向sdram读数据
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        req <= 0;
    end 
    else if( usedw<200   )begin 
        req<=1'b1;
    end 
    else if(usedw>900)begin 
       req<=0; 
    end 
end
assign  wrreq= (full==0) ? din_vld : 1'b0 ;


endmodule 

参数模块


/**************************************sdram************************************/
//sdram工作参数
      //`define  BUSRT_1
      //`define  BUSRT_2
      //`define  BUSRT_4
      //`define  BUSRT_8
     `define  BUSRT_512    //突发长度
            `ifdef   BUSRT_1
               `define  BUSRT_MAX  1
               `define  BL   3'b000          //A0-A2
             `elsif  BUSRT_2
                `define  BUSRT_MAX  2
                 `define  BL   3'b001
              `elsif  BUSRT_4
                `define  BUSRT_MAX  4
                 `define  BL   3'b010
              `elsif  BUSRT_8
                `define  BUSRT_MAX  8
                 `define  BL   3'b011
                 `define  FIFO_L   300   //写FIFO的数量低值
                 `define  FIFO_H   1500  //写FIFO的数量高值
             `elsif  BUSRT_512
                 `define  BUSRT_MAX  512
                 `define  BL   3'b111
                 `define  FIFO_L   300   //写FIFO的数量低值
                 `define  FIFO_H   1500  //写FIFO的数量高值
              `endif 

      //连续突发
      //`define  BT   1      //A3
      `define  BT     1'b0

      //突发写/单写
      //`define  OP   1
      `define  OP     1'b0            //A9

      `define   CAS_LTY1  //列选  延迟
      //`define   CAS_LTY2
            `ifdef CAS_LTY1   //列选通延迟设置 延迟    A4-A6
                 `define   CAS_LTY   3'b010
                 `define    CL       2  
            `elsif CAS_LTY2
                 `define   CAS_LTY   3'b011
                 `define    CL       3  
            `endif
       `define   ADDR_MAX    16777215 

//时间参数
      `define     TIME_TRC  7      //刷新命令生效时间  
      `define     TIME_TRP  3      //预充电时间
      `define     TIME_TMRS 2        //2个clk时钟周期  模式寄存器
      `define     TIME_WAIT  20000     //上电等待20us        
      `define     TIME_TRCD 3       //激活命令
      `define     TIME_REF  780     //自动刷新间隔 

//cmd命令参数    cs_n使能,ras_n行选,cas_n列选,we_n写使能
      `define     CMD_WRITE 4'b0100   //写  
      `define     CMD_RDAD  4'b0101  //读
      `define     CMD_ACTI  4'b0011  //激活
      `define     CMD_NOP   4'b0111   //空操作
      `define     CMD_MRS   4'b0000  //模式寄存器
      `define     CMD_AREF  4'b0001  //自刷新  A10==1  
      `define     CMD_PREC  4'b0010   //预充电  所有bank  



/**************************************图像采集模块************************************/
`define   ROW_MAX   720       //一共720行
`define   COL_MAX   2560    //一行1280个像素,一个像素2字节
`define   FPS       921600  //一帧数据有多少个数据     9216
`define   BUSRT_NUM 1800      //突发1800次,一帧数据完


/**************************************vga端口模块************************************/
//vga端口模块  1280*720像素
`define     H_FP   110    //行前沿
`define     H_SW   40     //行同步脉冲
`define     H_BP   220    //行后沿
`define     H_AP   1280   //行有效像素
`define     H_TP   1650   //行总时序

`define     V_FP   5      //场前沿    
`define     V_SW   5      //场同步脉冲       
`define     V_BP   20     //场后沿        
`define     V_AP   720    //场有效像素            
`define     V_TP   750    //场总时序     



/**************************************I2C端口模块************************************/
//I2C端口模块
`define   CMD_EN   5'b000_01    //[0]表示为开始工作
`define   CMD_RDST 5'b000_10    //[1]表示发起始位
`define   CMD_WR   5'b001_00    //[2] 表示写数据    
`define   CMD_RD   5'b010_00    //[3]表示接收数据
`define   CMD_NO   5'b100_00    //[4] 表示发送停止位不应答

备注:fifo_ctrl模块中调用了两个FIFO深度为1024,宽度一个为18bit(包含sop,eop),一个16bit;

VGA显示模块调用FIFO深度为1024,宽度为16bit;

另外调用pll生成时钟24M(摄像头配置输输出时钟)、75M(VGA显示模块输出时钟)、100M(SDRAM时钟)

工程代码:https://download.csdn.net/download/wyong0306/88728960

  • 19
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 23
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值