首页 > 代码库 > FPGA设计——CMOS摄像与显示(DVP)
FPGA设计——CMOS摄像与显示(DVP)
1. 概述
本设计采用FPGA技术,将CMOS摄像头的视频数据经过采集、存储、处理、帧率转换,最终通过HDMI接口显示在电视屏幕上。
2. 硬件系统框图
CMOS采用smartsens的分辨率为1080p的摄像头芯片SC2035,FPGA采用ALTERA公司的CYCLONE IV,FLASH采用EPCS64,DDR2采用Hynix公司的1Gb内存条,HDMI采用Silicon Image公司的SiI9134。
3. FPGA逻辑框图
FPGA各部分逻辑模块如下图所示:
CMOS Capture,采集CMOS摄像头视频数据;
I2C Master,配置CMOS芯片;
DDR2 Control,配置与控制DDR2芯片组,实现读写仲裁;
FIFO Write,将采集到的视频数据跨时钟域地写进DDR2中;
FIFO Read,将DDR2中的数据跨时钟域地读出给后续图像处理模块;
Frame Buffer,负责FIFO Write和FIFO Read的调度,实现帧率转换;
RAW to RGB,将原始RAW8数据转换成RGB888数据;
RGB to YCbCr,将RGB888数据转换成YCbCr444数据;
YC444 to YC422,将YC444的数据转换成YC422的数据给HDMI TX模块;
HDMI TX,将处理好的视频数据发送给HDMI PHY芯片,同时通过I2C接口配置HDMI PHY芯片。
4. FPGA逻辑代码
//file name: top_fpga.v //author: shugen.yin //date: 2016.9.28 //function: top file of project //log: module top_fpga ( //global signal clk, rst_n, //cmos1 port cmos_pclk_1, cmos_hsync_1, cmos_vsync_1, cmos_data_1, cmos_mclk_1, i2c_sclk_1, i2c_sdat_1, //hdmi port hdmi_clk, hdmi_txde, hdmi_hs, hdmi_vs, hdmi_data, hdmi_scl, hdmi_sda, //ddr2 port mem_odt, mem_cs_n, mem_cke, mem_addr, mem_ba, mem_ras_n, mem_cas_n, mem_we_n, mem_dm, mem_clk, mem_clk_n, mem_dq, mem_dqs, led ); input clk; input rst_n; //cmos1 port input cmos_pclk_1; input cmos_hsync_1; input cmos_vsync_1; input [23:0] cmos_data_1; output cmos_mclk_1; inout i2c_sclk_1; inout i2c_sdat_1; //hdmi output hdmi_clk; output hdmi_txde; output hdmi_hs; output hdmi_vs; output [15:0] hdmi_data; output hdmi_scl; inout hdmi_sda; //ddr2 output [1:0] mem_odt; output [1:0] mem_cs_n; output [1:0] mem_cke; output [13:0] mem_addr; output [2:0] mem_ba; output mem_ras_n; output mem_cas_n; output mem_we_n; output [7:0] mem_dm; inout [1:0] mem_clk; inout [1:0] mem_clk_n; inout [63:0] mem_dq; inout [7:0] mem_dqs; output led; //global define //`define TEST_MODE `define VGA_1080P `define DDR2_EN parameter IMG_HDISP = 16‘d1920; parameter IMG_VDISP = 16‘d1080; //----------------PLL------------------ wire locked_01; wire clk_25m; wire clk_74m; alt_pll_01 alt_pll_01_inst ( .inclk0(clk) , // input inclk0_sig .c0(clk_25m) , // output c0_sig .c1(clk_74m), .locked(locked_01) // output locked_sig ); assign cmos_mclk_1 = clk_25m; //----------Soft reset----------------- reg [15:0] cnt_rst; reg soft_rst_n; reg soft_rstn_short; always @(posedge clk) if(~rst_n) cnt_rst <= 0; else if(cnt_rst>=‘h3ff) cnt_rst<= cnt_rst; else cnt_rst <= cnt_rst + 1‘b1; always @(posedge clk) if(cnt_rst<‘h155) soft_rst_n <= 1‘b0; else soft_rst_n <= 1‘b1; always @(posedge clk) if(cnt_rst<‘h10) soft_rstn_short <= 1‘b0; else soft_rstn_short <= 1‘b1; //-------CMOS1 I2C init---------- wire i2c1_init_done; wire i2c1_scl; wire i2c1_sda; i2c_port i2c_port_inst1 ( .clk(clk) , // input clk_sig .rst_n(1‘b1) , // input rst_n_sig .i2c_scl(i2c1_scl) , // output i2c_scl_sig .i2c_sda(i2c1_sda) , // inout i2c_sda_sig .i2c_init_done(i2c1_init_done) ); assign i2c_sclk_1 = (~i2c1_init_done)?i2c1_scl:1‘bz; assign i2c_sdat_1 = (~i2c1_init_done)?i2c1_sda:1‘bz; //------------cmos1 signal buffer---------------- (* noprune *)reg [13:0] cmos1_hcnt; (* noprune *)reg [11:0] cmos1_vcnt; reg cmos_vsync_1_buf0; reg cmos_vsync_1_buf1; always @(posedge cmos_pclk_1) begin cmos_vsync_1_buf0 <= cmos_vsync_1; cmos_vsync_1_buf1 <= cmos_vsync_1_buf0; end wire cmos_vsync_1_pos; assign cmos_vsync_1_pos = (cmos_vsync_1_buf0==1 & cmos_vsync_1_buf1==0); reg [7:0] cmos_data_1_r; reg cmos_hsync_1_buf0; reg cmos_hsync_1_buf1; always @(posedge cmos_pclk_1) begin cmos_hsync_1_buf0 <= cmos_hsync_1; cmos_hsync_1_buf1 <= cmos_hsync_1_buf0; end reg [7:0] cmos_data_1_buf0; reg [7:0] cmos_data_1_buf1; always @(posedge cmos_pclk_1) begin cmos_data_1_buf0 <= cmos_data_1[7:0]; cmos_data_1_buf1 <= cmos_data_1_buf0; end wire cmos_hsync_1_pos; assign cmos_hsync_1_pos = (cmos_hsync_1_buf0==1‘b1 & cmos_hsync_1_buf1==1‘b0); always @(posedge cmos_pclk_1) if(cmos_vsync_1_pos | cmos_hsync_1_pos) cmos1_hcnt <= 0; else if(cmos1_hcnt<=(IMG_HDISP) & cmos_hsync_1_buf0) cmos1_hcnt <= cmos1_hcnt + 1‘b1; else cmos1_hcnt <= cmos1_hcnt; always @(posedge cmos_pclk_1) if(cmos_vsync_1_pos) cmos1_vcnt <= 0; else if(cmos_hsync_1_pos) cmos1_vcnt <= cmos1_vcnt + 1‘b1; else cmos1_vcnt <= cmos1_vcnt; reg cmos_hsync_1_buf; reg [7:0] cmos_data_1_buf; always @(posedge cmos_pclk_1) if(cmos1_hcnt>=1 & cmos1_hcnt<=(IMG_HDISP) & cmos1_vcnt>=1 & cmos1_vcnt<=(IMG_VDISP)) begin cmos_hsync_1_buf <= 1‘b1; cmos_data_1_buf <= cmos_data_1_buf1; end else begin cmos_hsync_1_buf <= 1‘b0; cmos_data_1_buf <= 0; end //cmos processed signal wire [7:0] cmos_data_processed; wire cmos_vsync_processed; wire cmos_href_processed; assign cmos_data_processed = cmos_data_1_buf1; assign cmos_vsync_processed = cmos_vsync_1_buf1; assign cmos_href_processed = cmos_hsync_1_buf1;//cmos_hsync_0_buf; //------------Video Test--------------- `ifdef VGA_1080P wire pclk1; assign pclk1 = cmos_pclk_1; wire pclk2; assign pclk2 = clk_74m; `endif `ifdef TEST_MODE //VIDEO input reg [15:0] vcnt; reg [11:0] hcnt; reg vsync; reg hsync; reg [7:0] data; reg data_valid; `ifdef VGA_1080P always @(posedge pclk1) if(~soft_rst_n) hcnt <= IMG_HDISP; else if(hcnt>=(IMG_HDISP+279)) hcnt <= 0; else hcnt <= hcnt + 1‘b1; always @(posedge pclk1) if(~soft_rst_n) vcnt <= IMG_VDISP; else if(hcnt>=(IMG_HDISP+279)) if(vcnt>=(IMG_VDISP+44)) vcnt <= 0; else vcnt <= vcnt + 1‘b1; else vcnt <= vcnt; always @(posedge pclk1) if((hcnt>=IMG_HDISP+88) & (hcnt<(IMG_HDISP+132)))// & (vcnt>=0) & (vcnt<(IMG_VDISP))) hsync <= 1‘b1; else hsync <= 1‘b0; always @(posedge pclk1) if(vcnt>=(IMG_VDISP+4) & vcnt<(IMG_VDISP+10)) vsync <= 1‘b1; else vsync <= 1‘b0; `endif always @(*) if((hcnt>=0) & (hcnt<(IMG_HDISP)) & (vcnt>=0) & (vcnt<(IMG_VDISP))) data_valid <= 1‘b1; else data_valid <= 1‘b0; always @(posedge pclk1) if((hcnt>=0) & (hcnt<(IMG_HDISP)) & (vcnt>=0) & (vcnt<(IMG_VDISP/4))) if(hcnt>=0 & hcnt<(IMG_HDISP/4)) data <= 8‘h00; else if(hcnt>=(IMG_HDISP/4) & hcnt<(2*IMG_HDISP/4)) data <= 8‘he0; else if(hcnt>=(2*IMG_HDISP/4) & hcnt<(3*IMG_HDISP/4)) data <= 8‘h00; else data <= 8‘he0; else if((hcnt>=0) & (hcnt<(IMG_HDISP)) & (vcnt>=(IMG_VDISP/4)) & (vcnt<(2*IMG_VDISP/4))) if(hcnt>=0 & hcnt<(IMG_HDISP/4)) data <= 8‘he0; else if(hcnt>=(IMG_HDISP/4) & hcnt<(2*IMG_HDISP/4)) data <= 8‘h00; else if(hcnt>=(2*IMG_HDISP/4) & hcnt<(3*IMG_HDISP/4)) data <= 8‘he0; else data <= 8‘h00; else if((hcnt>=0) & (hcnt<(IMG_HDISP)) & (vcnt>=(2*IMG_VDISP/4)) & (vcnt<(3*IMG_VDISP/4))) if(hcnt>=0 & hcnt<(IMG_HDISP/4)) data <= 8‘h00; else if(hcnt>=(IMG_HDISP/4) & hcnt<(2*IMG_HDISP/4)) data <= 8‘he0; else if(hcnt>=(2*IMG_HDISP/4) & hcnt<(3*IMG_HDISP/4)) data <= 8‘h00; else data <= 8‘he0; else if((hcnt>=0) & (hcnt<(IMG_HDISP)) & (vcnt>=(3*IMG_VDISP/4)) & (vcnt<(IMG_VDISP))) if(hcnt>=0 & hcnt<(IMG_HDISP/4)) data <= 8‘he0; else if(hcnt>=(IMG_HDISP/4) & hcnt<(2*IMG_HDISP/4)) data <= 8‘h00; else if(hcnt>=(2*IMG_HDISP/4) & hcnt<(3*IMG_HDISP/4)) data <= 8‘he0; else data <= 8‘h00; else data <= 0; `endif //VIDEO output reg [15:0] vcnt_1; reg [11:0] hcnt_1; reg vsync_1; reg hsync_1; reg [7:0] data_1; reg data_valid_1; reg vsync_o; reg hsync_o; reg data_valid_o; `ifdef VGA_1080P always @(posedge pclk2) if(~soft_rst_n) hcnt_1 <= IMG_HDISP; else if(hcnt_1>=(IMG_HDISP+279)) hcnt_1 <= 0; else hcnt_1 <= hcnt_1 + 1‘b1; always @(posedge pclk2) if(~soft_rst_n) vcnt_1 <= IMG_VDISP; else if(hcnt_1>=(IMG_HDISP+279)) if(vcnt_1>=(IMG_VDISP+44)) vcnt_1 <= 0; else vcnt_1 <= vcnt_1 + 1‘b1; else vcnt_1 <= vcnt_1; always @(posedge pclk2) if((hcnt_1>=IMG_HDISP+88) & (hcnt_1<(IMG_HDISP+132)))// & (vcnt>=0) & (vcnt<(IMG_VDISP))) hsync_1 <= 1‘b1; else hsync_1 <= 1‘b0; always @(posedge pclk2) if(vcnt_1>=(IMG_VDISP+4) & vcnt_1<(IMG_VDISP+10)) vsync_1 <= 1‘b1; else vsync_1 <= 1‘b0; always @(posedge pclk2) if((hcnt_1>=IMG_HDISP+88) & (hcnt_1<(IMG_HDISP+132))) hsync_o <= 1‘b1; else hsync_o <= 1‘b0; always @(posedge pclk2) if(vcnt_1>=(IMG_VDISP+4) & vcnt_1<(IMG_VDISP+10)) vsync_o <= 1‘b1; else vsync_o <= 1‘b0; always @(*) if((hcnt_1>=0) & (hcnt_1<(IMG_HDISP)) & (vcnt_1>=0) & (vcnt_1<(IMG_VDISP+0))) data_valid_o <= 1‘b1; else data_valid_o <= 1‘b0; `endif always @(*) if((hcnt_1>=0) & (hcnt_1<(IMG_HDISP+0)) & (vcnt_1>=0) & (vcnt_1<(IMG_VDISP+0))) data_valid_1 <= 1‘b1; else data_valid_1 <= 1‘b0; //-------------ddr2 control------------ wire [7:0] rd1_q; wire phy_clk; wire [31:0] rd1_start_address; wire [31:0] wr1_start_address; wire [31:0] rd1_end_address; wire [31:0] wr1_end_address; `ifdef DDR2_EN ddr2_control ddr2_control_inst ( .ref_clk(clk_25m) , // input ref_clk_sig .rst_n(soft_rst_n) , // input rst_n_sig `ifdef TEST_MODE .cmos_vsync1(vsync), .dvp_vsync1(vsync_1) , .phy_clk(phy_clk), .wr1_data(data) , // input [7:0] wr1_data_sig .wr1_wrreq(data_valid) , // input wr1_wrreq_sig .wr1_clk(pclk1) , // input wr1_clk_sig // .wr1_aclr(wr1_aclr_sig) , // input wr1_aclr_sig .wr1_start_addr(wr1_start_address) , // input [25:0] wr1_start_addr_sig `ifdef VGA_1080P .wr1_end_addr(wr1_end_address) , `endif `else .cmos_vsync1(cmos_vsync_processed) , // input cmos_vsync1_sig .dvp_vsync1(vsync_1) , .phy_clk(phy_clk), .wr1_data(cmos_data_processed) , // input [7:0] wr1_data_sig .wr1_wrreq(cmos_href_processed) , // input wr1_wrreq_sig .wr1_clk(cmos_pclk_1) , // input wr1_clk_sig // .wr1_aclr(wr1_aclr_sig) , // input wr1_aclr_sig .wr1_start_addr(wr1_start_address) , // input [25:0] wr1_start_addr_sig .wr1_end_addr(wr1_end_address) , // input [25:0] wr1_end_addr_sig `endif .rd1_q(rd1_q) , // output [7:0] rd1_q_sig .rd1_clk(pclk2) , // input rd1_clk_sig .rd1_rdreq(data_valid_1) , // input rd1_rdreq_sig // .rd1_aclr(rd1_aclr_sig) , // input rd1_aclr_sig .rd1_start_addr(rd1_start_address) , // input [25:0] rd1_start_addr_sig .rd1_end_addr(rd1_end_address) , // input [25:0] rd1_end_addr_sig .mem_odt(mem_odt) , // output [1:0] mem_odt_sig .mem_cs_n(mem_cs_n) , // output [1:0] mem_cs_n_sig .mem_cke(mem_cke) , // output [1:0] mem_cke_sig .mem_addr(mem_addr) , // output [13:0] mem_addr_sig .mem_ba(mem_ba) , // output [2:0] mem_ba_sig .mem_ras_n(mem_ras_n) , // output mem_ras_n_sig .mem_cas_n(mem_cas_n) , // output mem_cas_n_sig .mem_we_n(mem_we_n) , // output mem_we_n_sig .mem_dm(mem_dm) , // output [7:0] mem_dm_sig .mem_clk(mem_clk) , // inout [1:0] mem_clk_sig .mem_clk_n(mem_clk_n) , // inout [1:0] mem_clk_n_sig .mem_dq(mem_dq) , // inout [63:0] mem_dq_sig .mem_dqs(mem_dqs) // inout [7:0] mem_dqs_sig ); frame_control frame_control_inst ( .clk(phy_clk) , // input clk_sig .rst_n(soft_rstn_short) , // input rst_n_sig .frame1_vsync(cmos_vsync_processed) , // input wr_done_sig .frame2_vsync(vsync_1) , // input rd_done_sig .rd_start_address(rd1_start_address) , // output [31:0] rd_start_address_sig .wr_start_address(wr1_start_address), // output [31:0] wr_start_address_sig .rd_end_address(rd1_end_address), .wr_end_address(wr1_end_address) ); `endif //-----------HDMI---------------- hdmi_vid_gen hdmi_vid_gen_inst ( .pclk(clk_74m) , // input pclk_sig .rst_n(soft_rstn_short), .vsync(vsync_o) , // input vsync_sig .hsync(hsync_o) , // input hsync_sig .hcnt(hcnt_1), .vcnt(vcnt_1), .datain_valid(data_valid_o) , // input datain_valid_sig .datain(rd1_q) , // input [7:0] datain_sig .hdmi_clk(hdmi_clk) , // output hdmi_clk_sig .hdmi_txde(hdmi_txde) , // output hdmi_txde_sig .hdmi_hs(hdmi_hs) , // output hdmi_hs_sig .hdmi_vs(hdmi_vs) , // output hdmi_vs_sig .hdmi_data(hdmi_data) // output [15:0] hdmi_data_sig ); //-------HDMI i2c Init----------- wire hdmi_init_done; wire hdmi_scl_r; wire hdmi_sda_r; hdmi_i2c_port hdmi_i2c_port_inst ( .clk(clk) , // input clk_sig .rst_n(soft_rstn_short) , // input rst_n_sig .i2c_scl(hdmi_scl_r) , // output i2c_scl_sig .i2c_sda(hdmi_sda_r) , // inout i2c_sda_sig .i2c_init_done(hdmi_init_done) ); assign hdmi_scl = (~hdmi_init_done)?hdmi_scl_r:1‘bz; assign hdmi_sda = (~hdmi_init_done)?hdmi_sda_r:1‘bz; endmodule
5. CMOS配置
Smartsens的SC2035支持最高1080p30帧的输出,参考寄存器配置如下:
module i2c_cfg_par( input clk, input [07:0] lut_index, output reg [23:0] lut_data ); //`define SC1035 `define SC2035 //`define SC3035_M //`define SC3035_D //`define SC5035 always @(*) begin case(lut_index) `ifdef SC2035 //sc2035 setting //27M input 67.5M output ‘d0 : lut_data <= ‘h3105_02; ‘d1 : lut_data <= ‘h0103_01; ‘d2 : lut_data <= ‘h3105_02; ‘d3 : lut_data <= ‘h0100_00; ‘d4 : lut_data <= ‘h301e_b0; ‘d5 : lut_data <= ‘h320c_03; ‘d6 : lut_data <= ‘h320d_e8; ‘d7 : lut_data <= ‘h3231_24; ‘d8 : lut_data <= ‘h320E_04; ‘d9 : lut_data <= ‘h320F_65; ‘d10 : lut_data <= ‘h3211_08; //x start ‘d11 : lut_data <= ‘h3213_10; //y start ‘d12 : lut_data <= ‘h3e03_01; ‘d13 : lut_data <= ‘h3e01_46; ‘d14 : lut_data <= ‘h3e08_00; ‘d15 : lut_data <= ‘h3e09_10; ‘d16 : lut_data <= ‘h3518_03; ‘d17 : lut_data <= ‘h3518_03; ‘d18 : lut_data <= ‘h5025_09; ‘d19 : lut_data <= ‘h3908_c0; ‘d20 : lut_data <= ‘h3416_10; ‘d21 : lut_data <= ‘h3e0f_90; ‘d22 : lut_data <= ‘h3638_85; ‘d23 : lut_data <= ‘h3637_bf; ‘d24 : lut_data <= ‘h3639_98; ‘d25 : lut_data <= ‘h3035_01; ‘d26 : lut_data <= ‘h3034_ba; ‘d27 : lut_data <= ‘h3300_10; ‘d28 : lut_data <= ‘h3301_18; ‘d29 : lut_data <= ‘h3308_38; ‘d30 : lut_data <= ‘h3306_34; ‘d31 : lut_data <= ‘h330a_00; ‘d32 : lut_data <= ‘h330b_90; ‘d33 : lut_data <= ‘h3303_18; ‘d34 : lut_data <= ‘h3309_18; ‘d35 : lut_data <= ‘h331e_0e; ‘d36 : lut_data <= ‘h331f_0e; ‘d37 : lut_data <= ‘h3320_14; ‘d38 : lut_data <= ‘h3321_14; ‘d39 : lut_data <= ‘h3322_14; ‘d40 : lut_data <= ‘h3323_14; ‘d41 : lut_data <= ‘h3626_03; ‘d42 : lut_data <= ‘h3621_28; ‘d43 : lut_data <= ‘h3f08_04; ‘d44 : lut_data <= ‘h3f09_44; ‘d45 : lut_data <= ‘h4500_25; ‘d46 : lut_data <= ‘h3c09_08; ‘d47 : lut_data <= ‘h335d_20; ‘d48 : lut_data <= ‘h3368_02; ‘d49 : lut_data <= ‘h3369_00; ‘d50 : lut_data <= ‘h336a_04; ‘d51 : lut_data <= ‘h336b_65; ‘d52 : lut_data <= ‘h330e_50; ‘d53 : lut_data <= ‘h3367_08; ‘d54 : lut_data <= ‘h3f00_06; ‘d55 : lut_data <= ‘h3f04_01; ‘d56 : lut_data <= ‘h3f05_c8; ‘d57 : lut_data <= ‘h3905_1c; ‘d58 : lut_data <= ‘h5780_7f; ‘d59 : lut_data <= ‘h5782_0a; ‘d60 : lut_data <= ‘h5783_08; ‘d61 : lut_data <= ‘h5786_20; ‘d62 : lut_data <= ‘h5787_0c; ‘d63 : lut_data <= ‘h5789_01; ‘d64 : lut_data <= ‘h578a_0f; ‘d65 : lut_data <= ‘h5000_06; ‘d66 : lut_data <= ‘h3632_48; ‘d67 : lut_data <= ‘h3622_0e; ‘d68 : lut_data <= ‘h3627_02; ‘d69 : lut_data <= ‘h3630_b4; ‘d70 : lut_data <= ‘h3633_94; ‘d71 : lut_data <= ‘h3620_42; ‘d72 : lut_data <= ‘h363a_0c; ‘d73 : lut_data <= ‘h3334_60; ‘d74 : lut_data <= ‘h303f_81; ‘d75 : lut_data <= ‘h501f_00; ‘d76 : lut_data <= ‘h3b00_f8; ‘d77 : lut_data <= ‘h3b01_40; ‘d78 : lut_data <= ‘h3c01_14; ‘d79 : lut_data <= ‘h4000_00; ‘d80 : lut_data <= ‘h3d08_00;//‘h3d08_01; ‘d81 : lut_data <= ‘h3640_00; ‘d82 : lut_data <= ‘h0100_01; ‘d83 : lut_data <= ‘h303a_09; ‘d84 : lut_data <= ‘h3039_66; ‘d85 : lut_data <= ‘h303f_82; ‘d86 : lut_data <= ‘h3636_88; ‘d87 : lut_data <= ‘h3631_90; ‘d88 : lut_data <= ‘h3635_08; ‘d89 : lut_data <= ‘h3105_04; ‘d90 : lut_data <= ‘h3105_04; `endif default : lut_data <= ‘h0000; endcase end endmodule
6. 显示结果
电视显示1080p30的视频信号,图像中的色卡表明颜色显示正常。
本文出自 “shugenyin的博客” 博客,请务必保留此出处http://shugenyin.blog.51cto.com/4259554/1857492
FPGA设计——CMOS摄像与显示(DVP)