OV5640数据的解码
为了配合开发板的使用,笔者搞了一个OV5640的摄像头模组,OV5640具体的相关手册及资料网上已经很多,感兴趣的都可以自行去查找,基本大同小异。这里也不把OV5640初始化的代码贴出来,因为就是简单的类似I2C接口配置数据。这里主要讲下初始化后的CMOS数据的解码,笔者是根据自己的需求把数据的VS,HS信号分别表示在了数据流的第一第二位,不过也是处理后的表示。
这里初始化后的数据是RGB565的数据格式,对于初始化完成的COMS,一般情况是先要把前面不稳定的帧弃,笔者这里设置为15帧。具体可根据代码来解读,笔者前面做的边缘检测,高斯滤波就是基于此解码方式做的实验。
顶层文件Cmosbuf.v:
1 //************************************************************************** 2 // *** file name : Cmosbuf.v 3 // *** version : 1.0 4 // *** Description : Cmos data turn to stream 5 // *** Blogs : https://www.cnblogs.com/WenGalois123/ 6 // *** Author : Galois_V 7 // *** Date : 2022.08.23 8 // *** Changes : Initial 9 //************************************************************************** 10 `timescale 1ns/1ps 11 module Cmosbuf 12 #( 13 parameter DROP_FPS = 15 , 14 parameter FIFO_DEPTH = 2048 , 15 parameter H_Active = 1280 , 16 parameter V_Active = 720 17 ) 18 ( 19 input i_sys_clk , 20 input i_sys_rstn , 21 input i_cmos_clk , 22 input i_cmos_pclk , 23 input i_cmos_vs , 24 input i_cmos_hs , 25 input [7:0] i_cmos_data , 26 output o_cmos_xclk , 27 input i_fifo_ready , 28 output [31:0] o_stream_data , 29 output o_stream_valid , 30 output o_frame_rst , 31 output o_cmos_vs 32 ); 33 wire w_cmos_vs ; 34 wire w_cmos_hs ; 35 wire w_cmos_de ; 36 wire [15:0] w_cmos_data ; 37 wire w_start_frame ; 38 wire w_end_line ; 39 wire [17:0] w_fifo_din ; 40 wire [17:0] w_fifo_dout ; 41 wire w_rst_vs ; 42 reg [5:0] r_sys_rstn ; 43 reg [3:0] r_vs_buf ; 44 45 function integer clog; 46 input [31:0] i_data; 47 begin 48 for(clog=0;i_data >0; clog = clog + 1) 49 begin 50 i_data = i_data >> 1; 51 end 52 end 53 endfunction 54 55 always@(posedge i_cmos_clk) 56 begin 57 r_sys_rstn <= {r_sys_rstn[4:0],i_sys_rstn}; 58 end 59 Cmosdecode 60 #( 61 .DROP_FPS (DROP_FPS ), 62 .H_Active (H_Active ), 63 .V_Active (V_Active ) 64 )u_Cmosdecode 65 ( 66 .i_sys_clk (i_sys_clk ), 67 .i_sys_rstn (i_sys_rstn ), 68 .i_cmos_clk (i_cmos_clk ), 69 .i_cmos_vs (i_cmos_vs ), 70 .i_cmos_hs (i_cmos_hs ), 71 .i_cmos_data (i_cmos_data ), 72 .o_cmos_xclk ( ), 73 .o_cmos_vs (w_cmos_vs ), 74 .o_cmos_hs (w_cmos_hs ), 75 .o_cmos_de (w_cmos_de ), 76 .o_cmos_data (w_cmos_data ), 77 .o_start_frame (w_start_frame ), 78 .o_end_line (w_end_line ) 79 ); 80 81 always@(posedge i_sys_clk) 82 begin 83 r_vs_buf <= {r_vs_buf[2:0],i_cmos_vs}; 84 end 85 86 assign w_rst_vs = ~r_vs_buf[2] & r_vs_buf[3]; 87 assign w_fifo_din = {w_start_frame,w_end_line,w_cmos_data}; 88 89 xpm_fifo_async 90 #( 91 .FIFO_MEMORY_TYPE ("block" ), 92 .ECC_MODE ("no_ecc" ), 93 .RELATED_CLOCKS (0 ), 94 .FIFO_WRITE_DEPTH (FIFO_DEPTH ), 95 .WRITE_DATA_WIDTH (18 ), 96 .WR_DATA_COUNT_WIDTH (clog(FIFO_DEPTH) ), 97 .PROG_FULL_THRESH (10 ), 98 .FULL_RESET_VALUE (0 ), 99 .USE_ADV_FEATURES ("0707" ), 100 .READ_MODE ("fwft" ), 101 .FIFO_READ_LATENCY (0 ), 102 .READ_DATA_WIDTH (18 ), 103 .RD_DATA_COUNT_WIDTH (clog(FIFO_DEPTH) ), 104 .PROG_EMPTY_THRESH (10 ), 105 .DOUT_RESET_VALUE ("0" ), 106 .CDC_SYNC_STAGES (2 ), 107 .WAKEUP_TIME (0 ) 108 ) 109 u_cmos_fifo 110 ( 111 .rst (w_rst_vs | (~r_sys_rstn[5])), 112 .wr_clk (i_cmos_clk ), 113 .wr_en (w_cmos_de ), 114 .din (w_fifo_din ), 115 .full ( ), 116 .overflow ( ), 117 .prog_full ( ), 118 .wr_data_count ( ), 119 .almost_full ( ), 120 .wr_ack ( ), 121 .wr_rst_busy ( ), 122 .rd_clk (i_sys_clk ), 123 .rd_en (i_fifo_ready ), 124 .dout (w_fifo_dout ), 125 .empty (w_fifo_empty ), 126 .underflow ( ), 127 .rd_rst_busy ( ), 128 .prog_empty ( ), 129 .rd_data_count ( ), 130 .almost_empty ( ), 131 .data_valid ( ), 132 .sleep (1'b0 ), 133 .injectsbiterr (1'b0 ), 134 .injectdbiterr (1'b0 ), 135 .sbiterr ( ), 136 .dbiterr ( ) 137 ); 138 assign o_cmos_xclk = i_cmos_pclk; 139 assign o_stream_valid = ~w_fifo_empty & i_fifo_ready; 140 assign o_cmos_vs = w_cmos_vs; 141 assign o_frame_rst = w_rst_vs; 142 assign o_stream_data = {w_fifo_dout[17:16],6'd0,w_fifo_dout[15:11],3'd0,w_fifo_dout[10:5],2'd0,w_fifo_dout[4:0],3'd0}; 143 144 endmodule
上述的i_cmos_pclk是需要提供给FPGA外部OV5640的o_cmos_xclk,而i_cmos_clk则是OV5640输入像素数据的同步时钟,i_sys_clk这里是整个系统的时钟。如果i_sys_clk与i_cmos_clk不是同一个时钟就存在跨时钟域,因此这里通过一个异步FIFO来实现跨时钟域的处理。
数据解码模块Cmosdecode.v
1 //************************************************************************** 2 // *** file name : Cmosdecode.v 3 // *** version : 1.0 4 // *** Description : Cmos data decode 5 // *** Blogs : https://www.cnblogs.com/WenGalois123/ 6 // *** Author : Galois_V 7 // *** Date : 2022.08.23 8 // *** Changes : Initial 9 //************************************************************************** 10 `timescale 1ns/1ps 11 module Cmosdecode 12 #( 13 parameter DROP_FPS = 15 , 14 parameter H_Active = 640 , 15 parameter V_Active = 480 16 ) 17 ( 18 input i_sys_clk , 19 input i_sys_rstn , 20 input i_cmos_clk , 21 input i_cmos_vs , 22 input i_cmos_hs , 23 input [7:0] i_cmos_data , 24 output o_cmos_xclk , 25 output o_cmos_vs , 26 output o_cmos_hs , 27 output o_cmos_de , 28 output [15:0] o_cmos_data , 29 output o_start_frame , 30 output o_end_line 31 ); 32 wire w_vs_pos ; 33 wire w_vs_neg ; 34 wire w_hs_neg ; 35 reg [5:0] r_sys_rstn ; 36 reg [2:0] r_vs ; 37 reg [2:0] r_hs ; 38 reg [7:0] r_cmos_data ; 39 reg [6:0] r_cmos_fps ; 40 reg r_out_en ; 41 reg r_1st_hs ; 42 reg r_reverse_en ; 43 reg r_reverse_en_dly; 44 reg [15:0] r_rgb_data ; 45 reg [11:0] r_cnt_pixel ; 46 47 always@(posedge i_cmos_clk) 48 begin 49 r_sys_rstn <= {r_sys_rstn[4:0],i_sys_rstn}; 50 end 51 52 always@(posedge i_cmos_clk) 53 begin 54 r_vs <= {r_vs[1:0],i_cmos_vs}; 55 r_hs <= {r_hs[1:0],i_cmos_hs}; 56 end 57 always@(posedge i_cmos_clk) 58 begin 59 r_cmos_data <= i_cmos_data; 60 end 61 assign w_vs_pos = ~r_vs[2] & r_vs[1]; 62 assign w_vs_neg = ~r_vs[1] & r_vs[2]; 63 assign w_hs_neg = ~r_hs[1] & r_hs[2]; 64 /******************************************************************************\ 65 Drop some frames 66 \******************************************************************************/ 67 always@(posedge i_cmos_clk) 68 begin 69 if(~r_sys_rstn[5]) 70 begin 71 r_cmos_fps <= 'd0; 72 end 73 else if(r_cmos_fps >= DROP_FPS) 74 begin 75 r_cmos_fps <= r_cmos_fps; 76 end 77 else if(w_vs_pos) 78 begin 79 r_cmos_fps <= r_cmos_fps + 1'b1; 80 end 81 end 82 always@(posedge i_cmos_clk) 83 begin 84 if(~r_sys_rstn[5]) 85 begin 86 r_out_en <= 'd0; 87 end 88 else if(r_cmos_fps >= DROP_FPS) 89 begin 90 r_out_en <= 1'b1; 91 end 92 else 93 begin 94 r_out_en <= r_out_en; 95 end 96 end 97 always@(posedge i_cmos_clk) 98 begin 99 if(~r_sys_rstn[5]) 100 begin 101 r_1st_hs <= 'd0; 102 end 103 else if(w_vs_neg) 104 begin 105 r_1st_hs <= 1'b1; 106 end 107 else if(w_hs_neg) 108 begin 109 r_1st_hs <= 'd0; 110 end 111 end 112 /******************************************************************************\ 113 decode the data from cmos 114 \******************************************************************************/ 115 always@(posedge i_cmos_clk) 116 begin 117 if(~r_sys_rstn[5]) 118 begin 119 r_reverse_en <= 'd0; 120 end 121 else if(r_hs[1]) 122 begin 123 r_reverse_en <= ~r_reverse_en; 124 end 125 else 126 begin 127 r_reverse_en <= 'd0; 128 end 129 end 130 always@(i_cmos_clk) 131 begin 132 if(~r_sys_rstn[5]) 133 begin 134 r_reverse_en_dly <= 'd0; 135 end 136 else 137 begin 138 r_reverse_en_dly <= r_reverse_en; 139 end 140 end 141 always@(posedge i_cmos_clk) 142 begin 143 if(~r_sys_rstn[5]) 144 begin 145 r_rgb_data <= 'd0; 146 end 147 else if(r_hs[1]) 148 begin 149 r_rgb_data <= {r_rgb_data[7:0],r_cmos_data}; 150 end 151 else if(~r_hs[1]) 152 begin 153 r_rgb_data <= 'd0; 154 end 155 end 156 always@(posedge i_cmos_clk) 157 begin 158 if(~r_sys_rstn[5]) 159 begin 160 r_cnt_pixel <= 'd0; 161 end 162 else if(~r_hs[2]) 163 begin 164 r_cnt_pixel <= 'd0; 165 end 166 else if(r_reverse_en) 167 begin 168 r_cnt_pixel <= r_cnt_pixel + 1'b1; 169 end 170 end 171 /******************************************************************************\ 172 output cmos signal 173 \******************************************************************************/ 174 assign o_cmos_vs = r_out_en ? r_vs[2] : 1'b0; 175 assign o_cmos_hs = r_out_en ? r_hs[2] : 1'b0; 176 assign o_cmos_de = r_reverse_en & o_cmos_hs & (r_cnt_pixel < H_Active); 177 assign o_start_frame = r_reverse_en & (r_cnt_pixel == 'd0) & r_1st_hs; 178 assign o_end_line = r_reverse_en & (r_cnt_pixel == H_Active - 1'b1); 179 assign o_cmos_xclk = i_cmos_clk; 180 assign o_cmos_data = r_rgb_data; 181 182 endmodule
以上便是CMOS数据的解码的Verilog代码,笔者在前面两个实验已经验证过了,是可以正常使用的。