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