General design drawing of system
System components
Camera initialization module
Camera initialization writes register and rewrites data through IIC protocol or SCCB protocol. The conditions met before initialization are shown in the figure.
IIC initialization module code
module OV7670_INIT_IIC( Clk, Rst_n, Start, Iic_clk, Sda, Init_done ); input Clk; input Rst_n; input Start; output Iic_clk; inout Sda; output reg Init_done; reg [7:0]data_cnt;//Count 115 data counter localparam DATA_SIZE = 8'd115; wire [15:0]q_rom; wire done_iic; reg wr_en; wire [7:0]wr_data;//Data written wire [15:0]word_adrr; reg [1:0]main_state; wire ack ; reg [9:0] cnt; reg ok ; always @(posedge Clk or negedge Rst_n) if(!Rst_n) cnt <= 1'b0; else if(done_iic) cnt <= 1'b0; else if(cnt == 10'd99) //Count 2us cnt <= 1'b0; else cnt <= cnt + 1'b1; always @(posedge Clk or negedge Rst_n) if(!Rst_n) ok <= 1'b0; else if(cnt == 10'd99) ok <= 1'b1; else ok <= 1'b0; always @(posedge Clk or negedge Rst_n) if(!Rst_n) data_cnt <= 1'b0; else if(Start) data_cnt <= 1'b0; else if(data_cnt < DATA_SIZE) begin if(done_iic && (!ack)) data_cnt <= data_cnt + 1'b1; else data_cnt <= data_cnt; end else data_cnt <= DATA_SIZE; //Generate initialization completion flag signal always @(posedge Clk or negedge Rst_n) if(!Rst_n) Init_done <= 1'b0; else if(data_cnt == DATA_SIZE) Init_done <= 1'b1; else Init_done <= 1'b0; //State machine sends data always @(posedge Clk or negedge Rst_n) if(!Rst_n) begin main_state <= 2'b0; wr_en <= 1'b0; end else begin if(data_cnt < DATA_SIZE) begin case(main_state) 2'b0: begin if(Start) main_state <= 2'd1; else main_state <= 2'd0; end 2'd1: begin wr_en <= 1'b1; main_state <= 2'd2; end 2'd2: begin wr_en <= 1'b0; if(ok) main_state <= 2'd1; else main_state <= 2'd2; end default : main_state <= 1'b0; endcase end else begin wr_en <= 1'b0; main_state <= 1'b0; end end //IIC module IIC IIC( .Clk(Clk), .Rst_n(Rst_n), .Wr(wr_en), .Read(1'b0), .Wdata_num(1), .Rdata_num(1'b1), .Address_num(2'd1), .Device_adress(8'h42), //Device chip selection address .Word_adrr(word_adrr), //Storage unit address .Wr_data(wr_data), .Rd_data(), .Wr_data_vaule(), .Rd_data_vaule(), .Done(done_iic), .ack(ack), .Sda(Sda), .Iic_clk(Iic_clk) ); assign wr_data = q_rom[7:0]; assign word_adrr = q_rom[15:8]; OV7670_TABLE_ROM OV7670_TABLE_ROM ( .addr(data_cnt), .clk(Clk), .q(q_rom) ); endmodule
IIC writes 8 bits of 115 different register addresses at a time.
IIC initialization module problems and causes
The main reasons for the failure of initialization using IIC protocol are that the idle time of IIC bus is too short, and the interval between the stop bit (rising edge) generated by the last write completion and the start bit (falling edge) generated by the next write start is too short, which does not meet the requirements of camera devices. The device requirements are shown in the figure.
The actual waveform measured by logic analyzer is shown in the figure.
It can be clearly seen from the figure that when IIC protocol writes different register addresses for the second time, the slave does not generate reply bits, resulting in initialization failure. The actual bus idle time is 700ns.
SCCB initialization module code
module OV7670_INIT_SCCB( Clk , Rst_n , Start , Sccb_clk , Sda , Init_done ); input Clk ; input Rst_n ; input Start ; output Sccb_clk ; output Sda ; output reg Init_done ; reg [7:0] addr_cnt ; //Address counter counting 115 times wire [15:0] q_rom ; wire [7:0] wr_data ; wire [7:0] word_adrr ; wire wr_done ; reg wr_en ; reg [1:0] main_state ; localparam DATA_SIZE = 115 ; always @(posedge Clk or negedge Rst_n) if(!Rst_n) addr_cnt <= 1'b0; else if(Start) addr_cnt <= 1'b0; else if(addr_cnt < DATA_SIZE) begin if(wr_done) addr_cnt <= addr_cnt + 1'b1; else addr_cnt <= addr_cnt ; end else addr_cnt <= DATA_SIZE ; always @(posedge Clk or negedge Rst_n) if(!Rst_n) Init_done <= 1'b0; else if(addr_cnt == DATA_SIZE) Init_done <= 1'b1; else Init_done <= 1'b0; always @(posedge Clk or negedge Rst_n) if(!Rst_n) begin main_state <= 2'b0; wr_en <= 1'b0; end else begin if(addr_cnt < DATA_SIZE) begin case(main_state) 2'b0: begin if(Start) main_state <= 2'd1; else main_state <= 2'd0; end 2'd1: begin wr_en <= 1'b1; main_state <= 2'd2; end 2'd2: begin wr_en <= 1'b0; if(wr_done) main_state <= 2'd1; end default : main_state <= 1'b0; endcase end else begin wr_en <= 1'b0; main_state <= 1'b0; end end assign wr_data = q_rom[7:0] ; assign word_adrr = q_rom[15:8] ; SCCB SCCB_inst( .Clk (Clk ) , .Rst_n (Rst_n ) , .Wr (wr_en ) , .Wr_data (wr_data ) , .Wr_data_vaule () , .Wr_done (wr_done ) , .Word_adrr (word_adrr ) , //Storage unit address .Device_adress (8'h42) , //Device address .Read () , .Rd_data () , .Rd_data_vaule () , .Rd_done () , .Sda (Sda ) , .Sccb_clk (Sccb_clk ) ); OV7670_TABLE_ROM OV7670_TABLE_ROM_insy ( .addr (addr_cnt ) , .clk (Clk ) , .q (q_rom ) ); endmodule
It is basically the same as IIC initialization code, because it only writes and does not read data.
Problems and causes of SCCB initialization
In the SCCB module code, in the same always statement, the judgment priority of the first if statement is higher than that of the second if statement. Because the SCCB enable signal in the initialization code remains at a high level, the SCCB protocol clock signal CLK is always generated. At a high level of CLK, the SDA signal does not produce a falling edge and start bit, resulting in initialization failure. The problem code is shown in the figure.
The comparison between the actual problem waveform and the correct waveform is shown in the figure. When the CLK signal is high, the two waveforms generate the rising edge, that is, the stop bit, but the error waveform does not generate the falling edge, that is, the stop bit when the CLK signal is high.
System top-level file code
`include "disp_parameter.v" module DVP_SDRAM_VGA( //global port input wire Clk , input wire Rst_n , //camera interface input wire Cmos_pclk , input wire Cmos_vsync , input wire Cmos_href , input wire [7:0] Cmos_data , output wire Cmos_xclk , //Drive camera clock output wire Cmos_sclk , inout wire Cmos_sda , output wire Cmos_pwdn , output wire Cmos_rst_n , //SDRAM port output wire Sdram_clk , output wire Sdram_cke , output wire Sdram_cs_n , output wire Sdram_cas_n , output wire Sdram_ras_n , output wire Sdram_we_n , output wire [1:0] Sdram_ba , output wire [12:0] Sdram_addr , inout wire [15:0] Sdram_dq , output wire [1:0] Sdram_dqm , //VGA port output wire [`Red_Bits - 1 :0] Disp_red , output wire [`Green_Bits - 1 :0] Disp_green , output wire [`Blue_Bits - 1 :0] Disp_blue , output wire Hsync , output wire Vsync , output wire Clk_vga , output wire Clk_blk ); reg [31:0] cnt ; wire go ; wire sys_rst_n ; wire clk_cmos_24M ; wire clk_100M ; wire clk_shift_100M ; wire clk_vga_24M ; wire lock ; wire init_done ; wire wr_req ; //Read SDRAM request signal wire [15:0] data_cmos ; //Camera signal wire pix_reg ; wire [15:0] pix_data ; wire wr_rst ; wire [10:0] pix_x ; wire [10:0] pix_y ; wire rd_value_r ; reg rd_value ; assign Cmos_pwdn = 1'b0; assign Cmos_rst_n = (cnt > 32'd175_000); //3.5ms assign sys_rst_n = Rst_n && lock; always @(posedge Clk or negedge Rst_n) if(!Rst_n) cnt <= 1'b0 ; else if(cnt < 32'd6500_001) // 6.5ms cnt <= cnt + 1'b1 ; else cnt <= cnt ; assign go = (cnt == 32'd6500_000 ) ? 1'b1:1'b0; assign rd_value_r = ((pix_x == 0) && (pix_y == 0))?1'b1:1'b0; //Read cache module reset flag bit always @(posedge Clk or negedge Rst_n) if(!Rst_n) rd_value <= 1'b0; else if(rd_value_r) rd_value <= 1'b1; else rd_value <= rd_value ; pll pll_inst ( .areset ( !Rst_n ), .inclk0 ( Clk ), .c0 ( clk_cmos_24M ), .c1 ( clk_100M ), .c2 ( clk_shift_100M ), .c3 ( clk_vga_24M ), .locked ( lock ) ); OV7670_INIT_IIC OV7670_INIT_IIC_inst( .Clk (Clk ) , .Rst_n (sys_rst_n ) , .Start (go ) , .Iic_clk (Cmos_sclk ) , .Sda (Cmos_sda ) , .Init_done (init_done ) ); CAMERA_OV7670_DVP CAMERA_OV7670_DVP_inst( .Rst_n (sys_rst_n) , .Clk_cmos (clk_cmos_24M) , //Drive camera clock .Cmos_pclk (Cmos_pclk ) , //Camera input clock .Cmos_vsync (Cmos_vsync) , .Cmos_href (Cmos_href ) , .Cmos_data (Cmos_data ) , .Cmos_data_value (wr_req ) , .Cmos_data_pixel (data_cmos) , .Xaddress () , .Yaddress () , .Wr_rst (wr_rst) , .Cmos_xclk (Cmos_xclk) ); SDRAM_TOP SDRAM_TOP_inst( .Clk (clk_100M) , .Rst_n (sys_rst_n) , .Clk_out (clk_shift_100M) , //Input phase offset clock .Wr_fifo_wr_clk (Cmos_pclk) , .Wr_fifo_wr_req (wr_req) , .Wr_fifo_wr_data (data_cmos) , //Write to FIFO .Sdram_wr_b_addr (0) , .Sdram_wr_e_addr (640*480) , .Wr_burst_len (10'd512) , .Wr_rst (!sys_rst_n) , //Write reset signal .Rd_fifo_rd_clk (clk_vga_24M) , .Rd_fifo_rd_req (pix_reg) , .Sdram_rd_b_addr (0) , .Sdram_rd_e_addr (640*480) , .Rd_burst_len (10'd512) , //Read burst length .Rd_rst (!sys_rst_n) , //Read reset signal .Rd_value (rd_value) , .Rd_fifo_rd_data (pix_data) , //Read the data read out in FIFO .Rd_fifo_num () , //Number of data in read FIFO .Sdram_clk (Sdram_clk ) , .Sdram_cke (Sdram_cke ) , .Sdram_cs_n (Sdram_cs_n ) , .Sdram_cas_n (Sdram_cas_n) , .Sdram_ras_n (Sdram_ras_n) , .Sdram_we_n (Sdram_we_n ) , .Sdram_ba (Sdram_ba ) , .Sdram_addr (Sdram_addr ) , .Sdram_dq (Sdram_dq ) , // SDRAM data bus .Sdram_dqm (Sdram_dqm ) ); VGA_CTRL VGA_CTRL_inst( .Clk (clk_vga_24M) , .Rst_n (sys_rst_n) , .Pix_data ({pix_data[15:11],3'd0,pix_data[10:5],2'd0,pix_data[4:0],3'd0}) , //R G B .Disp_red (Disp_red ) , .Disp_green (Disp_green) , .Disp_blue (Disp_blue ) , .Hsync (Hsync ) , .Vsync (Vsync ) , .Pix_x (pix_x) , .Pix_y (pix_y) , .Clk_vga (Clk_vga) , .Vga_blk (Clk_blk) , //VGA field blanking signal .Pix_reg (pix_reg) ); // VGA_CTRL VGA_CTRL_inst( // .Clk (clk_vga_24M) , // .Rst_n (sys_rst_n) , // .Pix_data (pix_data) , //R G B // .Disp_red (Disp_red ) , // .Disp_green (Disp_green) , // .Disp_blue (Disp_blue ) , // .Hsync (Hsync ) , // .Vsync (Vsync ) , // .Pix_x (pix_x) , // .Pix_y (pix_y) , // .Clk_vga (Clk_vga) , // .Vga_ BLK (clk_blk), / / VGA field blanking signal // .Pix_reg (pix_reg) // ); endmodule
Call the "disp\u parameter.v" file in the file, and you can select RGB565 or RGB888 mode for display.
The actual operation is shown in the figure.