verilog 代码分析与仿真
注意:使用vivado 自带的仿真工具, reg和wire等信号需要赋予初始值
边沿检测
module signal_test( input wire cmos_pclk_i, input wire cmos_vsync_i ); // 上升沿捕获 reg [1:0] vsync_d; wire vsync_start; wire vsync_end; always @(posedge cmos_pclk_i) begin vsync_d <= {vsync_d[0], cmos_vsync_i}; end assign vsync_start = vsync_d[1] && (!vsync_d[0]); assign vsync_end = (!vsync_d[1]) && vsync_d[0]; endmodule /* add_force {/signal_test/cmos_pclk_i} -radix hex {1 0ns} {0 50000ps} -repeat_every 100000ps add_force {/signal_test/cmos_vsync_i} -radix hex {1 0ns} {0 300ns} {1 700ns} */
仿真结果:
时钟二分频的巧用
//在一定区域内,将时钟cmos_pclk_i 进行二分频 reg byte_flag = 0; always@(posedge cmos_pclk_i) begin if(rst) byte_flag <= 0; else if(cmos_href_i) //控制信号,固定区域 byte_flag <= ~byte_flag; else byte_flag <= 0; end //将byte_flag 延时一拍,从仿真图中才可以看出此处的用意 reg byte_flag_r0 = 0; always@(posedge cmos_pclk_i) begin if(rst) byte_flag_r0 <= 0; else byte_flag_r0 <= byte_flag; end
仿真结果:
数据采集与数据融合
注意rgb565信号的生成
//接收摄像头的数据,当href为高电平时,采集数据,当为低电平时,用0填充 reg [7:0] cmos_data_d0 = 0; always@(posedge cmos_pclk_i) begin if(rst) cmos_data_d0 <= 8'd0; else if(cmos_href_i) cmos_data_d0 <= cmos_data_i; //MSB -> LSB else if(~cmos_href_i) cmos_data_d0 <= 8'd0; end reg [15:0] rgb565_o = 0; always@(posedge cmos_pclk_i) begin if(rst) rgb565_o <= 16'd0; //当href为高电平,byte_flag 为高时候,对rgb565数据进行拼装 else if(cmos_href_i & byte_flag) rgb565_o <= {cmos_data_d0,cmos_data_i}; //MSB -> LSB else if(~cmos_href_i) rgb565_o <= 8'd0; end
仿真结果:
成功的将两个数融合在一起,一个是寄存器里面保存的数据,一个是实时的输入数据。
关于像素的输出使能信号的生成
assign vs_o = vsync_d[1]; assign hs_o = href_d[1]; assign vid_clk_ce = (byte_flag_r0&hs_o)||(!hs_o);
仿真结果:
当hs_o 为高时,摄像头输出有效数据,2个2个一起,每当数据进行更新时,ce信号产生,当输出的是消隐区数据的时候,ce信号一直使能。
1 module signal_test_1( 2 3 input wire cmos_pclk_i, 4 input wire rst, 5 input wire [7:0]cmos_data_i, 6 input wire cmos_href_i, 7 input wire cmos_vsync_i, 8 output wire hs_o, 9 output wire vs_o, 10 output wire vid_clk_ce 11 12 ); 13 14 /*parameter[5:0]CMOS_FRAME_WAITCNT = 4'd15;*/ 15 16 // 对行场信号进行边沿检测处理 17 reg[1:0]vsync_d = 2'b11; 18 reg[1:0]href_d = 2'b00; 19 wire vsync_start; 20 wire vsync_end; 21 //vs signal deal with. 22 always@(posedge cmos_pclk_i) 23 begin 24 vsync_d <= {vsync_d[0],cmos_vsync_i}; 25 href_d <= {href_d[0],cmos_href_i}; 26 end 27 assign vsync_start = vsync_d[1]&(!vsync_d[0]); //捕捉vsync信号的下降沿 28 assign vsync_end = (!vsync_d[1])&vsync_d[0]; //捕捉vsync信号的上升沿 29 30 31 /*reg[6:0]cmos_fps = 0; 32 //frame count. 33 always@(posedge cmos_pclk_i) 34 begin 35 if(rst) 36 begin 37 cmos_fps <= 7'd0; 38 end 39 40 else if(vsync_start) //每当一场开始的时候,计数器加一,难道是一帧只有一场? 41 begin 42 cmos_fps <= cmos_fps + 7'd1; 43 end 44 45 //计数到了CMOS_FRAME_WAITCNT时,就保持这个数值不变(15) 46 else if(cmos_fps >= CMOS_FRAME_WAITCNT) 47 begin 48 cmos_fps <= CMOS_FRAME_WAITCNT; 49 end 50 end*/ 51 52 53 //在一定区域内,将时钟cmos_pclk_i 进行二分频 54 reg byte_flag = 0; 55 always@(posedge cmos_pclk_i) 56 begin 57 if(rst) 58 byte_flag <= 0; 59 60 else if(cmos_href_i) //控制信号,固定区域 61 byte_flag <= ~byte_flag; 62 63 else 64 byte_flag <= 0; 65 end 66 67 //将byte_flag 延时一拍,从仿真图中才可以看出此处的用意 68 reg byte_flag_r0 = 0; 69 always@(posedge cmos_pclk_i) 70 begin 71 if(rst) 72 byte_flag_r0 <= 0; 73 74 else 75 byte_flag_r0 <= byte_flag; 76 end 77 78 //接收摄像头的数据,当href为高电平时,采集数据,当为低电平时,用0填充 79 reg [7:0] cmos_data_d0 = 0; 80 always@(posedge cmos_pclk_i) 81 begin 82 if(rst) 83 cmos_data_d0 <= 8'd0; 84 85 else if(cmos_href_i) 86 cmos_data_d0 <= cmos_data_i; //MSB -> LSB 87 88 else if(~cmos_href_i) 89 cmos_data_d0 <= 8'd0; 90 end 91 92 93 reg [15:0] rgb565_o = 0; 94 always@(posedge cmos_pclk_i) 95 begin 96 if(rst) 97 rgb565_o <= 16'd0; 98 99 //当href为高电平,byte_flag 为高时候,对rgb565数据进行拼装 100 else if(cmos_href_i & byte_flag) 101 rgb565_o <= {cmos_data_d0,cmos_data_i}; //MSB -> LSB 102 103 else if(~cmos_href_i) 104 rgb565_o <= 8'd0; 105 end 106 107 assign vs_o = vsync_d[1]; 108 assign hs_o = href_d[1]; 109 assign vid_clk_ce = (byte_flag_r0&hs_o)||(!hs_o); 110 111 112 113 /* 114 115 add_force {/signal_test_1/cmos_pclk_i} -radix hex {1 0ns} {0 50000ps} -repeat_every 100000ps 116 add_force {/signal_test_1/rst} -radix hex {1 0ns} {0 100ns} 117 add_force {/signal_test_1/cmos_href_i} -radix hex {0 0ns} {1 500ns} {0 1500ns} 118 add_force {/signal_test_1/cmos_data_i} -radix hex {0 0ns} {1 500ns} {2 600ns} {3 700ns} {4 800ns} {5 900ns} {6 1000ns} 119 {7 1100ns} {8 1200ns} {9 1300ns} {10 1400ns} {0 1500ns} 120 add_force {/signal_test_1/cmos_vsync_i} -radix hex {1 0ns} {0 300ns} {1 1800ns} 121 122 */ 123 124 125 endmodule
源程序与注释:
1 `timescale 1ns / 1ps 2 ////////////////////////////////////////////////////////////////////////////////// 3 // Company: 4 // Engineer: 5 // 6 // Create Date: 2018/05/17 13:22:09 7 // Design Name: 8 // Module Name: cmos_decode 9 // Project Name: 10 // Target Devices: 11 // Tool Versions: 12 // Description: 13 // 14 // Dependencies: 15 // 16 // Revision: 17 // Revision 0.01 - File Created 18 // Additional Comments: 19 // 20 ////////////////////////////////////////////////////////////////////////////////// 21 22 23 module cmos_decode( 24 //system signal. 25 input cmos_clk_i, //cmos senseor clock. 26 input rst_n_i, //system reset.active low. 27 //cmos sensor hardware interface. 28 input cmos_pclk_i, //input pixel clock. 29 input cmos_href_i, //input pixel hs signal. 30 input cmos_vsync_i, //input pixel vs signal. 31 input[7:0]cmos_data_i, //data. 32 output cmos_xclk_o, //output clock to cmos sensor. 33 //user interface. 34 output hs_o, //hs signal. 35 output vs_o, //vs signal. 36 output reg [15:0] rgb565_o, //data output 37 output vid_clk_ce 38 ); 39 40 41 parameter[5:0]CMOS_FRAME_WAITCNT = 4'd15; 42 43 //复位信号延时5个时钟周期 44 reg[4:0] rst_n_reg = 5'd0; 45 //reset signal deal with. 46 always@(posedge cmos_clk_i) 47 begin 48 rst_n_reg <= {rst_n_reg[3:0],rst_n_i}; 49 end 50 51 52 // 对行场信号进行边沿检测处理 53 reg[1:0]vsync_d; 54 reg[1:0]href_d; 55 wire vsync_start; 56 wire vsync_end; 57 //vs signal deal with. 58 always@(posedge cmos_pclk_i) 59 begin 60 vsync_d <= {vsync_d[0],cmos_vsync_i}; 61 href_d <= {href_d[0],cmos_href_i}; 62 end 63 assign vsync_start = vsync_d[1]&(!vsync_d[0]); //捕捉vsync信号的下降沿 64 assign vsync_end = (!vsync_d[1])&vsync_d[0]; //捕捉vsync信号的上升沿 65 66 67 reg[6:0]cmos_fps; 68 //frame count. 69 always@(posedge cmos_pclk_i) 70 begin 71 if(!rst_n_reg[4]) 72 begin 73 cmos_fps <= 7'd0; 74 end 75 76 else if(vsync_start) //每当一场开始的时候,计数器加一,难道是一帧只有一场? 77 begin 78 cmos_fps <= cmos_fps + 7'd1; 79 end 80 81 //计数到了CMOS_FRAME_WAITCNT时,就保持这个数值不变(15) 82 else if(cmos_fps >= CMOS_FRAME_WAITCNT) 83 begin 84 cmos_fps <= CMOS_FRAME_WAITCNT; 85 end 86 end 87 88 89 //wait frames and output enable. 90 reg out_en; 91 always@(posedge cmos_pclk_i) 92 begin 93 if(!rst_n_reg[4]) 94 begin 95 out_en <= 1'b0; 96 end 97 98 //当计数器达到CMOS_FRAME_WAITCNT(15)时,产生一个使能信号 99 else if(cmos_fps >= CMOS_FRAME_WAITCNT) 100 begin 101 out_en <= 1'b1; 102 end 103 104 //没有达到条件时候,保持原信号不变 105 else 106 begin 107 out_en <= out_en; 108 end 109 end 110 111 //output data 8bit changed into 16bit in rgb565. 112 reg [7:0] cmos_data_d0; 113 reg [15:0]cmos_rgb565_d0; 114 reg byte_flag; 115 always@(posedge cmos_pclk_i) 116 begin 117 if(!rst_n_reg[4]) 118 byte_flag <= 0; 119 120 //产生一个标志位,每当href为高 电平时,产生跳变 121 else if(cmos_href_i) 122 byte_flag <= ~byte_flag; 123 else 124 byte_flag <= 0; 125 end 126 127 //为什么在这里打一拍 128 reg byte_flag_r0; 129 always@(posedge cmos_pclk_i) 130 begin 131 if(!rst_n_reg[4]) 132 byte_flag_r0 <= 0; 133 else 134 byte_flag_r0 <= byte_flag; 135 end 136 137 //接收摄像头的数据,当href为高电平时,采集数据,当为低电平时,用0填充 138 always@(posedge cmos_pclk_i) 139 begin 140 if(!rst_n_reg[4]) 141 cmos_data_d0 <= 8'd0; 142 143 else if(cmos_href_i) 144 cmos_data_d0 <= cmos_data_i; //MSB -> LSB 145 146 else if(~cmos_href_i) 147 cmos_data_d0 <= 8'd0; 148 end 149 150 //重要的来了 151 always@(posedge cmos_pclk_i) 152 begin 153 if(!rst_n_reg[4]) 154 rgb565_o <= 16'd0; 155 156 //当href为高电平,byte_flag 为高时候,对rgb565数据进行拼装 157 else if(cmos_href_i & byte_flag) 158 rgb565_o <= {cmos_data_d0,cmos_data_i}; //MSB -> LSB 159 160 else if(~cmos_href_i) 161 rgb565_o <= 8'd0; 162 end 163 164 165 assign vid_clk_ce = out_en ? (byte_flag_r0&hs_o)||(!hs_o) : 1'b0; 166 assign vs_o = out_en ? vsync_d[1] : 1'b0; 167 assign hs_o = out_en ? href_d[1] : 1'b0; 168 assign cmos_xclk_o = cmos_clk_i; 169 170 endmodule