Video transmission based on OV7670 camera

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.

Tags: Verilog Single-Chip Microcomputer FPGA

Posted by rlgriffo on Sun, 01 May 2022 19:53:58 +0300