一、FPGA Cyclone Ⅳ OV5640图像实时采集系统设计
1、系统框架2、摄像头配置模块3、图像数据拼接模块4、SDRAM操作模块5、乒乓缓存模块6、VGA驱动模块7、顶层模块8、参数定义9、最终效果①:分析综合②:上板验证1、系统框架
2、摄像头配置模块
使用SCCB协议配置摄像头
/**************************************功能介绍***********************************Copyright:Date:Author :厉长川Version :.10.10 v1Description:摄像头配置模块*********************************************************************************/`include "param.v"module sccb( input clk ,//系统时钟50MHzinput rst_n ,//复位信号output regdone ,//配置完成标志outputcmos_rst_n ,//摄像头复位信号outputcmos_pwdn ,//摄像头掉电使能信号outputregcmos_scl,//时钟线inout cmos_sda //数据线);//参数定义 localparam IDLE = 3'd0 ,//初始化START = 3'd1 ,//起始D_ADD = 3'd2 ,//写入器件地址DC = 3'd3 ,//响应(don't care)H_ADD = 3'd4 ,//写入寄存器地址高八位L_ADD = 3'd5 ,//写入寄存器地址低八位WR = 3'd6 ,//写数据STOP = 3'd7 ;//停止 //中间信号定义 wire idle2start ;//状态跳转条件 wire start2d_add ; wire d_add2dc ; wire dc2h_add ; wire h_add2dc ;wire dc2l_add ; wire l_add2dc ; wire dc2wr ;wire wr2dc ;wire dc2stop; wire stop2idle ; reg[2:0] state_c;//现态reg[2:0] state_n;//次态reg[5:0] cnt_1m;//50Mhz时钟做50分频产生1Mhz时钟 wire add_cnt_1m ; wire end_cnt_1m ; reg clk_1m;//1Mhz时钟 reg[1:0] cnt_250k ;//1Mhz时钟做4分频产生250Khz时钟 reg[3:0] cnt_bit;//bit计数wire add_cnt_bit ; reg[7:0] num ;//配置寄存器个数reg[20:0] cnt_ms;//20ms计数 wire add_cnt_ms ; wire end_cnt_ms ; reg en;//sccb使能reg[31:0] lut_data ;//写入数据(分别是器件地址,寄存器地址和寄存器数据,各8bit)reg[1:0] flag_dc;//计数进入DC状态次数reg sda ;//sccb写数据寄存//cmos_sda:sccb写数据赋值assign cmos_sda = (state_c != DC)?sda:1'bz;//cnt_ms:20ms计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_ms <= 21'b0;end else if(add_cnt_ms)begin if(end_cnt_ms)begin cnt_ms <= 21'b0;endelse begin cnt_ms <= cnt_ms + 1'b1;end endend assign add_cnt_ms = cnt_ms != `CNT_MS;assign end_cnt_ms = add_cnt_ms && cnt_ms == `CNT_MS + 1'b1; //cmos_rst_n:摄像头复位信号assign cmos_rst_n = cnt_ms > `RST_CMOS;//cmos_pwdn:摄像头掉电使能信号assign cmos_pwdn = cnt_ms < `PWDN;//en:sccb使能always @(posedge clk or negedge rst_n)begin if(!rst_n)beginen <= 1'b0;end else if(cnt_ms == `CNT_MS - 1'b1)begin en <= 1'b1;end else if(num == `NUM_CFG)begin en <= 1'b0;end end //cnt_1m:产生1Mhz时钟计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_1m <= 6'b0;end else if(add_cnt_1m)begin if(end_cnt_1m)begin cnt_1m <= 6'b0;endelse begin cnt_1m <= cnt_1m + 1'b1;end endend assign add_cnt_1m = (state_c != IDLE);assign end_cnt_1m = add_cnt_1m && cnt_1m == `CNT_1M - 1'b1;//clk_1m:1Mhz时钟always @(posedge clk or negedge rst_n)begin if(!rst_n)beginclk_1m <= 1'b1;end else if((cnt_1m == (`CNT_1M >> 1) - 1'b1) || end_cnt_1m)begin clk_1m <= ~clk_1m;end end//cnt_250k:产生250Khz时钟计数always @(posedge clk_1m or negedge rst_n)begin if(!rst_n)begincnt_250k <= 2'b0;end else begin cnt_250k <= cnt_250k + 1'b1;end end//cnt_bit:bit计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_bit <= 4'b0;end else if(add_cnt_bit)begin cnt_bit <= cnt_bit + 1'b1;endelse if(state_c == DC)begincnt_bit <= 4'b0;endend assign add_cnt_bit = ((state_c == D_ADD) || (state_c == H_ADD) || (state_c == L_ADD) || (state_c == WR))&& (cnt_250k == 2'd3) && (cnt_1m == 1'b1);//flag_dc:计数进入DC状态次数always @(posedge clk or negedge rst_n)begin if(!rst_n)beginflag_dc <= 2'b0;end else if((cnt_250k == 2'd2) && end_cnt_1m && (state_c == DC))begin flag_dc <= flag_dc + 1'b1;end end//状态机always @(posedge clk or negedge rst_n)begin if(!rst_n)beginstate_c <= IDLE;end else begin state_c <= state_n;end endalways @(*)begin case (state_c)IDLE : if(idle2start)beginstate_n = START;endelse beginstate_n = state_c;endSTART : if(start2d_add)beginstate_n = D_ADD;endelse beginstate_n = state_c;endD_ADD : if(d_add2dc)beginstate_n = DC;endelse beginstate_n = state_c;endDC : if(dc2h_add)beginstate_n = H_ADD;endelse if(dc2l_add)beginstate_n = L_ADD;endelse if(dc2wr)beginstate_n = WR;endelse if(dc2stop)beginstate_n = STOP;endelse beginstate_n = state_c;endH_ADD : if(h_add2dc)beginstate_n = DC;endelse beginstate_n = state_c;endL_ADD : if(l_add2dc)beginstate_n = DC;endelse beginstate_n = state_c;endWR : if(wr2dc)beginstate_n = DC;endelse beginstate_n = state_c;endSTOP : if(stop2idle)beginstate_n = IDLE;endelse beginstate_n = state_c;enddefault: state_n = state_c;endcaseend//给定状态跳转条件assign idle2start= (state_c == IDLE ) && en ;assign start2d_add = (state_c == START) && (cnt_250k == 2'd2) && end_cnt_1m ;assign d_add2dc = (state_c == D_ADD) && (cnt_250k == 2'd2) && end_cnt_1m && (cnt_bit == 4'd8) ;assign dc2h_add = (state_c == DC ) && (cnt_250k == 2'd2) && end_cnt_1m && (flag_dc == 1'b0) ;assign h_add2dc = (state_c == H_ADD) && (cnt_250k == 2'd2) && end_cnt_1m && (cnt_bit == 4'd8) ;assign dc2l_add = (state_c == DC ) && (cnt_250k == 2'd2) && end_cnt_1m && (flag_dc == 1'b1) ; assign l_add2dc = (state_c == L_ADD) && (cnt_250k == 2'd2) && end_cnt_1m && (cnt_bit == 4'd8) ; assign dc2wr= (state_c == DC ) && (cnt_250k == 2'd2) && end_cnt_1m && (flag_dc == 2'd2) ;assign wr2dc= (state_c == WR ) && (cnt_250k == 2'd2) && end_cnt_1m && (cnt_bit == 4'd8) ;assign dc2stop = (state_c == DC ) && (cnt_250k == 2'd2) && end_cnt_1m && (flag_dc == 2'd3) ;assign stop2idle= (state_c == STOP ) && (cnt_250k == 2'd2) && end_cnt_1m ;//cmos_scl:时钟总线always @(posedge clk or negedge rst_n)begin if(!rst_n)begincmos_scl <= 1'b1;end else if((state_c == STOP))beginif((cnt_250k == 2'd3) && end_cnt_1m)begincmos_scl <= 1'b1;endendelse if(state_c != IDLE)begin if((cnt_250k == 1'b1) && end_cnt_1m)begincmos_scl <= 1'b0;endelse if((cnt_250k == 2'd3) && end_cnt_1m)begincmos_scl <= 1'b1;endend else begin cmos_scl <= 1'b1;end end//sda:数据总线always @(posedge clk or negedge rst_n)begin if(!rst_n)beginsda <= 1'b1;end else begin case (state_c)START:if((cnt_250k == 1'b0) && end_cnt_1m)beginsda <= 1'b0;endD_ADD:if((cnt_250k == 2'd3) && (cnt_1m == 2'd2))beginsda <= lut_data[32 - cnt_bit];endDC :if((cnt_250k == 2'd3) && (cnt_1m == 2'd2))beginsda <= 1'b0;endH_ADD:if((cnt_250k == 2'd3) && (cnt_1m == 2'd2))beginsda <= lut_data[24 - cnt_bit];endL_ADD:if((cnt_250k == 2'd3) && (cnt_1m == 2'd2))beginsda <= lut_data[16 - cnt_bit];endWR :if((cnt_250k == 2'd3) && (cnt_1m == 2'd2))beginsda <= lut_data[8 - cnt_bit];endSTOP :if((cnt_250k == 1'b0) && end_cnt_1m)beginsda <= 1'b1;enddefault: sda <= 1'b1;endcaseend end//num:配置寄存器个数计数always @(posedge clk or negedge rst_n)begin if(!rst_n)beginnum <= 1'b0;end else if(dc2stop)begin num <= num + 1'b1;end end//done:配置完成标志always @(posedge clk or negedge rst_n)begin if(!rst_n)begindone <= 1'b0;end else if((num == `NUM_CFG) && stop2idle)begin done <= 1'b1;end end//lut_data:数据always@(*)begincase(num) 8'd0 : lut_data <= {8'h78,16'h3008,8'h82}; //Bit[7]:复位 Bit[6]:电源休眠8'd1 : lut_data <= {8'h78,16'h3008,8'h02}; //正常工作模式8'd2 : lut_data <= {8'h78,16'h3103,8'h02}; //Bit[1]:1 PLL Clock//引脚输入/输出控制 FREX/VSYNC/HREF/PCLK/D[9:6]8'd3 : lut_data <= {8'h78,8'h30,8'h17,8'hff};//引脚输入/输出控制 D[5:0]/GPIO1/GPIO0 8'd4 : lut_data <= {8'h78,16'h3018,8'hff};8'd5 : lut_data <= {8'h78,16'h3037,8'h13}; //PLL分频控制8'd6 : lut_data <= {8'h78,16'h3108,8'h01}; //系统根分频器8'd7 : lut_data <= {8'h78,16'h3630,8'h36};8'd8 : lut_data <= {8'h78,16'h3631,8'h0e};8'd9 : lut_data <= {8'h78,16'h3632,8'he2};8'd10 : lut_data <= {8'h78,16'h3633,8'h12};8'd11 : lut_data <= {8'h78,16'h3621,8'he0};8'd12 : lut_data <= {8'h78,16'h3704,8'ha0};8'd13 : lut_data <= {8'h78,16'h3703,8'h5a};8'd14 : lut_data <= {8'h78,16'h3715,8'h78};8'd15 : lut_data <= {8'h78,16'h3717,8'h01};8'd16 : lut_data <= {8'h78,16'h370b,8'h60};8'd17 : lut_data <= {8'h78,16'h3705,8'h1a};8'd18 : lut_data <= {8'h78,16'h3905,8'h02};8'd19 : lut_data <= {8'h78,16'h3906,8'h10};8'd20 : lut_data <= {8'h78,16'h3901,8'h0a};8'd21 : lut_data <= {8'h78,16'h3731,8'h12};8'd22 : lut_data <= {8'h78,16'h3600,8'h08}; //VCM控制,用于自动聚焦8'd23 : lut_data <= {8'h78,16'h3601,8'h33}; //VCM控制,用于自动聚焦8'd24 : lut_data <= {8'h78,16'h302d,8'h60}; //系统控制8'd25 : lut_data <= {8'h78,16'h3620,8'h52};8'd26 : lut_data <= {8'h78,16'h371b,8'h20};8'd27 : lut_data <= {8'h78,16'h471c,8'h50};8'd28 : lut_data <= {8'h78,16'h3a13,8'h43}; //AEC(自动曝光控制)8'd29 : lut_data <= {8'h78,16'h3a18,8'h00}; //AEC 增益上限8'd30 : lut_data <= {8'h78,16'h3a19,8'hf8}; //AEC 增益上限8'd31 : lut_data <= {8'h78,16'h3635,8'h13};8'd32 : lut_data <= {8'h78,16'h3636,8'h03};8'd33 : lut_data <= {8'h78,16'h3634,8'h40};8'd34 : lut_data <= {8'h78,16'h3622,8'h01};8'd35 : lut_data <= {8'h78,16'h3c01,8'h34};8'd36 : lut_data <= {8'h78,16'h3c04,8'h28};8'd37 : lut_data <= {8'h78,16'h3c05,8'h98};8'd38 : lut_data <= {8'h78,16'h3c06,8'h00}; //light meter 1 阈值[15:8]8'd39 : lut_data <= {8'h78,16'h3c07,8'h08}; //light meter 1 阈值[7:0]8'd40 : lut_data <= {8'h78,16'h3c08,8'h00}; //light meter 2 阈值[15:8]8'd41 : lut_data <= {8'h78,16'h3c09,8'h1c}; //light meter 2 阈值[7:0]8'd42 : lut_data <= {8'h78,16'h3c0a,8'h9c}; //sample number[15:8]8'd43 : lut_data <= {8'h78,16'h3c0b,8'h40}; //sample number[7:0]8'd44 : lut_data <= {8'h78,16'h3810,8'h00}; //Timing Hoffset[11:8]8'd45 : lut_data <= {8'h78,16'h3811,8'h10}; //Timing Hoffset[7:0]8'd46 : lut_data <= {8'h78,16'h3812,8'h00}; //Timing Voffset[10:8]8'd47 : lut_data <= {8'h78,16'h3708,8'h64};8'd48 : lut_data <= {8'h78,16'h4001,8'h02}; //BLC(黑电平校准)补偿起始行号8'd49 : lut_data <= {8'h78,16'h4005,8'h1a}; //BLC(黑电平校准)补偿始终更新8'd50 : lut_data <= {8'h78,16'h3000,8'h00}; //系统块复位控制8'd51 : lut_data <= {8'h78,16'h3004,8'hff}; //时钟使能控制8'd52 : lut_data <= {8'h78,16'h4300,8'h61}; //格式控制 RGB5658'd53 : lut_data <= {8'h78,16'h501f,8'h01}; //ISP RGB8'd54 : lut_data <= {8'h78,16'h440e,8'h00};8'd55 : lut_data <= {8'h78,16'h5000,8'ha7}; //ISP控制8'd56 : lut_data <= {8'h78,16'h3a0f,8'h30}; //AEC控制;stable range in high8'd57 : lut_data <= {8'h78,16'h3a10,8'h28}; //AEC控制;stable range in low8'd58 : lut_data <= {8'h78,16'h3a1b,8'h30}; //AEC控制;stable range out high8'd59 : lut_data <= {8'h78,16'h3a1e,8'h26}; //AEC控制;stable range out low8'd60 : lut_data <= {8'h78,16'h3a11,8'h60}; //AEC控制; fast zone high8'd61 : lut_data <= {8'h78,16'h3a1f,8'h14}; //AEC控制; fast zone low//LENC(镜头校正)控制 16'h5800~16'h583d8'd62 : lut_data <= {8'h78,16'h5800,8'h23}; 8'd63 : lut_data <= {8'h78,16'h5801,8'h14};8'd64 : lut_data <= {8'h78,16'h5802,8'h0f};8'd65 : lut_data <= {8'h78,16'h5803,8'h0f};8'd66 : lut_data <= {8'h78,16'h5804,8'h12};8'd67 : lut_data <= {8'h78,16'h5805,8'h26};8'd68 : lut_data <= {8'h78,16'h5806,8'h0c};8'd69 : lut_data <= {8'h78,16'h5807,8'h08};8'd70 : lut_data <= {8'h78,16'h5808,8'h05};8'd71 : lut_data <= {8'h78,16'h5809,8'h05};8'd72 : lut_data <= {8'h78,16'h580a,8'h08};8'd73 : lut_data <= {8'h78,16'h580b,8'h0d};8'd74 : lut_data <= {8'h78,16'h580c,8'h08};8'd75 : lut_data <= {8'h78,16'h580d,8'h03};8'd76 : lut_data <= {8'h78,16'h580e,8'h00};8'd77 : lut_data <= {8'h78,16'h580f,8'h00};8'd78 : lut_data <= {8'h78,16'h5810,8'h03};8'd79 : lut_data <= {8'h78,16'h5811,8'h09};8'd80 : lut_data <= {8'h78,16'h5812,8'h07};8'd81 : lut_data <= {8'h78,16'h5813,8'h03};8'd82 : lut_data <= {8'h78,16'h5814,8'h00};8'd83 : lut_data <= {8'h78,16'h5815,8'h01};8'd84 : lut_data <= {8'h78,16'h5816,8'h03};8'd85 : lut_data <= {8'h78,16'h5817,8'h08};8'd86 : lut_data <= {8'h78,16'h5818,8'h0d};8'd87 : lut_data <= {8'h78,16'h5819,8'h08};8'd88 : lut_data <= {8'h78,16'h581a,8'h05};8'd89 : lut_data <= {8'h78,16'h581b,8'h06};8'd90 : lut_data <= {8'h78,16'h581c,8'h08};8'd91 : lut_data <= {8'h78,16'h581d,8'h0e};8'd92 : lut_data <= {8'h78,16'h581e,8'h29};8'd93 : lut_data <= {8'h78,16'h581f,8'h17};8'd94 : lut_data <= {8'h78,16'h5820,8'h11};8'd95 : lut_data <= {8'h78,16'h5821,8'h11};8'd96 : lut_data <= {8'h78,16'h5822,8'h15};8'd97 : lut_data <= {8'h78,16'h5823,8'h28};8'd98 : lut_data <= {8'h78,16'h5824,8'h46};8'd99 : lut_data <= {8'h78,16'h5825,8'h26};8'd100: lut_data <= {8'h78,16'h5826,8'h08};8'd101: lut_data <= {8'h78,16'h5827,8'h26};8'd102: lut_data <= {8'h78,16'h5828,8'h64};8'd103: lut_data <= {8'h78,16'h5829,8'h26};8'd104: lut_data <= {8'h78,16'h582a,8'h24};8'd105: lut_data <= {8'h78,16'h582b,8'h22};8'd106: lut_data <= {8'h78,16'h582c,8'h24};8'd107: lut_data <= {8'h78,16'h582d,8'h24};8'd108: lut_data <= {8'h78,16'h582e,8'h06};8'd109: lut_data <= {8'h78,16'h582f,8'h22};8'd110: lut_data <= {8'h78,16'h5830,8'h40};8'd111: lut_data <= {8'h78,16'h5831,8'h42};8'd112: lut_data <= {8'h78,16'h5832,8'h24};8'd113: lut_data <= {8'h78,16'h5833,8'h26};8'd114: lut_data <= {8'h78,16'h5834,8'h24};8'd115: lut_data <= {8'h78,16'h5835,8'h22};8'd116: lut_data <= {8'h78,16'h5836,8'h22};8'd117: lut_data <= {8'h78,16'h5837,8'h26};8'd118: lut_data <= {8'h78,16'h5838,8'h44};8'd119: lut_data <= {8'h78,16'h5839,8'h24};8'd120: lut_data <= {8'h78,16'h583a,8'h26};8'd121: lut_data <= {8'h78,16'h583b,8'h28};8'd122: lut_data <= {8'h78,16'h583c,8'h42};8'd123: lut_data <= {8'h78,16'h583d,8'hce};//AWB(自动白平衡控制) 16'h5180~16'h519e8'd124: lut_data <= {8'h78,16'h5180,8'hff};8'd125: lut_data <= {8'h78,16'h5181,8'hf2};8'd126: lut_data <= {8'h78,16'h5182,8'h00};8'd127: lut_data <= {8'h78,16'h5183,8'h14};8'd128: lut_data <= {8'h78,16'h5184,8'h25};8'd129: lut_data <= {8'h78,16'h5185,8'h24};8'd130: lut_data <= {8'h78,16'h5186,8'h09};8'd131: lut_data <= {8'h78,16'h5187,8'h09};8'd132: lut_data <= {8'h78,16'h5188,8'h09};8'd133: lut_data <= {8'h78,16'h5189,8'h75};8'd134: lut_data <= {8'h78,16'h518a,8'h54};8'd135: lut_data <= {8'h78,16'h518b,8'he0};8'd136: lut_data <= {8'h78,16'h518c,8'hb2};8'd137: lut_data <= {8'h78,16'h518d,8'h42};8'd138: lut_data <= {8'h78,16'h518e,8'h3d};8'd139: lut_data <= {8'h78,16'h518f,8'h56};8'd140: lut_data <= {8'h78,16'h5190,8'h46};8'd141: lut_data <= {8'h78,16'h5191,8'hf8};8'd142: lut_data <= {8'h78,16'h5192,8'h04};8'd143: lut_data <= {8'h78,16'h5193,8'h70};8'd144: lut_data <= {8'h78,16'h5194,8'hf0};8'd145: lut_data <= {8'h78,16'h5195,8'hf0};8'd146: lut_data <= {8'h78,16'h5196,8'h03};8'd147: lut_data <= {8'h78,16'h5197,8'h01};8'd148: lut_data <= {8'h78,16'h5198,8'h04};8'd149: lut_data <= {8'h78,16'h5199,8'h12};8'd150: lut_data <= {8'h78,16'h519a,8'h04};8'd151: lut_data <= {8'h78,16'h519b,8'h00};8'd152: lut_data <= {8'h78,16'h519c,8'h06};8'd153: lut_data <= {8'h78,16'h519d,8'h82};8'd154: lut_data <= {8'h78,16'h519e,8'h38};//Gamma(伽马)控制 16'h5480~16'h54908'd155: lut_data <= {8'h78,16'h5480,8'h01}; 8'd156: lut_data <= {8'h78,16'h5481,8'h08};8'd157: lut_data <= {8'h78,16'h5482,8'h14};8'd158: lut_data <= {8'h78,16'h5483,8'h28};8'd159: lut_data <= {8'h78,16'h5484,8'h51};8'd160: lut_data <= {8'h78,16'h5485,8'h65};8'd161: lut_data <= {8'h78,16'h5486,8'h71};8'd162: lut_data <= {8'h78,16'h5487,8'h7d};8'd163: lut_data <= {8'h78,16'h5488,8'h87};8'd164: lut_data <= {8'h78,16'h5489,8'h91};8'd165: lut_data <= {8'h78,16'h548a,8'h9a};8'd166: lut_data <= {8'h78,16'h548b,8'haa};8'd167: lut_data <= {8'h78,16'h548c,8'hb8};8'd168: lut_data <= {8'h78,16'h548d,8'hcd};8'd169: lut_data <= {8'h78,16'h548e,8'hdd};8'd170: lut_data <= {8'h78,16'h548f,8'hea};8'd171: lut_data <= {8'h78,16'h5490,8'h1d};//CMX(彩色矩阵控制) 16'h5381~16'h538b8'd172: lut_data <= {8'h78,16'h5381,8'h1e};8'd173: lut_data <= {8'h78,16'h5382,8'h5b};8'd174: lut_data <= {8'h78,16'h5383,8'h08};8'd175: lut_data <= {8'h78,16'h5384,8'h0a};8'd176: lut_data <= {8'h78,16'h5385,8'h7e};8'd177: lut_data <= {8'h78,16'h5386,8'h88};8'd178: lut_data <= {8'h78,16'h5387,8'h7c};8'd179: lut_data <= {8'h78,16'h5388,8'h6c};8'd180: lut_data <= {8'h78,16'h5389,8'h10};8'd181: lut_data <= {8'h78,16'h538a,8'h01};8'd182: lut_data <= {8'h78,16'h538b,8'h98};//SDE(特殊数码效果)控制 16'h5580~16'h558b8'd183: lut_data <= {8'h78,16'h5580,8'h06};8'd184: lut_data <= {8'h78,16'h5583,8'h40};8'd185: lut_data <= {8'h78,16'h5584,8'h10};8'd186: lut_data <= {8'h78,16'h5589,8'h10};8'd187: lut_data <= {8'h78,16'h558a,8'h00};8'd188: lut_data <= {8'h78,16'h558b,8'hf8};8'd189: lut_data <= {8'h78,16'h501d,8'h40}; //ISP MISC//CIP(颜色插值)控制 (16'h5300~16'h530c)8'd190: lut_data <= {8'h78,16'h5300,8'h08};8'd191: lut_data <= {8'h78,16'h5301,8'h30};8'd192: lut_data <= {8'h78,16'h5302,8'h10};8'd193: lut_data <= {8'h78,16'h5303,8'h00};8'd194: lut_data <= {8'h78,16'h5304,8'h08};8'd195: lut_data <= {8'h78,16'h5305,8'h30};8'd196: lut_data <= {8'h78,16'h5306,8'h08};8'd197: lut_data <= {8'h78,16'h5307,8'h16};8'd198: lut_data <= {8'h78,16'h5309,8'h08};8'd199: lut_data <= {8'h78,16'h530a,8'h30};8'd200: lut_data <= {8'h78,16'h530b,8'h04};8'd201: lut_data <= {8'h78,16'h530c,8'h06};8'd202: lut_data <= {8'h78,16'h5025,8'h00};//系统时钟分频 Bit[7:4]:系统时钟分频 input clock =24Mhz, PCLK = 48Mhz8'd203: lut_data <= {8'h78,16'h3035,8'h11}; 8'd204: lut_data <= {8'h78,16'h3036,8'h3c}; //PLL倍频8'd205: lut_data <= {8'h78,16'h3c07,8'h08};//时序控制 16'h3800~16'h38218'd206: lut_data <= {8'h78,16'h3820,8'h46};8'd207: lut_data <= {8'h78,16'h3821,8'h01};8'd208: lut_data <= {8'h78,16'h3814,8'h31};8'd209: lut_data <= {8'h78,16'h3815,8'h31};8'd210: lut_data <= {8'h78,16'h3800,8'h00};8'd211: lut_data <= {8'h78,16'h3801,8'h00};8'd212: lut_data <= {8'h78,16'h3802,8'h00};8'd213: lut_data <= {8'h78,16'h3803,8'h04};8'd214: lut_data <= {8'h78,16'h3804,8'h0a};8'd215: lut_data <= {8'h78,16'h3805,8'h3f};8'd216: lut_data <= {8'h78,16'h3806,8'h07};8'd217: lut_data <= {8'h78,16'h3807,8'h9b};//设置输出像素个数//DVP 输出水平像素点数高4位8'd218: lut_data <= {8'h78,16'h3808,8'h04};//DVP 输出水平像素点数低8位8'd219: lut_data <= {8'h78,16'h3809,8'h00};//DVP 输出垂直像素点数高3位8'd220: lut_data <= {8'h78,16'h380a,8'h03};//DVP 输出垂直像素点数低8位8'd221: lut_data <= {8'h78,16'h380b,8'h00};//水平总像素大小高5位8'd222: lut_data <= {8'h78,16'h380c,8'h08};//水平总像素大小低8位 8'd223: lut_data <= {8'h78,16'h380d,8'hc0};//垂直总像素大小高5位 8'd224: lut_data <= {8'h78,16'h380e,8'h04};//垂直总像素大小低8位8'd225: lut_data <= {8'h78,16'h380f,8'hf8};8'd226: lut_data <= {8'h78,16'h3813,8'h06};8'd227: lut_data <= {8'h78,16'h3618,8'h00};8'd228: lut_data <= {8'h78,16'h3612,8'h29};8'd229: lut_data <= {8'h78,16'h3709,8'h52};8'd230: lut_data <= {8'h78,16'h370c,8'h03};8'd231: lut_data <= {8'h78,16'h3a02,8'h17}; //60Hz max exposure8'd232: lut_data <= {8'h78,16'h3a03,8'h10}; //60Hz max exposure8'd233: lut_data <= {8'h78,16'h3a14,8'h17}; //50Hz max exposure8'd234: lut_data <= {8'h78,16'h3a15,8'h10}; //50Hz max exposure8'd235: lut_data <= {8'h78,16'h4004,8'h02}; //BLC(背光) 2 lines8'd236: lut_data <= {8'h78,16'h4713,8'h03}; //JPEG mode 38'd237: lut_data <= {8'h78,16'h4407,8'h04}; //量化标度8'd238: lut_data <= {8'h78,16'h460c,8'h22};8'd239: lut_data <= {8'h78,16'h4837,8'h22}; //DVP CLK divider8'd240: lut_data <= {8'h78,16'h3824,8'h02}; //DVP CLK divider8'd241: lut_data <= {8'h78,16'h5001,8'ha3}; //ISP 控制8'd242: lut_data <= {8'h78,16'h3b07,8'h0a}; //帧曝光模式 //彩条测试使能 8'd243: lut_data <= {8'h78,16'h503d,8'h00}; //8'h00:正常模式 8'h80:彩条显示//测试闪光灯功能8'd244: lut_data <= {8'h78,16'h3016,8'h02};8'd245: lut_data <= {8'h78,16'h301c,8'h02};8'd246: lut_data <= {8'h78,16'h3019,8'h02}; //打开闪光灯8'd247: lut_data <= {8'h78,16'h3019,8'h00}; //关闭闪光灯//只读存储器,防止在case中没有列举的情况,之前的寄存器被重复改写default : lut_data <= {8'h78,16'h300a,8'h00}; //器件ID高8位endcaseendendmodule
3、图像数据拼接模块
将摄像头采集的高八位和低八位图像数据进行拼接
/**************************************功能介绍***********************************Copyright:Date:Author :厉长川Version :.10.10 v1Description:图像数据采集模块*********************************************************************************/`include "param.v"module pixel_sampling( inputclk,//像素采集工作时钟,pclk inputrst_n,//复位信号 input [7:0] din ,//摄像头采集像素inputvsync ,//场同步信号inputhref,//行有效信号output reg dout_valid ,//输出数据有效标志outputreg[15:0]dout //输出拼接完成的像素 );//中间信号定义 reg [7:0] din_r ;//像素缓存reg [1:0] v_r ;//场同步信号同步打拍,检测上升沿reg flag;//像素拼接标志,高电平拼接,低电平缓存reg pixel_valid ;//舍弃10帧完成reg [3:0]cnt_frame;//像素帧计数wire add_cnt_frame ;wire end_cnt_frame ;//v_r:场同步信号同步打拍always @(posedge clk or negedge rst_n)begin if(!rst_n)beginv_r <= 2'b0;end else begin v_r <= {v_r[0], vsync};end end//cnt_frame:像素帧计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_frame <= 4'b0;end else if(add_cnt_frame)begin if(end_cnt_frame)begin cnt_frame <= 4'b0;endelse begin cnt_frame <= cnt_frame + 1'b1;end endend assign add_cnt_frame = (v_r[0] & ~v_r[1]) && (cnt_frame <= `PIXEL);assign end_cnt_frame = add_cnt_frame && cnt_frame == `PIXEL + 1'b1;//pixel_valid:舍弃10帧完成always @(posedge clk or negedge rst_n)begin if(!rst_n)beginpixel_valid <= 1'b0;end else if(cnt_frame == `PIXEL)begin pixel_valid <= 1'b1;end end//flag:像素拼接标志always @(posedge clk or negedge rst_n)begin if(!rst_n)beginflag <= 1'b0;end else if(href && pixel_valid)begin flag <= ~flag;end else beginflag <= 1'b0;endend//din_r:像素缓存always @(posedge clk or negedge rst_n)begin if(!rst_n)begindin_r <= 8'b0;end else if(href && pixel_valid)begin din_r <= din;end end//dout:像素拼接always @(posedge clk or negedge rst_n)begin if(!rst_n)begindout <= 16'b0;end else if(href && pixel_valid && flag)begin dout <= {din_r, din};end end//dout_valid:输出数据有效标志always @(posedge clk or negedge rst_n)begin if(!rst_n)begindout_valid <= 1'b0;end else if(href && pixel_valid)begin dout_valid <= flag;end else begindout_valid <= 1'b0;endendendmodule
4、SDRAM操作模块
SDRAM初始化、自刷新、读和写操作使用一个状态机完成
/**************************************功能介绍***********************************Copyright:Date:Author :厉长川Version :.10.10 v1Description:SDRAM模块*********************************************************************************/`include "param.v"module sdram( inputclk ,//100Mhzinputrst_n ,//复位,低电平inputw_req ,//写请求input r_req ,//读请求input[23:0]w_addr,//写地址input[23:0]r_addr ,//读地址input[15:0]w_data ,//写数据output[15:0] r_data,//读数据output reg [12:0] sdram_addr ,//地址总线output reg [1:0] sdram_ba ,//bank选择inout [15:0] sdram_dq ,//数据总线output reg [3:0] cmd ,//命令output r_ack ,//写操作响应output wr_ack,//读操作响应output reginit_done ,//初始化结束output w_done,//写操作完成标志output r_done //读操作完成标志); //参数定义parameter IDLE= 4'd0 ,//初始化PRE = 4'd1 ,//预充电状态AREF= 4'd2 ,//自动刷新状态REGIST = 4'd3 ,//模式寄存器配置W_ACT= 4'd4 ,//写行激活R_ACT= 4'd5 ,//读行激活WRITE= 4'd6 ,//写状态READ= 4'd7 ,//读状态BURST= 4'd8 ;//突发停止//状态跳转条件wireidle2pre ;wirepre2aref ;wirearef2regist ;wireregist2idle ;wirearef2idle ;wireidle2w_act ;wireidle2r_act ;wirew_act2write ;wirewrite2burst ;wirer_act2read ;wireread2burst ;wireburst2pre ;wirepre2idle ;//中间信号reg [3:0] state_c;//现态reg [3:0] state_n;//次态reg waite_done ;//200us上电等待结束reg [1:0] atref_time ;//自动刷新次数reg [13:0] cnt_init ;//上电初始化计数wireadd_cnt_init;wireend_cnt_init;reg [9:0] cnt_aref ;//自动刷新计数wireadd_cnt_aref;wireend_cnt_aref;reg [1:0] cnt_4clk ;//四周期时钟计数器wireadd_cnt_4clk;reg [2:0] cnt_7clk ;//7周期时钟计数器wireadd_cnt_7clk;reg [9:0] cnt_bit;//读写计数wireadd_cnt_bit ;wireend_cnt_bit ;wirerd_ack;//读响应赋值reg [2:0] r_ack_r;//读响应赋值打四拍reg wr;//写操作标志reg rd;//读操作标志reg aref_req ;//自动刷新请求reg ack_r1;//写响应打拍reg ack_r2;//读响应打拍reg [15:0] dq_r ;//sdram读数据打拍reg w_ack ;//写响应打拍reg w_en ;//写使能reg r_en ;//读使能// w_en:写使能always @(posedge clk or negedge rst_n)begin if(!rst_n)beginw_en <= 1'b0;end else if(w_req)begin w_en <= 1'b1;end else if(wr && pre2idle)begin w_en <= 1'b0;end end// r_en:读使能always @(posedge clk or negedge rst_n)begin if(!rst_n)beginr_en <= 1'b0;end else if(r_req)begin r_en <= 1'b1;end else if(rd && pre2idle)begin r_en <= 1'b0;end end// dq_r:sdram读数据打拍always @(posedge clk or negedge rst_n)begin if(!rst_n)begindq_r <= 16'b0;end else begin dq_r <= sdram_dq;end end// cnt_init:上电等待200us计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_init <= 14'b0;end else if(add_cnt_init)begin if(end_cnt_init)begin cnt_init <= 14'b0;endelse begin cnt_init <= cnt_init + 1'b1;end endend assign add_cnt_init = cnt_init <= `INIT_TIME;assign end_cnt_init = add_cnt_init && cnt_init == `INIT_TIME + 1'b1; // waite_done:上电等待200us结束标志always @(posedge clk or negedge rst_n)begin if(!rst_n)beginwaite_done <= 1'b0;end else if(cnt_init == `INIT_TIME - 1'b1)begin waite_done <= 1'b1;end else begin waite_done <= 1'b0;end end// cnt_aref:自动刷新7us计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_aref <= 10'b0;end else if(add_cnt_aref)begin if(end_cnt_aref)begin cnt_aref <= 10'b0;endelse begin cnt_aref <= cnt_aref + 1'b1;end endend assign add_cnt_aref = init_done;assign end_cnt_aref = add_cnt_aref && cnt_aref == `AREF_TIME - 1'b1;// cnt_4clk:四周期时钟计数器always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_4clk <= 2'b0;end else if(add_cnt_4clk)begin cnt_4clk <= cnt_4clk + 1'b1;endend assign add_cnt_4clk = (state_c == PRE) || (state_c == REGIST) || (state_c == W_ACT)|| (state_c == R_ACT) || (state_c == BURST);// cnt_7clk:七周期时钟计数器always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_7clk <= 3'b0;end else if(add_cnt_7clk)begin cnt_7clk <= cnt_7clk + 1'b1;endend assign add_cnt_7clk = (state_c == AREF);// atref_time:自动刷新次数always @(posedge clk or negedge rst_n)begin if(!rst_n)beginatref_time <= 2'b0;end else if(cnt_7clk == 3'd7)begin atref_time <= atref_time + 1'b1;end end// init_done:SDRAM初始化结束always @(posedge clk or negedge rst_n)begin if(!rst_n)begininit_done <= 1'b0;end else if(regist2idle)begin init_done <= 1'b1;end end// cnt_bit:读写计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_bit <= 10'b0;end else if(add_cnt_bit)begin if(end_cnt_bit)begin cnt_bit <= 10'b0;endelse begin cnt_bit <= cnt_bit + 1'b1;end endend assign add_cnt_bit = (state_c == WRITE) || (state_c == READ);assign end_cnt_bit = add_cnt_bit && (((state_c == WRITE) && (cnt_bit == `BURST_LEN - 1'b1)) || ((state_c == READ) && (cnt_bit == `BURST_LEN - 1'b1)));// 写操作标志always @(posedge clk or negedge rst_n)begin if(!rst_n)beginwr <= 1'b0;end else if(write2burst)begin wr <= 1'b1;end else if(pre2idle)begin wr <= 1'b0;end end// 读操作标志always @(posedge clk or negedge rst_n)begin if(!rst_n)beginrd <= 1'b0;end else if(read2burst)begin rd <= 1'b1;end else if(pre2idle)begin rd <= 1'b0;end end// aref_req:自动刷新请求always @(posedge clk or negedge rst_n)begin if(!rst_n)beginaref_req <= 1'b0;end else if(end_cnt_aref)begin aref_req <= 1'b1;end else if(aref2idle)begin aref_req <= 1'b0;end end// 状态转移always @(posedge clk or negedge rst_n)begin if(!rst_n)beginstate_c <= IDLE;end else begin state_c <= state_n;end end// 判断状态转移条件always @(*)begin case(state_c)IDLE :if(idle2pre)beginstate_n = PRE;endelse if(idle2w_act)beginstate_n = W_ACT;endelse if(idle2r_act)beginstate_n = R_ACT;endelse beginstate_n = state_c;endPRE:if(pre2idle)beginstate_n = IDLE;endelse if(pre2aref)beginstate_n = AREF;endelse beginstate_n = state_c;endAREF :if(aref2idle)beginstate_n = IDLE;endelse if(aref2regist)beginstate_n = REGIST;endelse beginstate_n = state_c;endREGIST :if(regist2idle)beginstate_n = IDLE;endelse beginstate_n = state_c;endW_ACT :if(w_act2write)beginstate_n = WRITE;endelse beginstate_n = state_c;endR_ACT :if(r_act2read)beginstate_n = READ;endelse beginstate_n = state_c;endWRITE :if(write2burst)beginstate_n = BURST;endelse beginstate_n = state_c;endREAD :if(read2burst)beginstate_n = BURST;endelse beginstate_n = state_c;endBURST :if(burst2pre)beginstate_n = PRE;endelse beginstate_n = state_c;enddefault:state_n = state_c;endcaseend// 状态转移条件赋值assign idle2pre = (state_c == IDLE ) && (waite_done || aref_req) ;//仲裁,进入自动刷新条件assign pre2aref = (state_c == PRE ) && (cnt_4clk == 2'd3) ;assign aref2regist = (state_c == AREF ) && (cnt_7clk == 3'd7) && (atref_time == 2'd3) ;assign regist2idle = (state_c == REGIST) && (cnt_4clk == 2'd3) ;assign aref2idle = (state_c == AREF ) && (cnt_7clk == 3'd7) && (atref_time == 2'd3) && init_done ;assign idle2w_act = (state_c == IDLE ) && !aref_req && w_en && init_done ;//仲裁,进入写操作条件assign idle2r_act = (state_c == IDLE ) && !aref_req && r_en && init_done ;//仲裁,进入读操作条件assign w_act2write = (state_c == W_ACT ) && (cnt_4clk == 2'd3) ;assign write2burst = (state_c == WRITE ) && end_cnt_bit ;assign r_act2read = (state_c == R_ACT ) && (cnt_4clk == 2'd3) ;assign read2burst = (state_c == READ ) && end_cnt_bit ;assign burst2pre = (state_c == BURST ) && (cnt_4clk == 2'd3) ;assign pre2idle = (state_c == PRE ) && (cnt_4clk == 2'd3) && (wr || rd) ;always @(*)begin if(!rst_n)begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;end else begin case (state_c)PRE: if(cnt_4clk == 1'b0)begincmd = `CMD_PRE;sdram_addr = 13'b001_0_00_000_0_000;//选中所有bank进行预充电sdram_ba = 2'b00;endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endAREF : if(cnt_7clk == 1'b0)begincmd = `CMD_AREF;sdram_addr = 13'b0;sdram_ba = 2'b0;endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endREGIST : if(cnt_4clk == 1'b0)begincmd = `CMD_MOD;sdram_addr = 13'b000_0_00_010_0_111;//配置模式寄存器sdram_ba = 2'b0;endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endW_ACT : if(cnt_4clk == 1'b0)begincmd = `CMD_ACT;sdram_addr = w_addr[21:9];sdram_ba = w_addr[23:22];endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endR_ACT : if(cnt_4clk == 1'b0)begincmd = `CMD_ACT;sdram_addr = r_addr[21:9];sdram_ba = r_addr[23:22];endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endWRITE : if(cnt_bit == 1'b0)begincmd = `CMD_WR;sdram_addr = {4'b0000, w_addr[8:0]};sdram_ba = w_addr[23:22];endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endREAD : if(cnt_bit == 1'b0)begincmd = `CMD_RD;sdram_addr = {4'b0000, r_addr[8:0]};sdram_ba = r_addr[23:22];endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endBURST : if(cnt_4clk == 1'b0)begincmd = `CMD_BR;sdram_addr = 13'b0;sdram_ba = 2'b0;endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;enddefault : begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endendcaseend end// wr_ack:写响应 assign wr_ack = (state_c == WRITE );// rd_ack:读响应assign rd_ack = (state_c == READ ); // r_ack_r:读响应打两拍always @(posedge clk or negedge rst_n)begin if(!rst_n)beginr_ack_r <= 3'b0;end else begin r_ack_r <= {r_ack_r[1:0], rd_ack};end end // r_ack:输出的读响应assign r_ack = r_ack_r[2];// w_ack:写响应打第一拍always @(posedge clk or negedge rst_n)begin if(!rst_n)beginw_ack <= 1'b0;end else begin w_ack <= wr_ack;end end // ack_r1:写响应打第二拍always @(posedge clk or negedge rst_n)begin if(!rst_n)beginack_r1 <= 1'b0;end else begin ack_r1 <= w_ack;end end// ack_r2:输出的读响应打拍always @(posedge clk or negedge rst_n)begin if(!rst_n)beginack_r2 <= 1'b0;end else begin ack_r2 <= r_ack;end end// 读写操作完成标志assign w_done = ack_r1 & ~w_ack;assign r_done = ack_r2 & ~r_ack;// 数据:sdram_dqassign sdram_dq = wr_ack?w_data:16'bz;// r_data:sdram读出数据assign r_data = r_ack?dq_r:16'd0;endmodule
5、乒乓缓存模块
/**************************************功能介绍***********************************Copyright:Date:Author :厉长川Version :.10.10 v1Description:数据缓存模块*********************************************************************************/`include "param.v"module data_cache( input clk ,//100MHz工作时钟input rst_n,//复位信号input w_done,//写完成input r_done,//读完成input init_done ,//sdram初始化结束input [15:0] r_data,//sdram数据接收fifo,输入数据input r_wrclk,//sdram数据接收fifo,写时钟input r_wrreq,//sdram数据接收fifo,写请求input [15:0] t_data,//sdram数据发送fifo,输入数据input t_rdclk,//sdram数据发送fifo,读时钟input t_rdreq,//sdram数据发送fifo,读请求 input w_ack ,//写响应input r_ack ,//读响应output[15:0] r_q,//sdram数据接收fifo,输出数据output reg [23:0] w_addr,//sdram写地址output reg [23:0] r_addr,//sdram读地址output[15:0] t_q,//sdram数据发送fifo,输出数据output reg sdram_rdreq ,//sdram数据接收fifo,读请求output reg sdram_wrreq //sdram数据发送fifo,写请求); //中间信号定义wire [9:0]r_rdusedw ;//sdram数据接收fifo,读数据计数wire [9:0]t_wrusedw ;//sdram数据发送fifo,写数据计数reg bank_flag ;//bank切换标志reg bank_en;//bank切换使能// bank_flag、bank_en、w_addr:bank切换标志、bank切换使能和写地址always @(posedge clk or negedge rst_n)begin if(!rst_n)beginbank_en <= 1'b0;bank_flag <= 1'b0;w_addr <= 24'b0;end else if(w_done)begin if(w_addr[22:0] >= `ADDR_END)beginbank_en <= 1'b1;bank_flag <= ~bank_flag;endelse beginw_addr <= w_addr + `BURST_LEN;endend else if(bank_en)beginbank_en <= 1'b0;if(bank_flag)beginw_addr <= {1'b1, 23'b0};endelse beginw_addr <= {1'b0, 23'b0};endendend//r_addr:读地址always @(posedge clk or negedge rst_n)begin if(!rst_n)beginr_addr <= 24'b0;end else if(r_done)begin if(r_addr[22:0] >= `ADDR_END)beginif(!bank_flag)beginr_addr <= {1'b1, 23'b0};endelse beginr_addr <= {1'b0, 23'b0};endendelse beginr_addr <= r_addr + `BURST_LEN;endend end//sdram_rdreq、sdram_wrreq:sdram读写请求always @(posedge clk or negedge rst_n)begin if(!rst_n)beginsdram_rdreq <= 1'b0;sdram_wrreq <= 1'b0;end else if(init_done)begin if(r_rdusedw >= `BURST_LEN)beginsdram_rdreq <= 1'b0;sdram_wrreq <= 1'b1;endelse if(t_wrusedw < `BURST_LEN)beginsdram_rdreq <= 1'b1;sdram_wrreq <= 1'b0;endelse beginsdram_rdreq <= 1'b0;sdram_wrreq <= 1'b0;endend else begin sdram_rdreq <= 1'b0;sdram_wrreq <= 1'b0;end endfifo_r u_fifo_r(.aclr ( ~rst_n ),.data (r_data ),.rdclk (clk ),//sdram数据接收fifo,读时钟.rdreq (w_ack),.wrclk (r_wrclk ),//sdram数据接收fifo,写时钟.wrreq (r_wrreq ),.q (r_q ),.rdusedw (r_rdusedw ));fifo_t u_fifo_t(.aclr ( ~rst_n ),.data (t_data ),.rdclk (t_rdclk ),//sdram数据发送fifo,读时钟.rdreq (t_rdreq ),.wrclk (clk ),//sdram数据发送fifo,写时钟.wrreq (r_ack),.q (t_q ),.wrusedw (t_wrusedw ));endmodule
6、VGA驱动模块
/**************************************功能介绍***********************************Copyright:Date:Author :厉长川Version :.10.10 v1Description:VGA驱动模块1024*768*********************************************************************************/`include "param.v"module vga( inputclk ,//65Mhzinputrst_n ,//复位信号input[15:0]din ,//vga输入数据output vga_out_hs ,//行同步output vga_out_vs,//场同步output[15:0]vga_dout,//rgb像素数据output data_req//像素数据请求信号);//中间信号定义wiredata_valid ;//输入像素有效标志 reg [10:0]cnt_h ;//行同步计数器wire add_cnt_h ;wire end_cnt_h ;reg [10:0]cnt_v ;//场同步计数器wire add_cnt_v ;wire end_cnt_v ;//cnt_h:行同步计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_h <= 11'b0;end else if(add_cnt_h)begin if(end_cnt_h)begin cnt_h <= 11'b0;endelse begin cnt_h <= cnt_h + 1'b1;end endend assign add_cnt_h = 1'b1;assign end_cnt_h = add_cnt_h && cnt_h == `H_TO - 1'b1;//cnt_v:场同步计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_v <= 11'b0;end else if(add_cnt_v)begin if(end_cnt_v)begin cnt_v <= 11'b0;endelse begin cnt_v <= cnt_v + 1'b1;end endend assign add_cnt_v = end_cnt_h;assign end_cnt_v = add_cnt_v && cnt_v == `V_TO - 1'b1;//vga_out_hs:行同步assign vga_out_hs = (cnt_h <= `H_SYNC - 1'b1) ;//vga_out_vs:场同步assign vga_out_vs = (cnt_v <= `V_SYNC - 1'b1) ;//data_req:像素数据请求信号 assign data_req = (`H_SYNC + `H_BP - 2'd2 < cnt_h) && (cnt_h <= `H_SYNC + `H_BP + `H_ACTIVE - 2'd2) &&(`V_SYNC + `V_BP < cnt_v) && (cnt_v <= `V_SYNC + `V_BP + `V_ACTIVE);//data_validassign data_valid = (`H_SYNC + `H_BP < cnt_h) && (cnt_h <= `H_SYNC + `H_BP + `H_ACTIVE) &&(`V_SYNC + `V_BP < cnt_v) && (cnt_v <= `V_SYNC + `V_BP + `V_ACTIVE);//vga_dout:rgb像素数据assign vga_dout = data_valid ? din : 16'b0;endmodule
7、顶层模块
/**************************************功能介绍***********************************Copyright:Date:Author :厉长川Version :.10.10 v1Description:顶层模块*********************************************************************************/module img_pro( inputclk ,//系统时钟50Mhzinputrst_n ,//复位信号,低电平有效input [7:0] cmos_db,//摄像头采集数据inputcmos_pclk ,//摄像头pclk时钟48MHzinputcmos_vsync ,//摄像头场同步信号inputcmos_href ,//摄像头行有效信号output cmos_rst_n ,//摄像头复位信号output cmos_xclk ,//摄像头xclk时钟24Mhzoutput cmos_pwdn ,//摄像头掉电使能信号output cmos_scl,//摄像头配置时钟信号inout cmos_sda,//摄像头配置数据信号output sdram_clk ,//sdram工作时钟output sdram_cke ,//sdram使能output [12:0]sdram_addr ,//sdram地址总线output [1:0] sdram_ba ,//sdram bank地址inout [15:0]sdram_dq ,//sdram数据总线output [1:0] sdram_dqm ,//数据掩码output [3:0] cmd ,//sdram操作命令output vga_out_hs ,//vga行同步信号output vga_out_vs ,//vga场同步信号output [15:0]vga_dout//vga输出的RGB数据); //中间信号定义 wirevga_clk;//vga时钟wireclk_100MHz ;//100MHz工作时钟wiredone ;//摄像头配置完成标志wire [15:0]pixel_dout ;//采集的像素数据wiredout_valid ;//采集数据有效标志wire [15:0]w_data;//sdram写入数据wire [15:0]r_data;//sdram读出数据wire [15:0]vga_din;//vga输入数据wiredata_req ;//vga数据请求wire [23:0]w_addr;//sdram写地址wire [23:0]r_addr;//sdram读地址wiresdram_rdreq ;//sdram数据接收fifo,读请求wiresdram_wrreq ;//sdram数据发送fifo,写请求wirer_ack ;//读响应wirewr_ack;//写响应wirelocked_1 ;//pll_1输出稳定标志wirelocked_2 ;//pll_2输出稳定标志wirereset ;//sccb、data_cache、sdram和vga模块复位信号wireinit_done ;//sdram初始化结束wirepixel_rst ;//pixel_sampling模块复位信号wirew_done;//写完成标志wirer_done;//读完成标志//sdram_cke:sdram使能assign sdram_cke = 1'b1;//sdram_dqm:数据掩码assign sdram_dqm = 2'b00;//reset:sccb、data_cache、sdram和vga模块复位信号assign reset = locked_1 & locked_2 & rst_n;//pixel_rst:pixel_sampling模块复位信号assign pixel_rst = done & init_done & reset;sccb u_sccb(.clk(clk ),.rst_n (reset ),.done (done),.cmos_rst_n (cmos_rst_n ),.cmos_pwdn (cmos_pwdn),.cmos_scl(cmos_scl),.cmos_sda(cmos_sda));pixel_sampling u_pixel_sampling(.clk(cmos_pclk),//摄像头pclk时钟48MHz.rst_n (pixel_rst),//pixel_sampling模块复位信号.din(cmos_db ),//摄像头采集数据.vsync (cmos_vsync ),//摄像头场同步信号.href (cmos_href),//摄像头行有效信号.dout_valid (dout_valid ),//输出数据有效标志.dout (pixel_dout ) //输出拼接完成的像素);data_cache u_data_cache(.clk(clk_100MHz ),.rst_n (reset ),.w_done (w_done ),.r_done (r_done ),.init_done (init_done),.r_data (pixel_dout ),.r_wrclk(cmos_pclk),.r_wrreq(dout_valid ),.t_data (r_data ),.t_rdclk(vga_clk ),.t_rdreq(data_req),.w_ack (wr_ack ),.r_ack (r_ack ),.r_q(w_data ),.w_addr (w_addr ),.r_addr (r_addr ),.t_q(vga_din ),.sdram_rdreq (sdram_rdreq ),//sdram数据接收fifo,读请求.sdram_wrreq (sdram_wrreq ) //sdram数据发送fifo,写请求);sdram u_sdram(.clk(clk_100MHz ),.rst_n (reset ),.w_req (sdram_wrreq ),.r_req (sdram_rdreq ),.w_addr (w_addr ),.r_addr (r_addr ),.w_data (w_data ),.r_data (r_data ),.sdram_addr (sdram_addr ),.sdram_ba(sdram_ba),.sdram_dq(sdram_dq),.cmd(cmd ),.init_done (init_done),.r_ack (r_ack ),.wr_ack (wr_ack ),.w_done (w_done ),//写操作完成标志.r_done (r_done ) //读操作完成标志);vga u_vga(.clk(vga_clk ),.rst_n (reset ),.din(vga_din ),.vga_out_hs (vga_out_hs ),.vga_out_vs (vga_out_vs ),.vga_dout(vga_dout),.data_req(data_req));pll_1pll_1_inst (.areset (~rst_n ),.inclk0 (clk ),//50MHz.c0 (vga_clk ),//65MHz.c1 (clk_100MHz ),//100MHz.c2 (sdram_clk),//100MHz,-75deg.locked (locked_1));pll_2pll_2_inst (.areset (~rst_n ),.inclk0 (clk ),//50MHz系统时钟.c0 (cmos_xclk),//24Mhz.locked (locked_2));endmodule
8、参数定义
仿真时可以修改参数节省仿真时间
/**************************************功能介绍***********************************Copyright:Date:Author :厉长川Version :.10.10 v1Description:参数定义*********************************************************************************///sccb参数定义`defineCNT_1M6'd50//1M时钟计数`defineCNT_MS21'd1315000 //26.3ms时间计数`definePWDN 18'd255000//5.1ms计时`defineRST_CMOS 19'd310000//1.1ms复位等待时间`defineNUM_CFG8'd248 //寄存器配置个数//pixel_sampling参数定义`definePIXEL 4'd10//舍弃帧数//vga接口参数// 1024*768 65Mhz`defineH_ACTIVE 11'd1024 //行有效 `defineH_FP 11'd24 //行前沿 `defineH_SYNC11'd136 //行同步`defineH_BP 11'd160 //行后沿 `defineH_TO 11'd1344 //行周期`defineV_ACTIVE 11'd768 //场有效 `defineV_FP 11'd3//场前沿 `defineV_SYNC11'd6//场同步 `defineV_BP 11'd29 //场后沿 `defineV_TO 11'd806 //场周期 //sdram模块参数`defineCMD_NOOP 4'b0111 //空指令`defineCMD_ACT4'b0011 //行激活指令`defineCMD_RD4'b0101 //读指令`defineCMD_WR4'b0100 //写指令`defineCMD_BR4'b0110 //突发终止指令`defineCMD_PRE 4'b0010 //预充电指令`defineCMD_AREF4'b0001 //自动刷新指令`defineCMD_MOD4'b0000 //模式寄存器配置命令`defineINIT_TIME 14'd10000 //上电等待时间,10000个时钟周期(100us)`defineAREF_TIME 10'd700 //自动刷新间隔时间,700个时钟周期(7us)`defineBURST_LEN 10'd512 //读写突发长度`defineADDR_END `H_ACTIVE * `V_ACTIVE - `BURST_LEN//读写地址末地址
9、最终效果
①:分析综合
②:上板验证
如果觉得《一 FPGA Cyclone Ⅳ OV5640图像实时采集系统设计》对你有帮助,请点赞、收藏,并留下你的观点哦!