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