1 module RGB_init( 2 //系统信号输入(时钟+复位) 3 input cmos_clk_i, //模块控制时钟 4 input rst_n_i, //系统复位信号 5 //OV5640输出信号(从5640输入到FPGA) 6 input cmos_pclk_i, //摄像头时钟 7 input cmos_href_i, //帧输出行同步信号 8 input cmos_vsync_i, //场同步信号 9 input [7:0] cmos_data_i, //像素数据 10 //模块的输出信号 11 output clk_ce, //摄像头帧数据输出/捕获使能信号(12Mhz),该信号的理解是最难的 12 output de_o, //数据有效信号 13 output [23:0] rgb_o, //输出的24bit像素数据 14 output vs_o, //输出的场同步信号 15 output hs_o, //输出的行同步信号 16 //输出道5640模块的像素时钟 17 output cmos_xclk 18 ); 19 20 //为了保持系统稳定,需要丢弃前期一部分帧图像,此处选择丢弃15个,自行选择,也有10个的 21 parameter[3:0]CMOS_FRAME_WAITCNT=15; 22 23 assign cmos_xclk=cmos_clk_i; //xclk为5640驱动时钟,为24/25Mhz 24 25 //在米联客的对复位信号的处理中,复位信号延迟了5个时钟,好像不延迟也可以,可以在例程2中查看 26 //个人认为复位信号的处理是为了使复位信号保持一个完整的信号周期 27 reg[4:0]rst_n_reg=5'd0; 28 always@(posedge cmos_clk_i) //同步于FPGA输入时钟 29 begin 30 rst_n_reg<={rst_n_reg[3:0],rst_n_i}; 31 end 32 33 reg cmos_href_r=1'b0; //将行同步信号进行缓存 34 reg [1:0]cmos_vsync_r; //将场同步信号进行缓存 35 reg[7:0]cmos_data_r; //将5640输出到FPGA的数据进行寄存,因为是处理输出16bit,就是将两个周期的输入信号进行拼接处理 36 //进行行、场同步信号进行缓存,输入数据进行一级缓存 37 always@(posedge cmos_pclk_i) 38 begin 39 cmos_vsync_r<=cmos_vsync_i; 40 cmos_href_r<=cmos_href_i; 41 cmos_data_r<=cmos_data_i; 42 end 43 44 //为了判断一帧数据的开始&结束,同时对帧进行计数,对场同步信号进行寄存 45 reg [1:0]cmos_vsync_d; 46 always@(posedge cmos_pclk_i) //同步于5640输出时钟 47 begin 48 cmos_vsync_d<={cmos_vsync_d[0],cmos_vsync_r}; 49 end 50 //场开始与结束信号 51 wire vs_start; 52 assign vs_start=(!cmos_vsync_d[1])&(cmos_vsync_d[0]); //posedge mark the action 53 wire vs_end; 54 assign vs_end=(cmos_vsync_d[1])&(!cmos_vsync_d[0]); 55 56 //行同步信号缓存 57 reg [1:0]cmos_href_d=2'd0; 58 always@(posedge cmos_pclk_i) 59 begin 60 cmos_href_d<={cmos_href_d[0],cmos_href_r}; 61 end 62 63 //前期丢弃部分帧 64 reg [4:0]frame_cnt=0; //帧计数器 65 reg out_en=0; //开始正常启动操作 66 always@(posedge cmos_pclk_i) 67 if(!rst_n_reg[4]) 68 begin 69 frame_cnt<=5'd0; 70 out_en<=1'b0; 71 end 72 else begin 73 if(vs_start) begin 74 frame_cnt<=frame_cnt+1; 75 out_en<=0; 76 end 77 else if(frame_cnt>=CMOS_FRAME_WAITCNT) 78 begin 79 out_en<=1; 80 frame_cnt<=CMOS_FRAME_WAITCNT; //保持正常帧处理完毕 81 end 82 end 83 //由于输出的是24bit数据,是由16bit数据转化而来,将两个帧的RGB数据进行拼接 84 reg href_cnt=0; 85 reg data_en=1'b0; 86 reg [15:0]RGBm=16'd0; //middle RGB data 87 88 always@(posedge cmos_pclk_i)begin 89 if(!rst_n_reg[4])begin 90 href_cnt<=0; 91 data_en<=1'b0; 92 RGBm<=16'd0; 93 end 94 //两个数据拼接完毕之后将data_en置一,第0次拼接使低8位有效,第1次使得低八位有效(位移) 95 else begin 96 href_cnt<=(cmos_href_r)?href_cnt+1'b1:href_cnt; 97 data_en<=(href_cnt==1); 98 if(href_cnt) RGBm<={RGBm[7:0],cmos_data_r}; //此处cmos_data_r lag 2 clocks,thus later all lag 2clks 99 end 100 end 101 102 assign rgb_o={RGBm[15:11],3'd0,RGBm[10:5],2'd0,RGBm[4:0],3'd0}; 103 //模块行同步输出 104 assign hs_o=out_en?(cmos_href_d[0]):0; //为了与暑促信号同步,该同步信号是滞后两个pclk 105 //模块场同步信号输出 106 assign vs_o=out_en?(cmos_vsync_r):0; //行同步结束之后开始场同步,场同步信号知乎一个pclk,觉得这个程序真的很nb,考虑的太全了 107 //模块数据输出同步时钟信号,12M, 108 assign de_o=out_en?data_en:0; 109 //输出时钟enable signal 110 assign clk_ce=out_en?((data_en&hs_o)||!hs_o):0; //其实好像1也行,没有边沿驱动 111 //在init complete的情况下,d0是经过了2个pclk延迟的,该output信号同步(更准确地说是对齐)于这个数据输入时的时钟, 112 //同步于12Mhz的data_en时钟 113 //该模块每2个pclk输出一次rgb[23:0]的数据,需要听过clk_ce对时钟频率进行同步,该处理解决了模块接口之间的同步问题 114 /* 115 举例说明: 116 在do==0时,clk_ce恒为高,没有时钟脉冲 117 在do==1时,该时钟始终同步于12M时钟 118 */ 119 endmodule