关灯
请选择 进入手机版 | 继续访问电脑版
米联客uisrc 首页 课程 XIINX-FPGA 2|DDR使用 查看内容
0

(非AXI4)S02-CH04-OV5640-HDMI(4 片 DDR 三缓存)

摘要: 在前面的章节,笔者非常详细的提供了一种数据缓存的构架,并且提供了完善的测试例子,对 构架的设计做了充分的测试验证。前面章节也完成了 OV5640 的图像缓存显示方案,总得来说没什么 难度,但是由于 OV5640 的输入 ...

4.1 概述

      在前面的章节,笔者非常详细的提供了一种数据缓存的构架,并且提供了完善的测试例子,对 构架的设计做了充分的测试验证。前面章节也完成了 OV5640 的图像缓存显示方案,总得来说没什么 难度,但是由于 OV5640 的输入信号是 720P@30HZ,而 HDMI输出是 720P@60HZ 所以本课程的三缓存设计可以最大程度上保证图像的输出结果。(7725的例子采用了相同的构架)。

4.2 构架设计

       对于稍微复杂一点的工程项目必须要有优秀的构架设计,优秀的设计构架的意义比具体写代码 更有价值,所以笔者建议读者在以后自己的项目中要多学习和思考构架的设计。笔者设计了一种基于 消息缓存模式的构架,可以广泛用于图像缓存,数据采集缓存,通信数据缓存等项目中。如下图所示,

       摄像头数据经过sensor_decode 模块解码摄像头数据后将RGB时序图像数据输入到MIG_BURTS_IMAGE, 然后再流出来到 vga_lcd_driver 模块,vga_lcd_driver 模块输出的是 RGB 时序,进过 HDMI IP模块 后接到 HDMI显示器显示输出。 

1)、OV5640摄像头接口:是连接到开发板的物理接口,摄像头模块安装FEP转CEP扩展卡上,默认安装CEP1接口。

2) 、HDMI 接口:是图形的输出接口,图像数据从 HDMI 接口输出 

3) 、sensor_decode模块:解码 OV5640 摄像头的图像数据,然后转为 R/G/B 数据,同时需要产生 HS 信号、VS信号、de 信号提供给后续模块使用。如下面一段代码 

assign rgb_o = {rgb565[15:11],3'd0 ,rgb565[10:5] ,2'd0,rgb565[4:0],3'd0};  

//assign rgb_o = {grid_data_2,grid_data_2,grid_data_2};  

assign clk_ce =out_en? byte_flag_r0:1'b0;  

assign vs_o = out_en ? vsync_d[1] : 1'b0;  

assign hs_o = out_en ? href_d[1] : 1'b0;


4)、vga_lcd_driver 模块:产生 RGB(VGA)输出时序 

5)、MIG_BURST_IMAGE 模块:管理图像数据和内存管理,MIG_BURST_IMAGE 模块中包括了 CH0_FIFO 模 块、CH6_FIFO 模块、MIG_DDR 控制器、MSG_FIFO 消息盒、M_S 内存管理状态机,此外还包括 CH0_FIFO 的读请求,以及 CH6_FIFO 的写请求。

4.3 主要模块源码分析

4.3.1 sensor_decode.v

module sensor_decode(  

 input cmos_clk_i,//cmos senseor clock.  

 input rst_n_i,//system reset.active low.  

 input cmos_pclk_i,//input pixel clock.  

 input cmos_href_i,//input pixel hs signal.  

 input cmos_vsync_i,//input pixel vs signal.  

 input  [7:0]cmos_data_i,//data.  

 output cmos_xclk_o,//output clock to cmos sensor.  

 output hs_o,//hs signal.  

 output vs_o,//vs signal.  

 output [23:0] rgb_o,//data output  

 output clk_ce

    );


assign cmos_xclk_o = cmos_clk_i;      

parameter[5:0]CMOS_FRAME_WAITCNT = 4'd15;      

reg[4:0] rst_n_reg = 5'd0;      

reg cmos_href_r;

reg cmos_vsync_r;

reg [7:0]cmos_data_r;


always@(posedge cmos_pclk_i)

begin  

       cmos_data_r <= cmos_data_i;  

       cmos_href_r <= cmos_href_i;  

       cmos_vsync_r<= ~cmos_vsync_i;  

end     

//reset signal deal with.  

always@(posedge cmos_clk_i)

begin  

 rst_n_reg <= {rst_n_reg[3:0],rst_n_i};  

End


reg[1:0]vsync_d;

reg[1:0]href_d;

wire vsync_start;

wire vsync_end;

//vs signal deal with.  

always@(posedge cmos_pclk_i)

begin  

 vsync_d <= {vsync_d[0],cmos_vsync_r};  

 href_d  <= {href_d[0],cmos_href_r};  

end


assign vsync_end  =  vsync_d[1]&(!vsync_d[0]);  assign vsync_start  = (!vsync_d[1])&vsync_d[0];


reg[6:0]cmos_fps;

//frame count.  

always@(posedge cmos_pclk_i)

begin

 if(!rst_n_reg[4])

  begin

  cmos_fps <= 7'd0;

  end

 else if(vsync_start)

  begin  

  cmos_fps <= cmos_fps + 7'd1;  

  end  

 else if(cmos_fps >= CMOS_FRAME_WAITCNT)  

  begin  

  cmos_fps <= CMOS_FRAME_WAITCNT;  

  end

end

//wait frames and output enable.  

reg out_en;

always@(posedge cmos_pclk_i)

begin

 if(!rst_n_reg[4])

  begin

  out_en <= 1'b0;

  end  

 else if(cmos_fps >= CMOS_FRAME_WAITCNT)  

  begin

  out_en <= 1'b1;

end

 else

  begin  

  out_en <= out_en;  

  end

end


//output data 8bit changed into 16bit in rgb565.  

reg [7:0] cmos_data_d0;  

reg [15:0]cmos_rgb565_d0;

reg byte_flag;


always@(posedge cmos_pclk_i)  

begin

 if(!rst_n_reg[4])  

  byte_flag <= 0;  

 else if(cmos_href_r)  

  byte_flag <= ~byte_flag;  

 else

  byte_flag <= 0;

end


reg byte_flag_r0;  

always@(posedge cmos_pclk_i)  

begin

 if(!rst_n_reg[4])  

  byte_flag_r0 <= 0;  

 else   

  byte_flag_r0 <= byte_flag;  

end


always@(posedge cmos_pclk_i)

begin

 if(!rst_n_reg[4])

  cmos_data_d0 <= 8'd0;  

 else if(cmos_href_r)  

  cmos_data_d0 <= cmos_data_r; //MSB -> LSB  

 else if(~cmos_href_r)   

  cmos_data_d0 <= 8'd0;

end


reg [15:0] rgb565;

always@(posedge cmos_pclk_i)

begin

 if(!rst_n_reg[4])

  rgb565 <= 16'd0;

 else if(cmos_href_r&byte_flag)  

  rgb565 <= {cmos_data_d0,cmos_data_r}; //MSB -> LSB

else if(~cmos_href_r)  

  rgb565 <= 8'd0;

End

//以下代码是利用摄像头输出的时序,产生自动定义的测试数据//   

reg [7:0]cnt_test;

reg [8:0]cnt_temp;

reg [11:0]vcounter;

reg [15:0]vcnt=10'd0;

always@(posedge cmos_pclk_i) begin

if(!rst_n_reg[4]) begin

    vcnt<=16'd0;

end else begin

    if(vsync_start)  

            vcounter <=12'd0;

            if(!vcnt[15])vcnt <= vcnt+1'b1;  

     else if({href_d[0],cmos_href_r}==2'b01)  

             vcounter <= vcounter + 12'd1;

 end

end

reg [11:0]hcounter;

always@(posedge cmos_pclk_i) begin

  if(!cmos_href_r)  

    hcounter <=12'd0;

  else  

    hcounter <= hcounter + 12'd1;

end

reg[7:0] grid_data_1;

reg[7:0] grid_data_2;

always @(posedge cmos_pclk_i)//格子图像 

begin

 if((hcounter[2]==1'b1)^(vcounter[4]==1'b1))

 grid_data_1 <= 8'h00;

 else

 grid_data_1 <= 8'hff;

 if((hcounter[6]==1'b1)^(vcounter[6]==1'b1))

 grid_data_2 <= 8'h00;

 else

 grid_data_2 <= 8'hff;

End

assign rgb_o = {grid_data_2,grid_data_2,grid_data_2};  

//以上代码是利用摄像头输出的时序,产生自动定义的测试数据//   

//assign rgb_o = {rgb565[15:11],3'd0 ,rgb565[10:5] ,2'd0,rgb565[4:0],3'd0};  assign clk_ce =out_en? byte_flag_r0:1'b0;  

assign vs_o = out_en ? vsync_d[1] : 1'b0;  

assign hs_o = out_en ? href_d[1] : 1'b0;

/*

ila_2 sensor_sg (

 .clk(cmos_pclk_i), // input wire clk

.probe0(vs_o), // input wire [0:0]  probe0    

 .probe1(hs_o), // input wire [0:0]  probe1   

 .probe2(clk_ce), // input wire [0:0]  probe2   

 .probe3(vcounter[8:0]), // input wire [0:0]  probe3   

 .probe4(grid_data_2) // input wire [0:0]  probe4   );*/


      OV5640输入的图像是 1280X720分辨率的图形,为了观察数据的方便,未来观察行场信号是否正 确,笔者先利用上一课中用到的测试图形方案数据代码OV5640产生的 RGB 数据,而行场型号继续使 用OV5640产生的行场信号。这么做的目的,主要是我们在对OV5640解码的时候可能采样的颜色时序 会出问题,但是一开始又不能定位问题,这样可以循序渐进式解决问题。 

4.3.2 vga_lcd_driver.v

module vga_lcd_driver(

    input  clk,

    input  [7:0]  r_i,

    input  [7:0]  g_i,

    input  [7:0]  b_i,

    output [7:0]  r_o,

    output [7:0]  g_o,

    output [7:0]  b_o,

    output de,

    output vsync,

    output hsync

    );


   reg  [11:0] hcounter;

   reg  [11:0] vcounter;

    

// Colours converted using The RGB


// -- Set the video mode to 1920x1080x60Hz (150MHz pixel clock needed)

 /*    parameter hVisible  = 1920;

   parameter hStartSync = 1920+88;

   parameter hEndSync   = 1920+88+44;

   parameter hMax       = 1920+88+44+148; //2200

   

   parameter vVisible    = 1080;

   parameter vStartSync  = 1080+4;

   parameter vEndSync    = 1080+4+5;

   parameter vMax        = 1080+4+5+36; //1125

*/


// -- Set the video mode to 1440x900x60Hz (106.47MHz pixel clock needed)

/*   parameter hVisible   = 1440;

   parameter hStartSync = 1440+80;

   parameter hEndSync   = 1440+80+152;

   parameter hMax       = 1440+80+152+232; //1904

   

   parameter vVisible    = 900;

   parameter vStartSync  = 900+1;

   parameter vEndSync    = 900+1+3;

   parameter vMax        = 900+1+3+28; //932

   */

  

// -- Set the video mode to 1280x720x60Hz (75MHz pixel clock needed)

   parameter hVisible   = 1280;

   parameter hStartSync = 1280+72;

   parameter hEndSync   = 1280+72+80;

   parameter hMax       = 1280+72+80+216; //1647

   

   parameter vVisible    = 720;

   parameter vStartSync  = 720+3;

   parameter vEndSync    = 720+3+5;

   parameter vMax        = 720+3+5+22; //749

/*

// -- Set the video mode to 800x600x60Hz (40MHz pixel clock needed)

  parameter hVisible   = 800;

   parameter hStartSync = 840; //800+40

   parameter hEndSync   = 968; //800+40+128

   parameter hMax       = 1056; //800+40+128+88

   

   parameter vVisible    = 600;

   parameter vStartSync  = 601; //600+1

   parameter vEndSync    = 605; //600+1+4

   parameter vMax        = 628; //600+1+4+23      



// -- Set the video mode to 640x480x60Hz (25MHz pixel clock needed)


   parameter hVisible   = 640;

   parameter hStartSync = 656; //640+16

   parameter hEndSync   = 752; //640+16+96

   parameter hMax       = 800; //640+16+96+48

   

   parameter vVisible    = 480;

   parameter vStartSync  = 490; //480+10

   parameter vEndSync    = 492; //480+10+2

   parameter vMax        = 525; //480+10+2+33

*/


//------------------------------------------

//v_sync counter & generator


always@(posedge clk) begin

if(hcounter < hMax - 12'd1)        //line over

hcounter <= hcounter + 12'd1;

else

hcounter <= 12'd0;

end


always@(posedge clk) begin

if(hcounter == hMax - 12'd1) begin

if(vcounter < vMax - 12'd1)  //frame over

vcounter <= vcounter + 12'd1;

else

vcounter <= 12'd0;

end

end


assign hsync = ((hcounter >= (hStartSync - 2'd2))&&(hcounter < (hEndSync - 2'd2)))? 1'b0:1'b1;  //Generate the hSync Pulses

assign vsync = ((vcounter >= (vStartSync - 1'b1))&&(vcounter < (vEndSync - 1'b1)))? 1'b0:1'b1; //Generate the vSync Pulses

  

  assign de = (vcounter >= vVisible || hcounter >= hVisible) ? 1'b0 : 1'b1;

  assign r_o = r_i;

  assign g_o = g_i;

  assign b_o = b_i;  

endmodule

     vga_lcd_driver模块的作用是产生 1280X720 分辨率的RGB使出时序,RGB 的数据来源来自 CH6_FIFO。读者可以修改不同分辨率输出不同的测试图形。 

4.3.3 CH0_FIFO FIFO IP 设置

Step1:设置 Native 和 Independent Clocks Block RAM

Step2:设置 FIFO 采用 Firt Word Fall Through 模式,FIFO 的写是 64bit 2048 深度 FIFO 的读是 512bit 256 深度

Step3:默认设置

Step4:设置计数器


   wire CH0_empty;

    CH0_FIFO CH0_FIFO_INST (

    .rst(CH0_FIFO_RST),  // input wire rst

    .wr_clk(CH0_wclk_i), // input wire wr_clk

    .rd_clk(CH0_rclk_i),// input wire rd_clk

    .din(CH0_data_i), // input wire [63 : 0] din

    .wr_en(CH0_wren_i), // input wire wr_en

    .rd_en(CH0_rden_i), // input wire rd_en

    .dout(CH0_data_o),  // output wire [512 : 0] dout

    .full(),  // output wire full

    .empty(CH0_empty), // output wire empty

    .rd_data_count(CH0_rusdw_o)  // output wire [7 : 0] rd_data_count

    );

4.3.4 CH6_FIFO FIFO IP 设置

Step1:设置 Native 和 Common Clocks Block RAM

Step2:设置 FIFO 采用 Firt Word Fall Through 模式,FIFO 的写是 32bit 32 深度 FIFO 的读是 64bit 16 深度

Step3:这一页设置默认

Step4:设置读FIFO 的 counter 计数器宽度是6bit

    //----------------CH6 fifo接口--------------------//

    CH6_FIFO CH6_FIFO_INST (

    .rst(CH6_FIFO_RST),   // input wire rst

    .wr_clk(CH6_wclk_i),   // input wire wr_clk

    .rd_clk(CH6_rclk_i),   // input wire rd_clk

    .din(CH6_data_i),      // input wire [512 : 0] din

    .wr_en(CH6_wren_i),    // input wire wr_en

    .rd_en(CH6_rden_i),    // input wire rd_en

    .dout(CH6_data_o),     // output wire [64 : 0] dout

    .full(),              // output wire full

    .empty(),            // output wire empty

    .rd_data_count(),  // output wire [10 : 0] rd_data_count

    .wr_data_count(CH6_wusdw_o)  // output wire [7 : 0] wr_data_count

    );

前面讲到 FIFO不支持从512BIT 转换为32bit所以需要添加以下代码将64Bit转换为32bit

always@(posedge CH6_rclk_i)begin

    CH6_64_32_rden <= CH6_rden_i ? CH6_64_32_rden + 1'b1 : 1'b0;

end

assign  CH6_data_o =  CH6_64_32_rden ? CH6_64_32_data_64[31:0] : CH6_64_32_data_64[63:32];

4.3.5 MSG_FIFO 模块

MSG_FIFO MSG_FIFO_INST (  

     .clk(MSG_FIFO_CLK),    // input wire clk  

     .din(MSG_FIFO_WRDATA), // input wire [7 : 0] din  

     .wr_en(MSG_FIFO_WREN), // input wire wr_en  

     .rd_en(MSG_FIFO_RDEN), // input wire rd_en  

     .dout(MSG_FIFO_RDDATA),// output wire [7 : 0] dout  

     .full(MSG_FIFO_FULL),  // output wire full  

     .empty(empty),         // output wire empty  

     .data_count(MSG_FIFO_USEDW) // output wire [4 : 0] data_count  

    );


MSG_FIFO 模块的作用是设计了一个消息的缓存,所有读写请求都会先保存在这消息队列里面然后再 按照先后顺序出列。M_S 模块会对 MSG_FIFO里面的消息进行处理。 

MSG_FIFO_CLK :MSG_FIFO 的时钟信号 这里就是系统本模块的系统时钟和 MIG 控制器时钟一致。  MSG_FIFO_WRDATA:长度为 8 代表同时可以一次性存储 8 个不同信号  

MSG_FIFO_WREN:写消息使能,当读 image_data_gen 和 vga_lcd_driver 模块的场信号过来的时候会 使能写 MSG_FIFO,把消息的状态进入 MSG_FIFO

MSG_FIFO_RDDATA:读消息使能,M_S 状态机会逐条取出 MSG_FIFO 队列中的消息。  MSG_FIFO_FULL:消息满信号,不应该让此信号满,如果满必然发出消息溢出  

MSG_FIFO_USEDW:记录目前已经写入的消息条数,这里最多记录 32 条消息 

CH6_FIFO 的配置界面: 

Step1:设置 Native 和 Common Clocks Block RAM

Step2:设置 FIFO采用 standard 模式,FIFO 的写是 8bit 32 深度读 FIFO 是 8bit 32 深度。

Step3:这一页默认不用设置

Step4:设置写FIFO 的 counter 计数器宽度5bit

4.3.6 CH0_FIFO_REQ/CH6_FIFO_REQ 模块

        //-------------------------数据缓存FIFO满状态标识-------------------------//

        always@(posedge ui_clk)

        begin

            CH0_REQ    <= (CH0_rusdw_o   >=PIXEL_H);//--大于等于一行可以读FIFO 写入DDR 这个参数可以调整         

            CH6_REQ    <= (CH6_wusdw_o   <=PIXEL_H);//--不满一行开始读DDR写入FIFO 这个参数可以调整--//

        end


CH0_REQ:这个模块中,信号在CH0_FIFO 缓存一行数据后有效  

CH6_REQ:这个模块中,当CH6_FIFO的数据小于一行开始读DDR并且写入。 

4.3.7 M_S 内存管理状态机

      //--包含sdram读测试/sdram写测试/sdram突发读/sdram突发写 模块--//

        always@(posedge ui_clk)

        begin

        if(!rst_tem[4])

                begin

                M_S           <=M_S_MSG_FIFO0;

                MSG_FIFO_RDEN <=1'd0;

                CH0_FIFO_RST  <=1'd0;

                CH6_FIFO_RST  <=1'd0;

                rst_FIFO_cnt  <=8'd0;

                count_rden    <=8'd0;

                count_wren    <=8'd0;    

                CH0_PTR       <=21'd0;

                CH6_PTR       <=21'd0;   

                CH0_Fbuf      <=7'd0;

                CH6_Fbuf      <=7'd0;

                end

        else case(M_S)

        //------------------------读取FIFO的控制信号-------------------------//

        M_S_MSG_FIFO0://--FIFO有数据就读取--//

            begin

            M_S             <=({MSG_FIFO_FULL,MSG_FIFO_USEDW}!=5'd0)?M_S_MSG_FIFO1:M_S_IDLE;

            MSG_FIFO_RDEN   <=({MSG_FIFO_FULL,MSG_FIFO_USEDW}!=5'd0);

            CH0_FIFO_RST    <=1'd0;

            CH6_FIFO_RST    <=1'd0;

            rst_FIFO_cnt    <=8'd0;

            count_rden      <=8'd0;

            count_wren      <=8'd0;

            end

            

        M_S_MSG_FIFO1://--延迟1个时钟--//

            begin

            M_S              <=M_S_MSG_FIFO2;

            MSG_FIFO_RDEN    <=1'd0;

            end

          

        M_S_MSG_FIFO2://--相对地址处理--//

            begin

            M_S                <=M_S_RST_FIFO0;

             //三缓存设计

              if(MSG_FIFO_RDDATA[7])begin

                 if(CH0_Fbuf == 2) begin

                     CH0_Fbuf <= 0;

                 end

                 else begin

                     CH0_Fbuf <= CH0_Fbuf + 1'b1;

                 end

                 CH0_PTR <= 21'd0;

              end

     

              if(MSG_FIFO_RDDATA[6])begin

                 if(CH0_Fbuf == 0) begin

                     CH6_Fbuf <= 2;

                 end

                 else begin

                     CH6_Fbuf <= CH0_Fbuf - 1'b1;

                 end

                 CH6_PTR <= 21'd0;

              end

               

            end

            

        //------------------------读取FIFO的控制信号-------------------------//

        M_S_RST_FIFO0:        

            begin

            M_S             <=(rst_FIFO_cnt>=8'd60)?M_S_IDLE:M_S;

            CH6_FIFO_RST    <=(rst_FIFO_cnt<=8'd20)&&MSG_FIFO_RDDATA[6];

            CH0_FIFO_RST    <=(rst_FIFO_cnt<=8'd20)&&MSG_FIFO_RDDATA[7];

            rst_FIFO_cnt    <=rst_FIFO_cnt+8'd1;

            end

            

        //-------------------------状态机空闲状态--------------------------//

        M_S_IDLE:            

            begin    

            count_rden        <=8'd0;

            count_wren        <=8'd0;

            casex    ({//-读写通道仲裁-//

                    CH0_REQ&&1'd1,//ch0_输入信道

                    1'b0,//ch1_预留信道

                    1'b0,//ch2_预留信道

                    1'b0,//ch3_预留信道

                    1'b0,//ch4_预留信道

                    1'b0,//ch5_预留信道

                    CH6_REQ&&1'd1//ch6_输出信道

                    })

            7'b1??????:    //-Sensor写数据-//    

                begin

                M_S          <=M_S_WR;

                end    

            7'b0000001:    //-vga读数据-//    

                begin

                M_S           <=M_S_RD;

                end

            default:        

                begin

                M_S           <=M_S_MSG_FIFO0;

                end    

            endcase

            end                    

        //-------------------------sdram读状态--------------------------//

        M_S_RD: //--读取数据--//        

            begin

            CH6_PTR         <= app_rdy ?(CH6_PTR+4'd8) : CH6_PTR ;//每次写入的数据地址

            M_S             <= app_rdy&&(count_rden==RD_BURST_LEN-1'b1)?M_S_MSG_FIFO0:M_S; //释放本次写权限   

            count_rden      <= app_rdy ? count_rden+1'd1:count_rden;//count_rden用来标记一次burst的数据量

            end

        //-------------------------sdram写状态--------------------------//

        M_S_WR://--写入数据--//            

            begin

            CH0_PTR         <= app_rdy&&app_wdf_rdy? (CH0_PTR+4'd8) : CH0_PTR ;//每次写入的数据地址

            M_S             <=app_rdy&&app_wdf_rdy&&(count_wren==WR_BURST_LEN-1'b1)?M_S_MSG_FIFO0:M_S;//释放本次写权限

            count_wren      <=app_rdy&&app_wdf_rdy ? count_wren+1'd1:count_wren;//count_wren用来标记一次burst的数据量

            end        

        default:                

            begin

            M_S              <=M_S_MSG_FIFO0;

            count_rden       <=8'd0;

            count_wren       <=8'd0;

            end    

        endcase                        

        end

M_S 状态机负责协调MIG 内存控制器以及各个模块之前的操作。

状态机里面笔者还设计了三缓存设计,当然笔者的设计最大可以支持128帧缓存,读者可以修改改进实现更多帧缓存。这样可以实现图像的延迟播放。

和三缓存相关的地址处理部分代码

assign    app_addr =(M_S==M_S_WR) ? ({CH0_Fbuf,CH0_PTR}) : ({CH6_Fbuf,CH6_PTR});

笔者这样设计可以非常方便地对缓存区域进行切换。

4.3.8 OV5640 寄存器配置文件

i2c_timing_ctrl.v

`timescale 1ns/1ns

module i2c_timing_ctrl

#(

parameter CLK_FREQ = 100_000_000, //100 MHz

parameter I2C_FREQ = 100_000 //10 KHz(< 400KHz)

)

(

//global clock

input clk, //100MHz

input rst_n, //system reset


//i2c interface

output i2c_sclk, //i2c clock

inout i2c_sdat, //i2c data for bidirection


//user interface

input [9:0] i2c_config_size, //i2c config data counte

output reg [9:0] i2c_config_index, //i2c config reg index, read 2 reg and write xx reg

input [31:0] i2c_config_data, //i2c config data

output i2c_config_done

);



//MMMMMMMMM 复位信号同步化 MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM

reg [4:0] RESETn=5'd31;

always@(posedge clk)//

RESETn <={RESETn[3:0],rst_n};//最终使用的同步信号是RESETn[4]




//----------------------------------------

//Delay xxus until i2c slave is steady

reg [16:0] delay_cnt;

localparam DELAY_TOP = CLK_FREQ/1000; //1ms Setting time after software/hardware reset

//localparam DELAY_TOP = 17'hff; //Just for test

always@(posedge clk)

begin

if(!RESETn[4])

delay_cnt <= 0;

else if(delay_cnt < DELAY_TOP)

delay_cnt <= delay_cnt + 1'b1;

else

delay_cnt <= delay_cnt;

end

wire delay_done = (delay_cnt == DELAY_TOP) ? 1'b1 : 1'b0; //81us delay



//----------------------------------------

//I2C Control Clock generate

reg [15:0] clk_cnt; //divide for i2c clock

/******************************************

 _______   _______

SCLK ____| |________|  |

 ________________ ______________

SDAT |________________|______________

 _               _

CLK_EN | |______________| |____________

    _     _

CAP_EN _______| |______________| |_____

*******************************************/

reg i2c_ctrl_clk; //i2c control clock, H: valid; L: valid

reg i2c_transfer_en; //send i2c data before, make sure that sdat is steady when i2c_sclk is valid

reg i2c_capture_en; //capture i2c data while sdat is steady from cmos

always@(posedge clk)

begin

if(!RESETn[4])

begin

clk_cnt <= 0;

i2c_ctrl_clk <= 0;

i2c_transfer_en <= 0;

i2c_capture_en <= 0;

end

else if(delay_done)

begin

if(clk_cnt < (CLK_FREQ/I2C_FREQ) - 1'b1)

clk_cnt <= clk_cnt + 1'd1;

else

clk_cnt <= 0;


//i2c control clock, H: valid; L: valid

i2c_ctrl_clk <= ((clk_cnt >= (CLK_FREQ/I2C_FREQ)/4 + 1'b1) &&

(clk_cnt < (3*CLK_FREQ/I2C_FREQ)/4 + 1'b1)) ? 1'b1 : 1'b0;

//send i2c data before, make sure that sdat is steady when i2c_sclk is valid

i2c_transfer_en <= (clk_cnt == 16'd0) ? 1'b1 : 1'b0;

//capture i2c data while sdat is steady from cmos

i2c_capture_en <= (clk_cnt == (2*CLK_FREQ/I2C_FREQ)/4 - 1'b1) ? 1'b1 : 1'b0;

end

else

begin

clk_cnt <= 0;

i2c_ctrl_clk <= 0;

i2c_transfer_en <= 0;

i2c_capture_en <= 0;

end

end


//-----------------------------------------

//I2C Timing state Parameter

localparam I2C_IDLE = 5'd0;

//Write I2C: {ID_Address, REG_Address+REG_Address2, W_REG_Data}

localparam I2C_WR_START = 5'd1;

localparam I2C_WR_IDADDR = 5'd2;

localparam I2C_WR_ACK1 = 5'd3;

localparam I2C_WR_REGADDR = 5'd4;

localparam I2C_WR_ACK2     = 5'd5;

localparam I2C_WR_REGADDR2 = 5'd6;

localparam I2C_WR_ACK2A    = 5'd7;

localparam I2C_WR_REGDATA = 5'd8;

localparam I2C_WR_ACK3 = 5'd9;

localparam I2C_WR_STOP = 5'd10;




//-----------------------------------------

// FSM: always1

reg [4:0] current_state, next_state; //i2c write and read state  

always@(posedge clk)

begin

if(!RESETn[4])

current_state <= I2C_IDLE;

else if(i2c_transfer_en)

current_state <= next_state;

end


//-----------------------------------------

wire i2c_transfer_end = (current_state == I2C_WR_STOP ) ? 1'b1 : 1'b0;

reg i2c_ack; //i2c slave renpose successed

always@(posedge clk)

begin

if(!RESETn[4])

i2c_config_index <= 0;

else if(i2c_transfer_en)

begin

if(i2c_transfer_end & ~i2c_ack)

// if(i2c_transfer_end /*& ~i2c_ack*/) //Just for test

begin

if(i2c_config_index < i2c_config_size)

i2c_config_index <= i2c_config_index + 1'b1;

// i2c_config_index <= {i2c_config_index[7:1], ~i2c_config_index[0]}; //Just for test

else

i2c_config_index <= i2c_config_size;

end

else

i2c_config_index <= i2c_config_index;

end

else

i2c_config_index <= i2c_config_index;

end

assign i2c_config_done = (i2c_config_index == i2c_config_size) ? 1'b1 : 1'b0;



//-----------------------------------------

// FSM: always2

reg [3:0] i2c_stream_cnt; //i2c data bit stream count

always@(*)

begin

next_state = I2C_IDLE; //state initialization

case(current_state)

I2C_IDLE: //5'd0

begin

if(delay_done) //1ms Setting time after software/hardware reset

begin

if(i2c_transfer_en)

begin

                if(i2c_config_index < i2c_config_size)

next_state = I2C_WR_START; //Write Data to I2C

else// if(i2c_config_index >= i2c_config_size)

next_state = I2C_IDLE; //Config I2C Complete

end

else

next_state = next_state;

end

else

next_state = I2C_IDLE; //Wait I2C Bus is steady

end

//Write I2C: {ID_Address, REG_Address, W_REG_Data}

I2C_WR_START: //5'd1

begin

if(i2c_transfer_en) next_state = I2C_WR_IDADDR;

else next_state = I2C_WR_START;

end

I2C_WR_IDADDR: //5'd2

if(i2c_transfer_en == 1'b1 && i2c_stream_cnt == 4'd8)

next_state = I2C_WR_ACK1;

else next_state = I2C_WR_IDADDR;

I2C_WR_ACK1: //5'd3

if(i2c_transfer_en) next_state = I2C_WR_REGADDR;

else next_state = I2C_WR_ACK1;

I2C_WR_REGADDR: //5'd4

if(i2c_transfer_en == 1'b1 && i2c_stream_cnt == 4'd8)

next_state = I2C_WR_ACK2;

else next_state = I2C_WR_REGADDR;

I2C_WR_ACK2: //5'd5

if(i2c_transfer_en) next_state = I2C_WR_REGADDR2;

else next_state = I2C_WR_ACK2;

I2C_WR_REGADDR2: //5'd6

if(i2c_transfer_en == 1'b1 && i2c_stream_cnt == 4'd8)

next_state = I2C_WR_ACK2A;

else next_state = I2C_WR_REGADDR2;

I2C_WR_ACK2A: //5'd7

if(i2c_transfer_en) next_state = I2C_WR_REGDATA;

else next_state = I2C_WR_ACK2A;

I2C_WR_REGDATA: //5'd8

if(i2c_transfer_en == 1'b1 && i2c_stream_cnt == 4'd8)

next_state = I2C_WR_ACK3;

else next_state = I2C_WR_REGDATA;

I2C_WR_ACK3: //5'd9

if(i2c_transfer_en) next_state = I2C_WR_STOP;

else next_state = I2C_WR_ACK3;

I2C_WR_STOP: //5'd10

if(i2c_transfer_en) next_state = I2C_IDLE;

else next_state = I2C_WR_STOP;

default:; //default vaule

endcase

end


//-----------------------------------------

// FSM: always3

//reg i2c_write_flag,  

reg i2c_sdat_out; //i2c data output

//reg [3:0] i2c_stream_cnt; //i2c data bit stream count

reg [7:0] i2c_wdata; //i2c data prepared to transfer

always@(posedge clk)

begin

if(!RESETn[4])

begin

i2c_sdat_out <= 1'b1;

i2c_stream_cnt <= 0;

i2c_wdata <= 0;

end

else if(i2c_transfer_en)

begin

case(next_state)

I2C_IDLE: //5'd0

begin

i2c_sdat_out <= 1'b1; //idle state

i2c_stream_cnt <= 0;

i2c_wdata <= 0;

end

//Write I2C: {ID_Address, REG_Address, W_REG_Data}

I2C_WR_START: //5'd1

begin

i2c_sdat_out <= 1'b0;

i2c_stream_cnt <= 0;

i2c_wdata <= i2c_config_data[31:24]; //ID_Address

end

I2C_WR_IDADDR: //5'd2

begin

i2c_stream_cnt <= i2c_stream_cnt + 1'b1;

i2c_sdat_out <= i2c_wdata[3'd7 - i2c_stream_cnt];

end

I2C_WR_ACK1: //5'd3

begin

i2c_stream_cnt <= 0;

i2c_wdata <= i2c_config_data[23:16]; //REG_Address

end

I2C_WR_REGADDR: //5'd4

begin

i2c_stream_cnt <= i2c_stream_cnt + 1'b1;

i2c_sdat_out <= i2c_wdata[3'd7 - i2c_stream_cnt];

end

I2C_WR_ACK2: //5'd5

begin

i2c_stream_cnt <= 0;

i2c_wdata <= i2c_config_data[15:8]; //REG_Address

end

I2C_WR_REGADDR2: //5'd6

begin

i2c_stream_cnt <= i2c_stream_cnt + 1'b1;

i2c_sdat_out <= i2c_wdata[3'd7 - i2c_stream_cnt];

end

I2C_WR_ACK2A: //5'd5

begin

i2c_stream_cnt <= 0;

i2c_wdata <= i2c_config_data[7:0]; //W_REG_Data

end

I2C_WR_REGDATA: //5'd6

begin

i2c_stream_cnt <= i2c_stream_cnt + 1'b1;

i2c_sdat_out <= i2c_wdata[3'd7 - i2c_stream_cnt];

end

I2C_WR_ACK3: //5'd7

i2c_stream_cnt <= 0;

I2C_WR_STOP: //5'd8

i2c_sdat_out <= 1'b0;

default:

            begin

            i2c_sdat_out <= 1'b1;

            i2c_stream_cnt <= 0;

            i2c_wdata <= 0;

            end

endcase

end

else

begin

i2c_stream_cnt <= i2c_stream_cnt;

i2c_sdat_out <= i2c_sdat_out;

end

end


//---------------------------------------------

//respone from slave for i2c data transfer

reg i2c_ack1, i2c_ack2, i2c_ack3,i2c_ack2a;

//reg i2c_ack;

//reg [7:0] i2c_rdata;

always@(posedge clk)

begin

if(!RESETn[4])

begin

{i2c_ack1, i2c_ack2, i2c_ack3,i2c_ack2a} <= 4'b1111;

i2c_ack <= 1'b1;


end

else if(i2c_capture_en)

begin

case(next_state)

I2C_IDLE:

begin

{i2c_ack1, i2c_ack2, i2c_ack3,i2c_ack2a} <= 4'b1111;

i2c_ack <= 1'b1;

end

//Write I2C: {ID_Address, REG_Address, W_REG_Data}

I2C_WR_ACK1: i2c_ack1 <= i2c_sdat;

I2C_WR_ACK2: i2c_ack2 <= i2c_sdat;

I2C_WR_ACK2A: i2c_ack2a <= i2c_sdat;

I2C_WR_ACK3: i2c_ack3 <= i2c_sdat;

I2C_WR_STOP: i2c_ack <= (i2c_ack1 | i2c_ack2 | i2c_ack3|i2c_ack2a);

endcase

end

else

begin

{i2c_ack1, i2c_ack2, i2c_ack3,i2c_ack2a} <= {i2c_ack1, i2c_ack2, i2c_ack3,i2c_ack2a};

i2c_ack <= i2c_ack;

end

end


//---------------------------------------------------

wire bir_en =   (current_state == I2C_WR_ACK1 || current_state == I2C_WR_ACK2 ||

                     current_state == I2C_WR_ACK2A ||current_state == I2C_WR_ACK3 ) ? 1'b1 : 1'b0;

assign i2c_sclk = (current_state >= I2C_WR_IDADDR && current_state <= I2C_WR_ACK3)?i2c_ctrl_clk : 1'b1;

assign i2c_sdat = (~bir_en) ? i2c_sdat_out : 1'bz;


endmodule


I2C_OV5640_RGB565_Config

`timescale 1ns/1ns

module I2C_OV5640_RGB565_Config

(

input [9:0] LUT_INDEX,

output reg [23:0] LUT_DATA,

output [9:0] LUT_SIZE

);


assign LUT_SIZE = 10'd253;


//-----------------------------------------------------------------

///////////////////// Config Data LUT   //////////////////////////

always@(*)

begin

case(LUT_INDEX)

   0:         LUT_DATA<=24'h310311;// system clock from pad, bit[1]

 1:         LUT_DATA<=24'h300882;// software reset, bit[7]// delay 5ms

 2:         LUT_DATA<=24'h300842;// software power down, bit[6]

 3:         LUT_DATA<=24'h310303;// system clock from PLL, bit[1]

 4:         LUT_DATA<=24'h3017ff;// FREX, Vsync, HREF, PCLK, D[9:6] output enable

 5:         LUT_DATA<=24'h3018ff;// D[5:0], GPIO[1:0] output enable

 6:         LUT_DATA<=24'h30341A;// MIPI 10-bit

 7:         LUT_DATA<=24'h303713;// PLL root divider, bit[4], PLL pre-divider, bit[3:0]

 8:         LUT_DATA<=24'h310801;// PCLK root divider, bit[5:4], SCLK2x root divider, bit[3:2] // SCLK root divider, bit[1:0]

 9:         LUT_DATA<=24'h363036;

 10:        LUT_DATA<=24'h36310e;

 11:        LUT_DATA<=24'h3632e2;

 12:        LUT_DATA<=24'h363312;

 13:        LUT_DATA<=24'h3621e0;

 14:        LUT_DATA<=24'h3704a0;

 15:        LUT_DATA<=24'h37035a;

 16:        LUT_DATA<=24'h371578;

 17:        LUT_DATA<=24'h371701;

 18:        LUT_DATA<=24'h370b60;

 19:        LUT_DATA<=24'h37051a;

 20:        LUT_DATA<=24'h390502;

 21:        LUT_DATA<=24'h390610;

 22:        LUT_DATA<=24'h39010a;

 23:        LUT_DATA<=24'h373112;

 24:        LUT_DATA<=24'h360008;// VCM control

 25:        LUT_DATA<=24'h360133;// VCM control

 26:        LUT_DATA<=24'h302d60;// system control

 27:        LUT_DATA<=24'h362052;

 28:        LUT_DATA<=24'h371b20;

 29:        LUT_DATA<=24'h471c50;

 30:        LUT_DATA<=24'h3a1343;// pre-gain = 1.047x

 31:        LUT_DATA<=24'h3a1800;// gain ceiling

 32:        LUT_DATA<=24'h3a19f8;// gain ceiling = 15.5x

 33:        LUT_DATA<=24'h363513;

 34:        LUT_DATA<=24'h363603;

 35:        LUT_DATA<=24'h363440;

 36:        LUT_DATA<=24'h362201; // 50/60Hz detection     50/60Hz

 37:        LUT_DATA<=24'h3c0134;// Band auto, bit[7]

 38:        LUT_DATA<=24'h3c0428;// threshold low sum  

 39:        LUT_DATA<=24'h3c0598;// threshold high sum

 40:        LUT_DATA<=24'h3c0600;// light meter 1 threshold[15:8]

 41:        LUT_DATA<=24'h3c0708;// light meter 1 threshold[7:0]

 42:        LUT_DATA<=24'h3c0800;// light meter 2 threshold[15:8]

 43:        LUT_DATA<=24'h3c091c;// light meter 2 threshold[7:0]

 44:        LUT_DATA<=24'h3c0a9c;// sample number[15:8]

 45:        LUT_DATA<=24'h3c0b40;// sample number[7:0]

 46:        LUT_DATA<=24'h381000;// Timing Hoffset[11:8]

 47:        LUT_DATA<=24'h381110;// Timing Hoffset[7:0]

 48:        LUT_DATA<=24'h381200;// Timing Voffset[10:8]

 49:        LUT_DATA<=24'h370864;

 50:        LUT_DATA<=24'h400102;// BLC start from line 2

 51:        LUT_DATA<=24'h40051a;// BLC always update

 52:        LUT_DATA<=24'h300000;// enable blocks

 53:        LUT_DATA<=24'h3004ff;// enable clocks

 54:        LUT_DATA<=24'h300e58;// MIPI power down, DVP enable

 55:        LUT_DATA<=24'h302e00;

 56:        LUT_DATA<=24'h430060;// RGB565

 57:        LUT_DATA<=24'h501f01;// ISP RGB

 58:        LUT_DATA<=24'h440e00;

 59:        LUT_DATA<=24'h5000a7; // Lenc on, raw gamma on, BPC on, WPC on, CIP on // AEC target    

 60:        LUT_DATA<=24'h3a0f30;// stable range in high

 61:        LUT_DATA<=24'h3a1028;// stable range in low

 62:        LUT_DATA<=24'h3a1b30;// stable range out high

 63:        LUT_DATA<=24'h3a1e26;// stable range out low

 64:        LUT_DATA<=24'h3a1160;// fast zone high

 65:        LUT_DATA<=24'h3a1f14;// fast zone low// Lens correction for

 66:        LUT_DATA<=24'h580023;

 67:        LUT_DATA<=24'h580114;

 68:        LUT_DATA<=24'h58020f;

 69:        LUT_DATA<=24'h58030f;

 70:        LUT_DATA<=24'h580412;

 71:        LUT_DATA<=24'h580526;

 72:        LUT_DATA<=24'h58060c;

 73:        LUT_DATA<=24'h580708;

 74:        LUT_DATA<=24'h580805;

 75:        LUT_DATA<=24'h580905;

 76:        LUT_DATA<=24'h580a08;

 77:        LUT_DATA<=24'h580b0d;

 78:        LUT_DATA<=24'h580c08;

 79:        LUT_DATA<=24'h580d03;

 80:        LUT_DATA<=24'h580e00;

 81:        LUT_DATA<=24'h580f00;

 82:        LUT_DATA<=24'h581003;

 83:        LUT_DATA<=24'h581109;

 84:        LUT_DATA<=24'h581207;

 85:        LUT_DATA<=24'h581303;

 86:        LUT_DATA<=24'h581400;

 87:        LUT_DATA<=24'h581501;

 88:        LUT_DATA<=24'h581603;

 89:        LUT_DATA<=24'h581708;

 90:        LUT_DATA<=24'h58180d;

 91:        LUT_DATA<=24'h581908;

 92:        LUT_DATA<=24'h581a05;

 93:        LUT_DATA<=24'h581b06;

 94:        LUT_DATA<=24'h581c08;

 95:        LUT_DATA<=24'h581d0e;

 96:        LUT_DATA<=24'h581e29;

 97:        LUT_DATA<=24'h581f17;

 98:        LUT_DATA<=24'h582011;

 99:        LUT_DATA<=24'h582111;

 100:       LUT_DATA<=24'h582215;

 101:       LUT_DATA<=24'h582328;

 102:       LUT_DATA<=24'h582446;

 103:       LUT_DATA<=24'h582526;

 104:       LUT_DATA<=24'h582608;

 105:       LUT_DATA<=24'h582726;

 106:       LUT_DATA<=24'h582864;

 107:       LUT_DATA<=24'h582926;

 108:       LUT_DATA<=24'h582a24;

 109:       LUT_DATA<=24'h582b22;

 110:       LUT_DATA<=24'h582c24;

 111:       LUT_DATA<=24'h582d24;

 112:       LUT_DATA<=24'h582e06;

 113:       LUT_DATA<=24'h582f22;

 114:       LUT_DATA<=24'h583040;

 115:       LUT_DATA<=24'h583142;

 116:       LUT_DATA<=24'h583224;

 117:       LUT_DATA<=24'h583326;

 118:       LUT_DATA<=24'h583424;

 119:       LUT_DATA<=24'h583522;

 120:       LUT_DATA<=24'h583622;

 121:       LUT_DATA<=24'h583726;

 122:       LUT_DATA<=24'h583844;

 123:       LUT_DATA<=24'h583924;

 124:       LUT_DATA<=24'h583a26;

 125:       LUT_DATA<=24'h583b28;

 126:       LUT_DATA<=24'h583c42;

 127:       LUT_DATA<=24'h583dce;// lenc BR offset // AWB    

 128:       LUT_DATA<=24'h5180ff;// AWB B block

 129:       LUT_DATA<=24'h5181f2;// AWB control

 130:       LUT_DATA<=24'h518200;// [7:4] max local counter, [3:0] max fast counter

 131:       LUT_DATA<=24'h518314;// AWB advanced

 132:       LUT_DATA<=24'h518425;

 133:       LUT_DATA<=24'h518524;

 134:       LUT_DATA<=24'h518609;

 135:       LUT_DATA<=24'h518709;

 136:       LUT_DATA<=24'h518809;

 137:       LUT_DATA<=24'h518975;

 138:       LUT_DATA<=24'h518a54;

 139:       LUT_DATA<=24'h518be0;

 140:       LUT_DATA<=24'h518cb2;

 141:       LUT_DATA<=24'h518d42;

 142:       LUT_DATA<=24'h518e3d;

 143:       LUT_DATA<=24'h518f56;

 144:       LUT_DATA<=24'h519046;

 145:       LUT_DATA<=24'h5191f8;// AWB top limit

 146:       LUT_DATA<=24'h519204;// AWB bottom limit

 147:       LUT_DATA<=24'h519370;// red limit

 148:       LUT_DATA<=24'h5194f0;// green limit

 149:       LUT_DATA<=24'h5195f0;// blue limit

 150:       LUT_DATA<=24'h519603;// AWB control

 151:       LUT_DATA<=24'h519701;// local limit

 152:       LUT_DATA<=24'h519804;

 153:       LUT_DATA<=24'h519912;

 154:       LUT_DATA<=24'h519a04;

 155:       LUT_DATA<=24'h519b00;

 156:       LUT_DATA<=24'h519c06;

 157:       LUT_DATA<=24'h519d82;

 158:       LUT_DATA<=24'h519e38;// AWB control // Gamma  

 159:       LUT_DATA<=24'h548001;// Gamma bias plus on, bit[0]

 160:       LUT_DATA<=24'h548108;

 161:       LUT_DATA<=24'h548214;

 162:       LUT_DATA<=24'h548328;

 163:       LUT_DATA<=24'h548451;

 164:       LUT_DATA<=24'h548565;

 165:       LUT_DATA<=24'h548671;

 166:       LUT_DATA<=24'h54877d;

 167:       LUT_DATA<=24'h548887;

 168:       LUT_DATA<=24'h548991;

 169:       LUT_DATA<=24'h548a9a;

 170:       LUT_DATA<=24'h548baa;

 171:       LUT_DATA<=24'h548cb8;

 172:       LUT_DATA<=24'h548dcd;

 173:       LUT_DATA<=24'h548edd;

 174:       LUT_DATA<=24'h548fea;

 175:       LUT_DATA<=24'h54901d;// color matrix    

 176:       LUT_DATA<=24'h53811e;// CMX1 for Y

 177:       LUT_DATA<=24'h53825b;// CMX2 for Y

 178:       LUT_DATA<=24'h538308;// CMX3 for Y

 179:       LUT_DATA<=24'h53840a;// CMX4 for U

 180:       LUT_DATA<=24'h53857e;// CMX5 for U

 181:       LUT_DATA<=24'h538688;// CMX6 for U

 182:       LUT_DATA<=24'h53877c;// CMX7 for V

 183:       LUT_DATA<=24'h53886c;// CMX8 for V

 184:       LUT_DATA<=24'h538910;// CMX9 for V

 185:       LUT_DATA<=24'h538a01;// sign[9]

 186:       LUT_DATA<=24'h538b98; // sign[8:1] // UV adjust   UV

 187:       LUT_DATA<=24'h558006;// saturation on, bit[1]

 188:       LUT_DATA<=24'h558340;

 189:       LUT_DATA<=24'h558410;

 190:       LUT_DATA<=24'h558910;

 191:       LUT_DATA<=24'h558a00;

 192:       LUT_DATA<=24'h558bf8;

 193:       LUT_DATA<=24'h501d40;// enable manual offset of contrast// CIP   

 194:       LUT_DATA<=24'h530008;// CIP sharpen MT threshold 1

 195:       LUT_DATA<=24'h530130;// CIP sharpen MT threshold 2

 196:       LUT_DATA<=24'h530210;// CIP sharpen MT offset 1

 197:       LUT_DATA<=24'h530300;// CIP sharpen MT offset 2

 198:       LUT_DATA<=24'h530408;// CIP DNS threshold 1

 199:       LUT_DATA<=24'h530530;// CIP DNS threshold 2

 200:       LUT_DATA<=24'h530608;// CIP DNS offset 1

 201:       LUT_DATA<=24'h530716;// CIP DNS offset 2

 202:       LUT_DATA<=24'h530908;// CIP sharpen TH threshold 1

 203:       LUT_DATA<=24'h530a30;// CIP sharpen TH threshold 2

 204:       LUT_DATA<=24'h530b04;// CIP sharpen TH offset 1

 205:       LUT_DATA<=24'h530c06;// CIP sharpen TH offset 2

 206:       LUT_DATA<=24'h502500;

 207:       LUT_DATA<=24'h300802; // wake up from standby, bit[6]

 //680x480 30帧/秒, night mode 5fps, input clock =24Mhz, PCLK =56M

 //set OV5640 to video mode 720p

 208:       LUT_DATA<=24'h303541;// PLL     input clock =24Mhz, PCLK =84Mhz 21

 209:       LUT_DATA<=24'h303669;// PLL

 210:       LUT_DATA<=24'h3c0707; // lightmeter 1 threshold[7:0]

 211:       LUT_DATA<=24'h382045; // flip

 212:       LUT_DATA<=24'h382103; // mirror

 213:       LUT_DATA<=24'h381431; // timing X inc

 214:       LUT_DATA<=24'h381531; // timing Y inc

 215:       LUT_DATA<=24'h380000; // HS

 216:       LUT_DATA<=24'h380100; // HS

 217:       LUT_DATA<=24'h380200; // VS

 218:       LUT_DATA<=24'h3803fa; // VS

 219:       LUT_DATA<=24'h38040a; // HW (HE)

 220:       LUT_DATA<=24'h38053f; // HW (HE)

 221:       LUT_DATA<=24'h380606; // VH (VE)

 222:       LUT_DATA<=24'h3807a9; // VH (VE)

 223:       LUT_DATA<=24'h380805; // DVPHO     (1280)

 224:       LUT_DATA<=24'h380900; // DVPHO     (1280)

 225:       LUT_DATA<=24'h380a02; // DVPVO     (720)

 226:       LUT_DATA<=24'h380bd0; // DVPVO     (720)

 227:       LUT_DATA<=24'h380c07; // HTS

 228:       LUT_DATA<=24'h380d64; // HTS

 229:       LUT_DATA<=24'h380e02; // VTS

 230:       LUT_DATA<=24'h380fe4; // VTS

 231:       LUT_DATA<=24'h381304; // timing V offset

 232:       LUT_DATA<=24'h361800;

 233:       LUT_DATA<=24'h361229;

 234:       LUT_DATA<=24'h370952;

 235:       LUT_DATA<=24'h370c03;

 236:       LUT_DATA<=24'h3a0202; // 60Hz max exposure

 237:       LUT_DATA<=24'h3a03e0; // 60Hz max exposure

 238:       LUT_DATA<=24'h3a1402; // 50Hz max exposure

 239:       LUT_DATA<=24'h3a15e0; // 50Hz max exposure

 240:       LUT_DATA<=24'h400402; // BLC line number

 241:       LUT_DATA<=24'h30021c; // reset JFIFO, SFIFO, JPG

 242:       LUT_DATA<=24'h3006c3; // disable clock of JPEG2x, JPEG

 243:       LUT_DATA<=24'h471303; // JPEG mode 3

 244:       LUT_DATA<=24'h440704; // Quantization sacle

 245:       LUT_DATA<=24'h460b37;

 246:       LUT_DATA<=24'h460c20;

 247:       LUT_DATA<=24'h483716; // MIPI global timing

 248:       LUT_DATA<=24'h382404; // PCLK manual divider

 249:       LUT_DATA<=24'h500183; // SDE on, CMX on, AWB on

 250:       LUT_DATA<=24'h350300; // AEC/AGC on

//  300:       LUT_DATA<=24'h301602; //Strobe output enable

//  301:       LUT_DATA<=24'h3b070a; //FREX strobe mode1

 //st       robe flash and frame exposure  

 251:       LUT_DATA<=24'h3b0083;              //STROBE CTRL: strobe request ON, Strobe mode: LED3

 252:       LUT_DATA<=24'h3b0000;              //STROBE CTRL: strobe request OFF


 //300:LUT_DATA<=24'h503d82;            //LUT_DATA<=24'h503d80; test pattern selection control, 80:color bar,00: test disable

 //301:LUT_DATA<=24'h474101;            //LUT_DATA<=24'h47401; test pattern enable, Test pattern 8-bit  

 default:   LUT_DATA<=24'h000000;

endcase

end


endmodule

4.4 增加现在逻辑分析仪和被调试信号

ila_0 debug_inst0 (

 .clk(ui_clk), // input wire clk  

 .probe0(CH0_data_o), // input wire [255:0]  probe0    

 .probe1(CH6_data_i), // input wire [31:0]  probe1

.probe2(CH6_wren_i),  

 .probe3(app_en),  

 .probe4(CH0_rusdw_o[6:0]),  

 .probe5(app_wdf_rdy),  

 .probe6(app_wdf_wren),  

 .probe7(count_wren[6:0]),  

 .probe8(app_rdy),  

 .probe9(count_rden[6:0]),  

 .probe10(M_S)

);  


ila_1 debug_inst1 (  

 .clk(CH6_rclk_i), // input wire clk  

 .probe0(CH6_data_o), // input wire [31:0]  probe0    

 .probe1(CH6_rden_i), // input wire [0:0]  probe1  

 .probe2(CH6_FS_i) // input wire [0:0]  probe1

);


ila_2 sensor_sg (  

 .clk(cmos_pclk_i), // input wire clk  

 .probe0(vs_o), // input wire [0:0]  probe0    

 .probe1(hs_o), // input wire [0:0]  probe1   

 .probe2(clk_ce), // input wire [0:0]  probe2   

 .probe3(vcounter[9:0]), // input wire [0:0]  probe3   

 .probe4(grid_data_2), // input wire [0:0]  probe4   

 .probe5(hcounter[10:0])

);

       笔者认为只要观察如上信号就可以观察整个内存管理的信号设计是否正确。ILA 的使用不在这 里讲解了,读者如果是初学者不会的可以到前面的章节找寻找相关内容。

4.5.1 在线仿真波形

图 4-5-2-1 数据

       这里笔者只给出 OV5640 部分添加测试代码和数据的部分,至于 M_S 内存管理部分,前面做下来已经很稳定了,不再累述。当然笔者的每一步都不是这么顺利,中间都是经过了很多次调试才达到 了设计结果,读者学习过程务必要理解笔者的设计思路而不是一味追求结果。 

4.5.2 测试输出接口

4.5.4 修改代码从OV5640 取 RGB 数据

之前在调试过程中用的测试数据,现在改为从摄像头获取的数据

assign rgb_o = {rgb565[4:0],3'd0 ,rgb565[10:5] ,2'd0,rgb565[15:11],3'd0};  //assign rgb_o = {grid_data_2,grid_data_2,grid_data_2};  

assign clk_ce =out_en? byte_flag_r0:1'b0;  

assign vs_o = out_en ? vsync_d[1] : 1'b0;  

assign hs_o = out_en ? href_d[1] : 1'b0;

4.5.5 测试输出结果

1

路过

雷人

握手

鲜花

鸡蛋

刚表态过的朋友 (1 人)

说点什么...

已有0条评论

最新评论...

本文作者
2019-10-17 16:47
  • 6
    粉丝
  • 557
    阅读
  • 0
    回复

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B
热门评论
排行榜

关注我们:微信公众号

官方微信

官方微信

客服热线:

0519-80699907

公司地址:常州溧阳市天目云谷3号楼北楼2楼

运营中心:常州溧阳市天目云谷3号楼北楼2楼

邮编:213300 Email:270682667#qq.com

Copyright   ©2019-2026  米联客uisrc内容版权归©UISRC.COM技术支持:UISRC.COM  备案号:苏ICP备19046771号