xianyufpga

  上电之后要做的是通过 SCCB 协议对摄像头的寄存器进行配置,在之前的博客中详细介绍过 SCCB 协议的基本原理以及和 IIC 协议的区别。经过半年后,在正点原子的 SCCB 配置寄存器的基础上,我进行了小小的改动,使得代码更加简洁易懂。

一、SCCB协议编写

  SCCB协议的介绍见之前的博客《协议——SCCB与IIC的区别》,此处不再赘述。之前的 SCCB 协议需要在端口进行 8 位地址和16位地址的选择,这次我把选择开关删了,改为内部代码判断,端口更加简洁了。

1、端口例化

//SCCB寄存器配置
//---------------------------------------------------
sccb_ov5640_cfg u_sccb_ov5640_cfg
(
    .clk                    (sccb_dri_clk           ),
    .rst_n                  (rst_n                  ),
    .sccb_vld                (sccb_vld                ), //SCCB配置有效信号
    .sccb_done              (sccb_done              ), //SCCB配置一次结束
    .sccb_en                (sccb_en                ),
    .sccb_data              (sccb_data              ),
    .sccb_cfg_done          (sccb_cfg_done          )  //SCCB配置全部结束
);

//SCCB时序驱动
//---------------------------------------------------
sccb 
#(
    .DEVICE_ID              (8\'h78                  ), //器件ID
    .CLK                    (26\'d24_000_000         ), //24Mhz   
    .SCL                    (18\'d250_000            )  //250Khz
)
u_sccb
(       
    .clk                    (cmos_xclk              ),   
    .rst_n                  (rst_n                  ),
    //SCCB input ------------------------------------
    .sccb_en                (sccb_en                ),
    .sccb_addr              (sccb_data[23:8]        ),  
    .sccb_data              (sccb_data[7:0]         ),
    //SCCB output -----------------------------------
    .sccb_done              (sccb_done              ),   
    .sccb_scl               (cmos_scl               ),
    .sccb_sda               (cmos_sda               ),
    //dri_clk ---------------------------------------
    .sccb_dri_clk           (sccb_dri_clk           )  //1Mhz
);

  OV7670 和 OV7725 的写 ID 都是 8\'h42,而 OV5640 的写 ID 为 8\'h78,这些都可以在各自的 datasheet 中查到,没什么说的。

  SCCB协议的 SCL 要求不高于400Khz,我们设置为 250Khz,通过例化模块的参数传递可以直接更改这些信息,对于 sccb 代码内部不必再更改,方便移植。

  sccb_start信号为开始配置标志,在上一讲博客中设计得到。sccb_en、sccb_data、sccb_done、sccb_dri_clk 都是和 sccb_cfg 模块进行交互的信号,其中 sccb_dri_clk 是 sccb_cfg 模块的时钟驱动信号。而 cmos_scl 和 cmos_sda 则是要输出到端口的信号。sccb_cfg_done 信号表示所有寄存器都配置完成,这个信号可以给之后的图像获取模块 cmos_capture 使用。

 

2、sccb 代码

//**************************************************************************
// *** 名称 : sccb.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2019-08-10
// *** 描述 : SCCB控制器,只支持写
//**************************************************************************

module sccb
//========================< 参数 >==========================================
#(
parameter DEVICE_ID         = 8\'b01010000           , //器件ID
parameter CLK               = 26\'d50_000_000        , //本模块的时钟频率
parameter SCL               = 18\'d250_000             //输出的SCL时钟频率
)
//========================< 端口 >==========================================
(
input   wire                clk                     , //时钟
input   wire                rst_n                   , //复位,低电平有效
//SCCB input ---------------------------------------- 
input   wire                sccb_en                 , //SCCB触发信号
input   wire    [15:0]      sccb_addr               , //SCCB器件内地址
input   wire    [ 7:0]      sccb_data               , //SCCB要写的数据
//SCCB output --------------------------------------- 
output  reg                 sccb_done               , //SCCB一次操作完成
output  reg                 sccb_scl                , //SCCB的SCL时钟信号
inout   wire                sccb_sda                , //SCCB的SDA数据信号
//dri_clk ------------------------------------------- 
output  reg                 sccb_dri_clk              //驱动SCCB操作的驱动时钟,1Mhz
);
//========================< 状态机参数 >====================================
localparam  IDLE            = 6\'b00_0001            ; //空闲状态
localparam  DEVICE          = 6\'b00_0010            ; //写器件地址
localparam  ADDR_16         = 6\'b00_0100            ; //写字地址高8位
localparam  ADDR_8          = 6\'b00_1000            ; //写字地址低8位
localparam  DATA            = 6\'b01_0000            ; //写数据
localparam  STOP            = 6\'b10_0000            ; //结束
//========================< 信号 >==========================================
reg                         sda_dir                 ; //SCCB数据(SDA)方向控制
reg                         sda_out                 ; //SDA输出信号
reg                         state_done              ; //状态结束
reg    [ 6:0]               cnt                     ; //计数
reg    [ 7:0]               state_c                 ; //状态机当前状态
reg    [ 7:0]               state_n                 ; //状态机下一状态
reg    [15:0]               sccb_addr_t             ; //地址寄存
reg    [ 7:0]               sccb_data_t             ; //数据寄存
reg    [ 9:0]               clk_cnt                 ; //分频时钟计数
wire   [ 8:0]               clk_divide              ; //模块驱动时钟的分频系数
//==========================================================================
//==    SDA数据输出或高阻
//==========================================================================
assign  sccb_sda = sda_dir ?  sda_out : 1\'bz;         
//==========================================================================
//==     生成SCL的4倍时钟来驱动后面SCCB的操作,生成1Mhz的sccb_dri_clk
//==========================================================================
assign  clk_divide = (CLK/SCL) >> 3; //>>3即除以8

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        sccb_dri_clk <=  1\'b1;
        clk_cnt <= 10\'d0;
    end
    else if(clk_cnt == clk_divide - 1\'d1) begin
        clk_cnt <= 10\'d0;
        sccb_dri_clk <= ~sccb_dri_clk;
    end
    else
        clk_cnt <= clk_cnt + 1\'b1;
end
//==========================================================================
//==    状态机
//==========================================================================
always @(posedge sccb_dri_clk or negedge rst_n) begin
    if(!rst_n)
        state_c <= IDLE;
    else
        state_c <= state_n;
end

always @(*) begin
    case(state_c)
        IDLE: begin                             //空闲状态
           if(sccb_en)
               state_n = DEVICE;
           else
               state_n = IDLE;
        end
        DEVICE: begin                           //写器件ID
            if(state_done) begin
                if(sccb_addr[15:8]!=0)
                   state_n = ADDR_16;
                else if(sccb_addr[15:8]==0)
                   state_n = ADDR_8 ;
            end
            else
                state_n = DEVICE;
        end
        ADDR_16: begin                          //写地址高8位
            if(state_done)
                state_n = ADDR_8;
            else
                state_n = ADDR_16;
        end
        ADDR_8: begin                           //写地址低8位
            if(state_done)
                state_n = DATA;
            else
                state_n = ADDR_8;
        end
        DATA: begin                             //写数据
            if(state_done)
                state_n = STOP;
            else
                state_n = DATA;
        end
        STOP: begin                             //结束
            if(state_done)
                state_n = IDLE;
            else
                state_n = STOP ;
        end
        default:state_n= IDLE;
    endcase
end
//==========================================================================
//==    设计各路信号
//==========================================================================
always @(posedge sccb_dri_clk or negedge rst_n) begin
    if(!rst_n) begin
        sccb_scl    <= 1\'b1;
        sda_out     <= 1\'b1;
        sda_dir     <= 1\'b1;
        sccb_done   <= 1\'b0;
        cnt         <= 1\'b0;
        state_done  <= 1\'b0;
        sccb_addr_t <= 1\'b0;
        sccb_data_t <= 1\'b0;
    end
    else begin
        state_done  <= 1\'b0;
        cnt         <= cnt + 1\'b1;
        case(state_c)
            //--------------------------------------------------- 空闲状态
            IDLE: begin
                    sccb_scl  <= 1\'b1;
                    sda_out   <= 1\'b1;
                    sda_dir   <= 1\'b1;
                    sccb_done <= 1\'b0;
                    cnt       <= 7\'b0;
                    if(sccb_en) begin
                        sccb_addr_t <= sccb_addr;
                        sccb_data_t <= sccb_data;
                    end
            end
            //--------------------------------------------------- 写器件ID
            DEVICE: begin
                case(cnt)
                    7\'d1 : sda_out  <= 1\'b0;
                    7\'d3 : sccb_scl <= 1\'b0;
                    7\'d4 : sda_out  <= DEVICE_ID[7];
                    7\'d5 : sccb_scl <= 1\'b1;
                    7\'d7 : sccb_scl <= 1\'b0;
                    7\'d8 : sda_out  <= DEVICE_ID[6];
                    7\'d9 : sccb_scl <= 1\'b1;
                    7\'d11: sccb_scl <= 1\'b0;
                    7\'d12: sda_out  <= DEVICE_ID[5];
                    7\'d13: sccb_scl <= 1\'b1;
                    7\'d15: sccb_scl <= 1\'b0;
                    7\'d16: sda_out  <= DEVICE_ID[4];
                    7\'d17: sccb_scl <= 1\'b1;
                    7\'d19: sccb_scl <= 1\'b0;
                    7\'d20: sda_out  <= DEVICE_ID[3];
                    7\'d21: sccb_scl <= 1\'b1;
                    7\'d23: sccb_scl <= 1\'b0;
                    7\'d24: sda_out  <= DEVICE_ID[2];
                    7\'d25: sccb_scl <= 1\'b1;
                    7\'d27: sccb_scl <= 1\'b0;
                    7\'d28: sda_out  <= DEVICE_ID[1];
                    7\'d29: sccb_scl <= 1\'b1;
                    7\'d31: sccb_scl <= 1\'b0;
                    7\'d32: sda_out  <= DEVICE_ID[0];
                    7\'d33: sccb_scl <= 1\'b1;
                    7\'d35: sccb_scl <= 1\'b0;
                    7\'d36: begin
                           sda_dir  <= 1\'b0;    //从机应答
                           sda_out  <= 1\'b1;
                    end
                    7\'d37: sccb_scl <= 1\'b1;
                    7\'d38: state_done <= 1\'b1;  //状态结束
                    7\'d39: begin
                           sccb_scl <= 1\'b0;
                           cnt <= 1\'b0;
                    end
                    default:;
                endcase
            end
            //--------------------------------------------------- 写字地址高8位
            ADDR_16: begin
                case(cnt)
                    7\'d0 : begin
                           sda_dir  <= 1\'b1 ;
                           sda_out  <= sccb_addr_t[15];
                    end
                    7\'d1 : sccb_scl <= 1\'b1;
                    7\'d3 : sccb_scl <= 1\'b0;
                    7\'d4 : sda_out  <= sccb_addr_t[14];
                    7\'d5 : sccb_scl <= 1\'b1;
                    7\'d7 : sccb_scl <= 1\'b0;
                    7\'d8 : sda_out  <= sccb_addr_t[13];
                    7\'d9 : sccb_scl <= 1\'b1;
                    7\'d11: sccb_scl <= 1\'b0;
                    7\'d12: sda_out  <= sccb_addr_t[12];
                    7\'d13: sccb_scl <= 1\'b1;
                    7\'d15: sccb_scl <= 1\'b0;
                    7\'d16: sda_out  <= sccb_addr_t[11];
                    7\'d17: sccb_scl <= 1\'b1;
                    7\'d19: sccb_scl <= 1\'b0;
                    7\'d20: sda_out  <= sccb_addr_t[10];
                    7\'d21: sccb_scl <= 1\'b1;
                    7\'d23: sccb_scl <= 1\'b0;
                    7\'d24: sda_out  <= sccb_addr_t[9];
                    7\'d25: sccb_scl <= 1\'b1;
                    7\'d27: sccb_scl <= 1\'b0;
                    7\'d28: sda_out  <= sccb_addr_t[8];
                    7\'d29: sccb_scl <= 1\'b1;
                    7\'d31: sccb_scl <= 1\'b0;
                    7\'d32: begin
                           sda_dir  <= 1\'b0;    //从机应答
                           sda_out  <= 1\'b1;
                    end
                    7\'d33: sccb_scl <= 1\'b1;
                    7\'d34: state_done <= 1\'b1;  //状态结束
                    7\'d35: begin
                           sccb_scl <= 1\'b0;
                           cnt <= 1\'b0;
                    end
                    default:;
                endcase
            end
            //--------------------------------------------------- 写字地址低8位
            ADDR_8: begin
                case(cnt)
                    7\'d0: begin
                           sda_dir  <= 1\'b1 ;
                           sda_out  <= sccb_addr_t[7];
                    end
                    7\'d1 : sccb_scl <= 1\'b1;
                    7\'d3 : sccb_scl <= 1\'b0;
                    7\'d4 : sda_out  <= sccb_addr_t[6];
                    7\'d5 : sccb_scl <= 1\'b1;
                    7\'d7 : sccb_scl <= 1\'b0;
                    7\'d8 : sda_out  <= sccb_addr_t[5];
                    7\'d9 : sccb_scl <= 1\'b1;
                    7\'d11: sccb_scl <= 1\'b0;
                    7\'d12: sda_out  <= sccb_addr_t[4];
                    7\'d13: sccb_scl <= 1\'b1;
                    7\'d15: sccb_scl <= 1\'b0;
                    7\'d16: sda_out  <= sccb_addr_t[3];
                    7\'d17: sccb_scl <= 1\'b1;
                    7\'d19: sccb_scl <= 1\'b0;
                    7\'d20: sda_out  <= sccb_addr_t[2];
                    7\'d21: sccb_scl <= 1\'b1;
                    7\'d23: sccb_scl <= 1\'b0;
                    7\'d24: sda_out  <= sccb_addr_t[1];
                    7\'d25: sccb_scl <= 1\'b1;
                    7\'d27: sccb_scl <= 1\'b0;
                    7\'d28: sda_out  <= sccb_addr_t[0];
                    7\'d29: sccb_scl <= 1\'b1;
                    7\'d31: sccb_scl <= 1\'b0;
                    7\'d32: begin
                           sda_dir  <= 1\'b0;    //从机应答
                           sda_out  <= 1\'b1;
                    end
                    7\'d33: sccb_scl <= 1\'b1;
                    7\'d34: state_done <= 1\'b1;  //状态结束
                    7\'d35: begin
                           sccb_scl <= 1\'b0;
                           cnt <= 1\'b0;
                    end
                    default:;
                endcase
            end
            //--------------------------------------------------- 写数据
            DATA: begin
                case(cnt)
                    7\'d0: begin
                           sda_out <= sccb_data_t[7];
                           sda_dir <= 1\'b1;
                    end
                    7\'d1 : sccb_scl <= 1\'b1;
                    7\'d3 : sccb_scl <= 1\'b0;
                    7\'d4 : sda_out  <= sccb_data_t[6];
                    7\'d5 : sccb_scl <= 1\'b1;
                    7\'d7 : sccb_scl <= 1\'b0;
                    7\'d8 : sda_out  <= sccb_data_t[5];
                    7\'d9 : sccb_scl <= 1\'b1;
                    7\'d11: sccb_scl <= 1\'b0;
                    7\'d12: sda_out  <= sccb_data_t[4];
                    7\'d13: sccb_scl <= 1\'b1;
                    7\'d15: sccb_scl <= 1\'b0;
                    7\'d16: sda_out  <= sccb_data_t[3];
                    7\'d17: sccb_scl <= 1\'b1;
                    7\'d19: sccb_scl <= 1\'b0;
                    7\'d20: sda_out  <= sccb_data_t[2];
                    7\'d21: sccb_scl <= 1\'b1;
                    7\'d23: sccb_scl <= 1\'b0;
                    7\'d24: sda_out  <= sccb_data_t[1];
                    7\'d25: sccb_scl <= 1\'b1;
                    7\'d27: sccb_scl <= 1\'b0;
                    7\'d28: sda_out  <= sccb_data_t[0];
                    7\'d29: sccb_scl <= 1\'b1;
                    7\'d31: sccb_scl <= 1\'b0;
                    7\'d32: begin
                           sda_dir  <= 1\'b0;    //从机应答
                           sda_out  <= 1\'b1;
                    end
                    7\'d33: sccb_scl <= 1\'b1;
                    7\'d34: state_done <= 1\'b1;  //状态结束
                    7\'d35: begin
                           sccb_scl <= 1\'b0;
                           cnt  <= 1\'b0;
                    end
                    default:;
                endcase
            end
            //--------------------------------------------------- 结束
            STOP: begin
                case(cnt)
                    7\'d0: begin
                           sda_dir  <= 1\'b1;
                           sda_out  <= 1\'b0;
                    end
                    7\'d1 : sccb_scl <= 1\'b1;
                    7\'d3 : sda_out  <= 1\'b1;
                    7\'d15: state_done <= 1\'b1;  //状态结束
                    7\'d16: begin
                           cnt <= 1\'b0;
                           sccb_done <= 1\'b1;   //sccb配置完成
                    end
                    default:;
                endcase
            end
        endcase
    end
end


endmodule

 

3、SCCB协议配置寄存器代码

module sccb_ov5640_cfg
//========================< 参数 >==========================================
#(
parameter REG_NUM           = 240                   , //寄存器个数
parameter CMOS_H_PIXEL      = 24\'d1024              , //CMOS水平方向像素个数
parameter CMOS_V_PIXEL      = 24\'d768               , //CMOS垂直方向像素个数
parameter TOTAL_H_PIXEL     = CMOS_H_PIXEL+13\'d1216 , //水平总像素大小
parameter TOTAL_V_PIXEL     = CMOS_V_PIXEL+13\'d504    //垂直总像素大小
)
//========================< 端口 >==========================================
(
input   wire                clk                     , //时钟,1Mhz
input   wire                rst_n                   , //复位,低电平有效
input   wire                sccb_vld                  , //SCCB配置有效信号
input   wire                sccb_done               , //SCCB寄存器配置完成信号
output  reg                 sccb_en                 , //SCCB触发执行信号   
output  reg     [23:0]      sccb_data               , //SCCB要配置的地址与数据(高8位地址,低8位数据)
output  reg                 sccb_cfg_done             //SCCB全部寄存器配置完成信号
);
//========================< 信号 >==========================================
reg                         sccb_vld_r                ;
wire                        sccb_start                ;
reg    [7:0]                reg_cnt                 ; //寄存器配置个数计数器
//==========================================================================
//==    sccb_vld上升沿检测
//==========================================================================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        sccb_vld_r <= 1\'b0;
    else
        sccb_vld_r <= sccb_vld;
end

assign sccb_start = sccb_vld && ~sccb_vld_r;
//==========================================================================
//==    sccb触发执行信号 
//==========================================================================  
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        sccb_en <= 1\'b0;
    else if(sccb_start)                     //开始配置寄存器
        sccb_en <= 1\'b1;
    else if(sccb_done && reg_cnt < REG_NUM) //上一个配置完后立马配置下一个
        sccb_en <= 1\'b1;
    else
        sccb_en <= 1\'b0;    
end 
//==========================================================================
//==    寄存器配置个数计数
//==========================================================================    
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        reg_cnt <= 8\'d0;
    else if(sccb_en)   
        reg_cnt <= reg_cnt + 8\'b1;
end
//==========================================================================
//==    所有寄存器全部配置完成信号
//==========================================================================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        sccb_cfg_done <= 1\'b0;
    else if((reg_cnt == REG_NUM) && sccb_done)
        sccb_cfg_done <= 1\'b1;  
end        
//==========================================================================
//==    配置寄存器地址与数据,Xclk=24Mhz
//==========================================================================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        sccb_data <= 24\'b0;
    else begin
    case(reg_cnt)
    ......
            default:
        endcase
    end
end



endmodule

 上述代码是改自正点原子的FPGA教程,我将软件复位后的延时删了,因为在前面我们已经进行了硬件复位,所以完全没必要再进行寄存器软件复位,而且就算进行软件复位,不需要再延时也是OK的。

  ov7725、ov7670和ov5640在这部分也是几乎一样的,只不过是寄存器和寄存器的个数那需要改一下,相关注意事项请看下面的详细介绍。

 

二、OV7670寄存器配置

  1 //**************************************************************************
  2 // *** 名称 : sccb_ov7670_cfg.v
  3 // *** 作者 : xianyu_FPGA
  4 // *** 博客 : https://www.cnblogs.com/xianyufpga/
  5 // *** 日期 : 2019-08-10
  6 // *** 描述 : SCCB配置OV7670寄存器
  7 //**************************************************************************
  8 
  9 module sccb_ov7670_cfg
 10 //========================< 参数 >==========================================
 11 #(
 12 parameter REG_NUM           = 123                     //寄存器个数
 13 )
 14 //========================< 端口 >==========================================
 15 (
 16 input   wire                clk                     , //时钟,1Mhz
 17 input   wire                rst_n                   , //复位,低电平有效
 18 input   wire                sccb_vld                  , //SCCB配置有效信号
 19 input   wire                sccb_done               , //SCCB寄存器配置完成信号
 20 output  reg                 sccb_en                 , //SCCB触发执行信号   
 21 output  reg     [15:0]      sccb_data               , //SCCB要配置的地址与数据(高8位地址,低8位数据)
 22 output  reg                 sccb_cfg_done             //SCCB全部寄存器配置完成信号
 23 );
 24 //========================< 信号 >==========================================
 25 reg                         sccb_vld_r                ;
 26 wire                        sccb_start                ;
 27 reg    [6:0]                reg_cnt                 ; //寄存器配置个数计数器
 28 //==========================================================================
 29 //==    sccb_vld上升沿检测
 30 //==========================================================================
 31 always @(posedge clk or negedge rst_n) begin
 32     if(!rst_n)
 33         sccb_vld_r <= 1\'b0;
 34     else
 35         sccb_vld_r <= sccb_vld;
 36 end
 37 
 38 assign sccb_start = sccb_vld && ~sccb_vld_r;
 39 //==========================================================================
 40 //==    sccb触发执行信号 
 41 //==========================================================================  
 42 always @(posedge clk or negedge rst_n) begin
 43     if(!rst_n)
 44         sccb_en <= 1\'b0;
 45     else if(sccb_start)                     //开始配置寄存器
 46         sccb_en <= 1\'b1;
 47     else if(sccb_done && reg_cnt < REG_NUM) //上一个配置完后立马配置下一个
 48         sccb_en <= 1\'b1;
 49     else
 50         sccb_en <= 1\'b0;    
 51 end 
 52 //==========================================================================
 53 //==    寄存器配置个数计数
 54 //==========================================================================    
 55 always @(posedge clk or negedge rst_n) begin
 56     if(!rst_n)
 57         reg_cnt <= 7\'d0;
 58     else if(sccb_en)   
 59         reg_cnt <= reg_cnt + 7\'b1;
 60 end
 61 //==========================================================================
 62 //==    所有寄存器全部配置完成信号
 63 //==========================================================================
 64 always @(posedge clk or negedge rst_n) begin
 65     if(!rst_n)
 66         sccb_cfg_done <= 1\'b0;
 67     else if((reg_cnt == REG_NUM) && sccb_done)  
 68         sccb_cfg_done <= 1\'b1;  
 69 end        
 70 //==========================================================================
 71 //==    配置寄存器地址与数据
 72 //==========================================================================
 73 always @(posedge clk or negedge rst_n) begin
 74     if(!rst_n)
 75         sccb_data <= 16\'b0;
 76     else begin
 77         case(reg_cnt)                        //30fps,XCLK=24Mhz,PCLK=24Mhz,ID=0x42
 78 //像素格式 ----------------------------------------------------------------------------------
 79             7\'d0   : sccb_data <= 16\'h12_04; //COM7     寄存器复位:否,图像选择:00_YUV,04_RGB
 80             7\'d1   : sccb_data <= 16\'h40_d0; //COM15    RGB565,范围00-FF(YUV为80,,范围为01-FE)
 81                                              //                            YUYV YVYU UYVY VYUY
 82             7\'d2   : sccb_data <= 16\'h3a_04; //TSLB     与COM13配合,bit[3]:0    0    1    1
 83             7\'d3   : sccb_data <= 16\'h3d_88; //COM13    与TSLB 配合,bit[3]: 0    1    0    1
 84 //帧率控制(Xclk=24Mhz) ----------------------------------------------------------------------
 85                                              //fps      30     15    25    14.3
 86                                              //pclk     24     12    24     12                                        
 87             7\'d4   : sccb_data <= 16\'h11_80; //CLKRC    80     00    80     00
 88             7\'d5   : sccb_data <= 16\'h6b_0a; //DBLV     0a     0a    0a     0a
 89             7\'d6   : sccb_data <= 16\'h2a_00; //EXHCH    00     00    00     00
 90             7\'d7   : sccb_data <= 16\'h2b_00; //EXHCL    00     00    00     00
 91             7\'d8   : sccb_data <= 16\'h92_00; //DM_LNL   00     00    66     1a
 92             7\'d9   : sccb_data <= 16\'h93_00; //DM_LNH   00     00    00     00
 93             7\'d10  : sccb_data <= 16\'h3b_0a; //COM11    0a     0a    0a     0a
 94 //镜像控制 ----------------------------------------------------------------------------------
 95             7\'d17  : sccb_data <= 16\'h1e_01; //镜像翻转 正常模式01  垂直翻转11
 96                                              //         水平翻转21  水平垂直翻转31
 97 //测试图案 ----------------------------------------------------------------------------------
 98                                              //         正常  彩条  细纹  渐变彩条
 99             7\'d18  : sccb_data <= 16\'h70_00; //测试图案  00    00    80     80
100             7\'d19  : sccb_data <= 16\'h71_01; //测试图案  01    81    01     81
101 //行场时序(默认值) --------------------------------------------------------------------------
102             7\'d20  : sccb_data <= 16\'h17_11; //HSTART   行频开始高8位
103             7\'d21  : sccb_data <= 16\'h18_61; //HSTOP    行频结束高8位
104             7\'d22  : sccb_data <= 16\'h32_80; //HREF     bit[5:3]行频开始低3位,bit[2:0]行频结束低3位
105             7\'d23  : sccb_data <= 16\'h19_03; //VSTART   场频开始高8位
106             7\'d24  : sccb_data <= 16\'h1a_7b; //VSTOP    场频结束高8位
107             7\'d25  : sccb_data <= 16\'h03_00; //VREF     bit[3:2]场频开始低2位,bit[1:0]场频结束低2位
108 //其他 --------------------------------------------------------------------------------------
109             7\'d26  : sccb_data <= 16\'h3e_00; //COM14    PCLK分频
110             7\'d27  : sccb_data <= 16\'h73_00; //SCALING  DSP缩放时钟分频,与COM14需一致,选择不分频
111             7\'d28  : sccb_data <= 16\'h0c_00;
112             7\'d29  : sccb_data <= 16\'h7a_20;
113             7\'d30  : sccb_data <= 16\'h7b_1c;
114             7\'d31  : sccb_data <= 16\'h7c_28;
115             7\'d32  : sccb_data <= 16\'h7d_3c;
116             7\'d33  : sccb_data <= 16\'h7e_55;
117             7\'d34  : sccb_data <= 16\'h7f_68;
118             7\'d35  : sccb_data <= 16\'h80_76;
119             7\'d36  : sccb_data <= 16\'h81_80;
120             7\'d37  : sccb_data <= 16\'h82_88;
121             7\'d38  : sccb_data <= 16\'h83_8f;
122             7\'d39  : sccb_data <= 16\'h84_96;
123             7\'d40  : sccb_data <= 16\'h85_a3;
124             7\'d41  : sccb_data <= 16\'h86_af;
125             7\'d42  : sccb_data <= 16\'h87_c4;
126             7\'d43  : sccb_data <= 16\'h88_d7;
127             7\'d44  : sccb_data <= 16\'h89_e8;
128             7\'d45  : sccb_data <= 16\'h00_00;
129             7\'d46  : sccb_data <= 16\'h10_00;
130             7\'d47  : sccb_data <= 16\'h0d_00;
131             7\'d48  : sccb_data <= 16\'h14_28;
132             7\'d49  : sccb_data <= 16\'h24_75;
133             7\'d50  : sccb_data <= 16\'h25_63;
134             7\'d51  : sccb_data <= 16\'h26_A5;
135             7\'d52  : sccb_data <= 16\'h9f_78;
136             7\'d53  : sccb_data <= 16\'ha0_68;
137             7\'d54  : sccb_data <= 16\'ha1_03;
138             7\'d55  : sccb_data <= 16\'ha6_df;
139             7\'d56  : sccb_data <= 16\'ha7_df;
140             7\'d57  : sccb_data <= 16\'ha8_f0;
141             7\'d58  : sccb_data <= 16\'ha9_90;
142             7\'d59  : sccb_data <= 16\'haa_94;
143             7\'d60  : sccb_data <= 16\'h13_ef;
144             7\'d61  : sccb_data <= 16\'h0e_61;
145             7\'d62  : sccb_data <= 16\'h72_11;
146             7\'d63  : sccb_data <= 16\'h16_02;
147             7\'d64  : sccb_data <= 16\'h0f_4b;
148             7\'d65  : sccb_data <= 16\'h21_02;
149             7\'d66  : sccb_data <= 16\'h22_91;
150             7\'d67  : sccb_data <= 16\'h29_07;
151             7\'d68  : sccb_data <= 16\'h33_0b;
152             7\'d69  : sccb_data <= 16\'h35_0b;
153             7\'d70  : sccb_data <= 16\'h37_1d;
154             7\'d71  : sccb_data <= 16\'h38_71;
155             7\'d72  : sccb_data <= 16\'h39_2a;
156             7\'d73  : sccb_data <= 16\'h3c_78;
157             7\'d74  : sccb_data <= 16\'h4d_40;
158             7\'d75  : sccb_data <= 16\'h4e_20;
159             7\'d76  : sccb_data <= 16\'h69_00;
160             7\'d77  : sccb_data <= 16\'ha2_02;
161             7\'d78  : sccb_data <= 16\'h74_19;
162             7\'d79  : sccb_data <= 16\'h8d_4f;
163             7\'d80  : sccb_data <= 16\'h8e_00;
164             7\'d81  : sccb_data <= 16\'h8f_00;
165             7\'d82  : sccb_data <= 16\'h90_00;
166             7\'d83  : sccb_data <= 16\'h91_00;
167             7\'d84  : sccb_data <= 16\'h96_00;
168             7\'d85  : sccb_data <= 16\'h9a_80;
169             7\'d86  : sccb_data <= 16\'hb0_84;
170             7\'d87  : sccb_data <= 16\'hb1_0c;
171             7\'d88  : sccb_data <= 16\'hb2_0e;
172             7\'d89  : sccb_data <= 16\'hb3_82;
173             7\'d90  : sccb_data <= 16\'hb8_0a;
174             7\'d91  : sccb_data <= 16\'h43_14;
175             7\'d92  : sccb_data <= 16\'h44_f0;
176             7\'d93  : sccb_data <= 16\'h45_34;
177             7\'d94  : sccb_data <= 16\'h46_58;
178             7\'d95  : sccb_data <= 16\'h47_28;
179             7\'d96  : sccb_data <= 16\'h48_3a;
180             7\'d97  : sccb_data <= 16\'h59_88;
181             7\'d98  : sccb_data <= 16\'h5a_88;
182             7\'d99  : sccb_data <= 16\'h5b_44;
183             7\'d100 : sccb_data <= 16\'h5c_67;
184             7\'d101 : sccb_data <= 16\'h5d_49;
185             7\'d102 : sccb_data <= 16\'h5e_0e;
186             7\'d103 : sccb_data <= 16\'h64_04;
187             7\'d104 : sccb_data <= 16\'h65_20;
188             7\'d105 : sccb_data <= 16\'h66_05;
189             7\'d106 : sccb_data <= 16\'h94_04;
190             7\'d107 : sccb_data <= 16\'h95_08;
191             7\'d108 : sccb_data <= 16\'h6c_0a;
192             7\'d109 : sccb_data <= 16\'h6d_55;
193             7\'d110 : sccb_data <= 16\'h4f_80;
194             7\'d111 : sccb_data <= 16\'h50_80;
195             7\'d112 : sccb_data <= 16\'h51_00;
196             7\'d113 : sccb_data <= 16\'h52_22;
197             7\'d114 : sccb_data <= 16\'h53_5e;
198             7\'d115 : sccb_data <= 16\'h54_80;
199             7\'d116 : sccb_data <= 16\'h09_03;
200             7\'d117 : sccb_data <= 16\'h6e_11;
201             7\'d118 : sccb_data <= 16\'h6f_9f;
202             7\'d119 : sccb_data <= 16\'h55_00;
203             7\'d120 : sccb_data <= 16\'h56_40;
204             7\'d121 : sccb_data <= 16\'h57_80;
205             7\'d122 : sccb_data <= 16\'h15_00;
206             default: sccb_data <= 16\'h1c_7f; //MIDH 制造商ID 高8位
207         endcase
208     end
209 end
210 
211 endmodule

  我只是把重要的寄存器提前了,可以通过更改 pll 寄存器而改变帧率,也可以通过窗口相关的寄存器改变输出的分辨率,但有些麻烦,我后面会介绍一种更好的办法来获取任意分辨率,以期适应我们的屏幕。

  这里输出的分辨率为 640x480,Pclk 为 24Mhz,fps 是我通过测量得到的,那如何进行理论值计算呢?

  datasheet 中有这样一张图,我们来算一下。一帧图像时间 = (2 x tPclk)x 510 x 784 = (2 x 510 x 784) / Pclk hz,一帧图像时间的倒数即为帧率 fps,因此帧率 fps = Pclk /(2 x 510 x 784),Pclk为24000000hz,因此计算得到 fps = 24000000 /(2 x 510 x 784)≈ 30.012。计算结果和实际测量值一致。

 

三、OV7725寄存器配置

  1 //**************************************************************************
  2 // *** 名称 : sccb_cfg.v
  3 // *** 作者 : xianyu_FPGA
  4 // *** 博客 : https://www.cnblogs.com/xianyufpga/
  5 // *** 日期 : 2019-08-10
  6 // *** 描述 : SCCB配置ov7725寄存器
  7 //**************************************************************************
  8 
  9 module sccb_ov7725_cfg
 10 //========================< 参数 >==========================================
 11 #(
 12 parameter REG_NUM           = 70                      //寄存器个数
 13 )
 14 //========================< 端口 >==========================================
 15 (
 16 input   wire                clk                     , //时钟,1Mhz
 17 input   wire                rst_n                   , //复位,低电平有效
 18 input   wire                sccb_vld                  , //SCCB配置有效信号
 19 input   wire                sccb_done               , //SCCB寄存器配置完成信号
 20 output  reg                 sccb_en                 , //SCCB触发执行信号   
 21 output  reg     [15:0]      sccb_data               , //SCCB要配置的地址与数据(高8位地址,低8位数据)
 22 output  reg                 sccb_cfg_done             //SCCB全部寄存器配置完成信号
 23 );
 24 //========================< 信号 >==========================================
 25 reg                         sccb_vld_r                ;
 26 wire                        sccb_start                ;
 27 reg    [6:0]                reg_cnt                 ; //寄存器配置个数计数器
 28 //==========================================================================
 29 //==    sccb_vld上升沿检测
 30 //==========================================================================
 31 always @(posedge clk or negedge rst_n) begin
 32     if(!rst_n)
 33         sccb_vld_r <= 1\'b0;
 34     else
 35         sccb_vld_r <= sccb_vld;
 36 end
 37 
 38 assign sccb_start = sccb_vld && ~sccb_vld_r;
 39 //==========================================================================
 40 //==    sccb触发执行信号 
 41 //==========================================================================  
 42 always @(posedge clk or negedge rst_n) begin
 43     if(!rst_n)
 44         sccb_en <= 1\'b0;
 45     else if(sccb_start)                     //开始配置寄存器
 46         sccb_en <= 1\'b1;
 47     else if(sccb_done && reg_cnt < REG_NUM) //上一个配置完后立马配置下一个
 48         sccb_en <= 1\'b1;
 49     else
 50         sccb_en <= 1\'b0;    
 51 end 
 52 //==========================================================================
 53 //==    寄存器配置个数计数
 54 //==========================================================================    
 55 always @(posedge clk or negedge rst_n) begin
 56     if(!rst_n)
 57         reg_cnt <= 7\'d0;
 58     else if(sccb_en)   
 59         reg_cnt <= reg_cnt + 7\'b1;
 60 end
 61 //==========================================================================
 62 //==    所有寄存器全部配置完成信号
 63 //==========================================================================
 64 always @(posedge clk or negedge rst_n) begin
 65     if(!rst_n)
 66         sccb_cfg_done <= 1\'b0;
 67     else if((reg_cnt == REG_NUM) && sccb_done)  
 68         sccb_cfg_done <= 1\'b1;  
 69 end        
 70 //==========================================================================
 71 //==    配置寄存器地址与数据
 72 //==========================================================================
 73 always @(posedge clk or negedge rst_n) begin
 74     if(!rst_n)
 75         sccb_data <= 16\'b0;
 76     else begin
 77         case(reg_cnt)                            //30fps,XCLK=24Mhz,PCLK=24Mhz,ID=0x42
 78 //基本设置 ----------------------------------------------------------------------------
 79             7\'d0  : sccb_data <= {8\'h12, 8\'h06}; //COM7     复位选择:否;格式:VGA_RGB565 
 80             7\'d1  : sccb_data <= {8\'h0c, 8\'h10}; //COM3     10正常模式; 90垂直翻转
 81                                                  //         50水平翻转; d0水平垂直翻转
 82                                                  //Bit[0]   0正常模式;  1彩条测试
 83 //时序参数 ----------------------------------------------------------------------------
 84             7\'d2  : sccb_data <= {8\'h17, 8\'h22}; //HSTART   VGA:8\'h22; QVGA:8\'h3f
 85             7\'d3  : sccb_data <= {8\'h18, 8\'ha4}; //HSIZE    VGA:8\'ha4; QVGA:8\'h50
 86             7\'d4  : sccb_data <= {8\'h19, 8\'h07}; //VSTART   VGA:8\'h07; QVGA:8\'h03
 87             7\'d5  : sccb_data <= {8\'h1a, 8\'hf0}; //VSIZE    VGA:8\'hf0; QVGA:8\'h78
 88             7\'d6  : sccb_data <= {8\'h29, 8\'ha0}; //HOutSize VGA:8\'hA0; QVGA:8\'hF0
 89             7\'d7  : sccb_data <= {8\'h2c, 8\'hf0}; //VOutSize VGA:8\'hF0; QVGA:8\'h78
 90 //帧率PLL(Xclk=24Mhz) ---------------------------------------------------------------
 91                                                  //fps/pclk 30/24 15/12 25/24 14.3/12
 92             7\'d8  : sccb_data <= {8\'h11, 8\'h01}; //           01    03    01    03
 93             7\'d9  : sccb_data <= {8\'h0d, 8\'h41}; //           41    41    41    41
 94             7\'d10 : sccb_data <= {8\'h2a, 8\'h00}; //           00    00    00    00
 95             7\'d11 : sccb_data <= {8\'h33, 8\'h00}; //           00    00    66    1a
 96             7\'d12 : sccb_data <= {8\'h34, 8\'h00}; //           00    00    00    00
 97             7\'d13 : sccb_data <= {8\'h2d, 8\'h00}; //           00    00    00    00
 98             7\'d14 : sccb_data <= {8\'h2e, 8\'h00}; //           00    00    00    00
 99             7\'d15 : sccb_data <= {8\'h0e, 8\'h65}; //           65    65    65    65
100             7\'d16 : sccb_data <= {8\'h2b, 8\'h00}; //60hz/50hz 默认00/60hz,有灯光干扰,fps如上
101                                                  //          改为9e/50hz,无灯光干扰,fps会变
102 //DSP 控制 ----------------------------------------------------------------------------
103             7\'d17 : sccb_data <= {8\'h42, 8\'h7f}; //TGT_B     黑电平校准蓝色通道目标值
104             7\'d18 : sccb_data <= {8\'h4d, 8\'h09}; //FixGain   模拟增益放大器
105             7\'d19 : sccb_data <= {8\'h63, 8\'hf0}; //AWB_Ctrl0 自动白平衡控制字节0
106             7\'d20 : sccb_data <= {8\'h64, 8\'hff}; //DSP_Ctrl1 DSP控制字节1
107             7\'d21 : sccb_data <= {8\'h65, 8\'h00}; //DSP_Ctrl2 DSP控制字节2
108             7\'d22 : sccb_data <= {8\'h66, 8\'h00}; //DSP_Ctrl3 DSP控制字节3
109             7\'d23 : sccb_data <= {8\'h67, 8\'h00}; //DSP_Ctrl4 DSP控制字节4 
110 //AGC AEC AWB ------------------------------------------------------------------------
111             7\'d24 : sccb_data <= {8\'h13, 8\'hff}; //COM8 自动增益/白平衡/曝光
112             7\'d25 : sccb_data <= {8\'h0f, 8\'hc5}; //COM6
113             7\'d26 : sccb_data <= {8\'h14, 8\'h11};  
114             7\'d27 : sccb_data <= {8\'h22, 8\'h98}; 
115             7\'d28 : sccb_data <= {8\'h23, 8\'h03};  
116             7\'d29 : sccb_data <= {8\'h24, 8\'h40}; 
117             7\'d30 : sccb_data <= {8\'h25, 8\'h30};  
118             7\'d31 : sccb_data <= {8\'h26, 8\'ha1};      
119             7\'d32 : sccb_data <= {8\'h6b, 8\'haa}; 
120             7\'d33 : sccb_data <= {8\'h13, 8\'hff}; 
121 //参数调整 ---------------------------------------------------------------------------
122             7\'d34 : sccb_data <= {8\'h90, 8\'h0a}; //EDGE1    边缘增强控制1
123             7\'d35 : sccb_data <= {8\'h91, 8\'h01}; //DNSOff   阈值下限
124             7\'d36 : sccb_data <= {8\'h92, 8\'h01}; //EDGE2    锐度(边缘增强)强度上限
125             7\'d37 : sccb_data <= {8\'h93, 8\'h01}; //EDGE3    锐度(边缘增强)强度下限
126             7\'d38 : sccb_data <= {8\'h94, 8\'h5f}; //MTX1     矩阵系数1
127             7\'d39 : sccb_data <= {8\'h95, 8\'h53}; //MTX2     矩阵系数2
128             7\'d40 : sccb_data <= {8\'h96, 8\'h11}; //MTX3     矩阵系数3
129             7\'d41 : sccb_data <= {8\'h97, 8\'h1a}; //MTX4     矩阵系数4
130             7\'d42 : sccb_data <= {8\'h98, 8\'h3d}; //MTX5     矩阵系数5
131             7\'d43 : sccb_data <= {8\'h99, 8\'h5a}; //MTX6     矩阵系数6
132             7\'d44 : sccb_data <= {8\'h9a, 8\'h1e}; //MTX_Ctrl 矩阵控制
133             7\'d45 : sccb_data <= {8\'h9b, 8\'h3f}; //BRIGHT   亮度
134             7\'d46 : sccb_data <= {8\'h9c, 8\'h25}; //CNST     对比度            
135             7\'d47 : sccb_data <= {8\'h9e, 8\'h81}; //UV/ADJ0  紫外线调控
136             7\'d48 : sccb_data <= {8\'ha6, 8\'h06}; //SDE      特殊数字效果控制
137             7\'d49 : sccb_data <= {8\'ha7, 8\'h65}; //USAT     "U"饱和增益
138             7\'d50 : sccb_data <= {8\'ha8, 8\'h65}; //VSAT     "V"饱和增益            
139             7\'d51 : sccb_data <= {8\'ha9, 8\'h80}; //HUECOS   cos值   
140             7\'d52 : sccb_data <= {8\'haa, 8\'h80}; //HUESIN   sin值
141 //伽马控制 -------------------------------------------------------------------------
142             7\'d53 : sccb_data <= {8\'h7e, 8\'h0c}; 
143             7\'d54 : sccb_data <= {8\'h7f, 8\'h16}; 
144             7\'d55 : sccb_data <= {8\'h80, 8\'h2a}; 
145             7\'d56 : sccb_data <= {8\'h81, 8\'h4e}; 
146             7\'d57 : sccb_data <= {8\'h82, 8\'h61}; 
147             7\'d58 : sccb_data <= {8\'h83, 8\'h6f}; 
148             7\'d59 : sccb_data <= {8\'h84, 8\'h7b}; 
149             7\'d60 : sccb_data <= {8\'h85, 8\'h86};   
150             7\'d61 : sccb_data <= {8\'h86, 8\'h8e}; 
151             7\'d62 : sccb_data <= {8\'h87, 8\'h97}; 
152             7\'d63 : sccb_data <= {8\'h88, 8\'ha4}; 
153             7\'d64 : sccb_data <= {8\'h89, 8\'haf}; 
154             7\'d65 : sccb_data <= {8\'h8a, 8\'hc5}; 
155             7\'d66 : sccb_data <= {8\'h8b, 8\'hd7}; 
156             7\'d67 : sccb_data <= {8\'h8c, 8\'he8}; 
157             7\'d68 : sccb_data <= {8\'h8d, 8\'h20}; 
158 //others --------------------------------------------------------------------------
159             7\'d69 : sccb_data <= {8\'h3d, 8\'h03}; //模拟过程的直流偏移
160         endcase
161     end
162 end
163 
164 endmodule

  和 OV7670 差不多,注意一下第 13 个寄存器 8\'h2b,根据韩彬的书《FPGA设计技巧与案例开发详解》介绍,假设我们原本寄存器配置的是 640x480@30fps,此时8\'h2b的值为00,大陆的白炽灯频率为50hz,会导致图像效果出现条纹干扰。当把 8\'h2b寄存器的值改为 9e 时,就可以避免该条纹干扰,但帧率却会由 30fps 变成 25fps。

 

四、OV5640寄存器配置

  1 //**************************************************************************
  2 // *** 名称 : sccb_ov5640_cfg.v
  3 // *** 作者 : xianyu_FPGA
  4 // *** 博客 : https://www.cnblogs.com/xianyufpga/
  5 // *** 日期 : 2019-08-10
  6 // *** 描述 : SCCB配置ov5640寄存器
  7 //**************************************************************************
  8 
  9 module sccb_ov5640_cfg
 10 //========================< 参数 >==========================================
 11 #(
 12 parameter REG_NUM           = 240                   , //寄存器个数
 13 parameter CMOS_H_PIXEL      = 24\'d1024              , //CMOS水平方向像素个数
 14 parameter CMOS_V_PIXEL      = 24\'d768               , //CMOS垂直方向像素个数
 15 parameter TOTAL_H_PIXEL     = CMOS_H_PIXEL+13\'d1216 , //水平总像素大小
 16 parameter TOTAL_V_PIXEL     = CMOS_V_PIXEL+13\'d504    //垂直总像素大小
 17 )
 18 //========================< 端口 >==========================================
 19 (
 20 input   wire                clk                     , //时钟,1Mhz
 21 input   wire                rst_n                   , //复位,低电平有效
 22 input   wire                sccb_vld                , //SCCB配置有效信号
 23 input   wire                sccb_done               , //SCCB寄存器配置完成信号
 24 output  reg                 sccb_en                 , //SCCB触发执行信号   
 25 output  reg     [23:0]      sccb_data               , //SCCB要配置的地址与数据(高8位地址,低8位数据)
 26 output  reg                 sccb_cfg_done             //SCCB全部寄存器配置完成信号
 27 );
 28 //========================< 信号 >==========================================
 29 reg                         sccb_vld_r                ;
 30 wire                        sccb_start                ;
 31 reg    [7:0]                reg_cnt                   ; //寄存器配置个数计数器
 32 //==========================================================================
 33 //==    sccb_vld上升沿检测
 34 //==========================================================================
 35 always @(posedge clk or negedge rst_n) begin
 36     if(!rst_n)
 37         sccb_vld_r <= 1\'b0;
 38     else
 39         sccb_vld_r <= sccb_vld;
 40 end
 41 
 42 assign sccb_start = sccb_vld && ~sccb_vld_r;
 43 //==========================================================================
 44 //==    sccb触发执行信号 
 45 //==========================================================================  
 46 always @(posedge clk or negedge rst_n) begin
 47     if(!rst_n)
 48         sccb_en <= 1\'b0;
 49     else if(sccb_start)                     //开始配置寄存器
 50         sccb_en <= 1\'b1;
 51     else if(sccb_done && reg_cnt < REG_NUM) //上一个配置完后立马配置下一个
 52         sccb_en <= 1\'b1;
 53     else
 54         sccb_en <= 1\'b0;    
 55 end 
 56 //==========================================================================
 57 //==    寄存器配置个数计数
 58 //==========================================================================    
 59 always @(posedge clk or negedge rst_n) begin
 60     if(!rst_n)
 61         reg_cnt <= 8\'d0;
 62     else if(sccb_en)   
 63         reg_cnt <= reg_cnt + 8\'b1;
 64 end
 65 //==========================================================================
 66 //==    所有寄存器全部配置完成信号
 67 //==========================================================================
 68 always @(posedge clk or negedge rst_n) begin
 69     if(!rst_n)
 70         sccb_cfg_done <= 1\'b0;
 71     else if((reg_cnt == REG_NUM) && sccb_done)
 72         sccb_cfg_done <= 1\'b1;  
 73 end        
 74 //==========================================================================
 75 //==    配置寄存器地址与数据,Xclk=24Mhz
 76 //==========================================================================
 77 always @(posedge clk or negedge rst_n) begin
 78     if(!rst_n)
 79         sccb_data <= 24\'b0;
 80     else begin
 81     case(reg_cnt)                                  //Xclk=24Mhz FPS=30fps Pclk=24Mhz(不解)
 82 //基本配置 ------------------------------------------------------------------------------------
 83             8\'d0  : sccb_data <= {16\'h3008,8\'h02}; //复位休眠 Bit[7]:复位 Bit[6]:休眠
 84             8\'d1  : sccb_data <= {16\'h300e,8\'h58}; //DVP 使能 DVP enable
 85             8\'d2  : sccb_data <= {16\'h4300,8\'h61}; //格式控制 RGB565
 86             8\'d3  : sccb_data <= {16\'h503d,8\'h00}; //测试图案 00正常 80彩条 81混乱 82棋盘
 87 //PLL(11_23为20fps) ---------------------------------------------------------------------------
 88             8\'d4  : sccb_data <= {16\'h3035,8\'h21}; //PLL分频  11/1x 21/2x 32/3x
 89             8\'d5  : sccb_data <= {16\'h3036,8\'h69}; //PLL倍频  23/1÷ 46/2÷ 69/3÷
 90             8\'d6  : sccb_data <= {16\'h3037,8\'h03}; //PLL分频  bit[4]:0/1 bypass/÷2
 91 //ISP(VGA模式) --------------------------------------------------------------------------------
 92             8\'d7  : sccb_data <= {16\'h3800,8\'h00};
 93             8\'d8  : sccb_data <= {16\'h3801,8\'h00};
 94             8\'d9  : sccb_data <= {16\'h3802,8\'h00};
 95             8\'d10 : sccb_data <= {16\'h3803,8\'h04};
 96             8\'d11 : sccb_data <= {16\'h3804,8\'h0a};
 97             8\'d12 : sccb_data <= {16\'h3805,8\'h3f};
 98             8\'d13 : sccb_data <= {16\'h3806,8\'h07};
 99             8\'d14 : sccb_data <= {16\'h3807,8\'h9b};
100 //输出窗口设置 --------------------------------------------------------------------------------
101             8\'d15 : sccb_data <= {16\'h3808,{4\'d0,CMOS_H_PIXEL[11:8]  }}; //水平像素点数高4位
102             8\'d16 : sccb_data <= {16\'h3809,      CMOS_H_PIXEL[ 7:0]   }; //水平像素点数低8位
103             8\'d17 : sccb_data <= {16\'h380a,{5\'d0,CMOS_V_PIXEL[10:8]  }}; //垂直像素点数高3位
104             8\'d18 : sccb_data <= {16\'h380b,      CMOS_V_PIXEL[ 7:0]   }; //垂直像素点数低8位
105             8\'d19 : sccb_data <= {16\'h380c,{3\'d0,TOTAL_H_PIXEL[12:8] }}; //水平总像素大小高5位
106             8\'d20 : sccb_data <= {16\'h380d,      TOTAL_H_PIXEL[ 7:0]  }; //水平总像素大小低8位
107             8\'d21 : sccb_data <= {16\'h380e,{3\'d0,TOTAL_V_PIXEL[12:8] }}; //垂直总像素大小高5位    
108             8\'d22 : sccb_data <= {16\'h380f,      TOTAL_V_PIXEL[ 7:0]  }; //垂直总像素大小低8位
109 //预缩放 --------------------------------------------------------------------------------------
110             8\'d23 : sccb_data <= {16\'h3810,8\'h00}; //Timing Hoffset[11:8]
111             8\'d24 : sccb_data <= {16\'h3811,8\'h10}; //Timing Hoffset[7:0]
112             8\'d25 : sccb_data <= {16\'h3812,8\'h00}; //Timing Voffset[10:8]
113             8\'d26 : sccb_data <= {16\'h3813,8\'h06}; //Timing Voffset[7:0]
114             8\'d27 : sccb_data <= {16\'h3814,8\'h31}; //Timing X INC
115             8\'d28 : sccb_data <= {16\'h3815,8\'h31}; //Timing Y INC
116             8\'d29 : sccb_data <= {16\'h3820,8\'h40}; //上下翻转:40/46
117             8\'d30 : sccb_data <= {16\'h3821,8\'h07}; //左右翻转:01/07
118 //SCCB ----------------------------------------------------------------------------------------
119             8\'d31 : sccb_data <= {16\'h3103,8\'h02}; //Bit[1]:1 PLL Clock
120             8\'d32 : sccb_data <= {16\'h3108,8\'h01}; //系统分频
121 //VCM -----------------------------------------------------------------------------------------
122             8\'d33 : sccb_data <= {16\'h3600,8\'h08}; //VCM控制,用于自动聚焦
123             8\'d34 : sccb_data <= {16\'h3601,8\'h33}; //VCM控制,用于自动聚焦
124 //AEC/AGC -------------------------------------------------------------------------------------
125             8\'d35 : sccb_data <= {16\'h3a02,8\'h17}; //60Hz max exposure
126             8\'d36 : sccb_data <= {16\'h3a03,8\'h10}; //60Hz max exposure
127             8\'d37 : sccb_data <= {16\'h3a0f,8\'h30}; //AEC控制;stable range in high
128             8\'d38 : sccb_data <= {16\'h3a10,8\'h28}; //AEC控制;stable range in low
129             8\'d39 : sccb_data <= {16\'h3a11,8\'h60}; //AEC控制; fast zone high
130             8\'d40 : sccb_data <= {16\'h3a13,8\'h43}; //AEC(自动曝光控制)
131             8\'d41 : sccb_data <= {16\'h3a14,8\'h17}; //50Hz max exposure
132             8\'d42 : sccb_data <= {16\'h3a15,8\'h10}; //50Hz max exposure
133             8\'d43 : sccb_data <= {16\'h3a18,8\'h00}; //AEC 增益上限
134             8\'d44 : sccb_data <= {16\'h3a19,8\'hf8}; //AEC 增益上限
135             8\'d45 : sccb_data <= {16\'h3a1b,8\'h30}; //AEC控制;stable range out high
136             8\'d46 : sccb_data <= {16\'h3a1e,8\'h26}; //AEC控制;stable range out low
137             8\'d47 : sccb_data <= {16\'h3a1f,8\'h14}; //AEC控制; fast zone low
138 //5060Hz --------------------------------------------------------------------------------------
139             8\'d48 : sccb_data <= {16\'h3c01,8\'h34};
140             8\'d49 : sccb_data <= {16\'h3c04,8\'h28};
141             8\'d50 : sccb_data <= {16\'h3c05,8\'h98};
142             8\'d51 : sccb_data <= {16\'h3c06,8\'h00}; //light meter 1 阈值[15:8]
143             8\'d52 : sccb_data <= {16\'h3c07,8\'h08}; //light meter 1 阈值[7:0]
144             8\'d53 : sccb_data <= {16\'h3c08,8\'h00}; //light meter 2 阈值[15:8]
145             8\'d54 : sccb_data <= {16\'h3c09,8\'h1c}; //light meter 2 阈值[7:0]
146             8\'d55 : sccb_data <= {16\'h3c0a,8\'h9c}; //sample number[15:8]
147             8\'d56 : sccb_data <= {16\'h3c0b,8\'h40}; //sample number[7:0]
148 //BLC -----------------------------------------------------------------------------------------
149             8\'d57 : sccb_data <= {16\'h4001,8\'h02}; //BLC(黑电平校准)补偿起始行号
150             8\'d58 : sccb_data <= {16\'h4004,8\'h02}; //BLC(背光) 2 lines
151             8\'d59 : sccb_data <= {16\'h4005,8\'h1a}; //BLC(黑电平校准)补偿始终更新
152 //ISP -----------------------------------------------------------------------------------------
153             8\'d60 : sccb_data <= {16\'h5000,8\'ha7}; //ISP 控制
154             8\'d61 : sccb_data <= {16\'h5001,8\'ha3}; //ISP 控制
155             8\'d62 : sccb_data <= {16\'h501d,8\'h40}; //ISP 控制
156             8\'d63 : sccb_data <= {16\'h501f,8\'h01}; //ISP RGB
157 //LENC(镜头校正)控制 16\'h5800~16\'h583d --------------------------------------------------------
158             8\'d64 : sccb_data <= {16\'h5800,8\'h23};
159             8\'d65 : sccb_data <= {16\'h5801,8\'h14};
160             8\'d66 : sccb_data <= {16\'h5802,8\'h0f};
161             8\'d67 : sccb_data <= {16\'h5803,8\'h0f};
162             8\'d68 : sccb_data <= {16\'h5804,8\'h12};
163             8\'d69 : sccb_data <= {16\'h5805,8\'h26};
164             8\'d70 : sccb_data <= {16\'h5806,8\'h0c};
165             8\'d71 : sccb_data <= {16\'h5807,8\'h08};
166             8\'d72 : sccb_data <= {16\'h5808,8\'h05};
167             8\'d73 : sccb_data <= {16\'h5809,8\'h05};
168             8\'d74 : sccb_data <= {16\'h580a,8\'h08};
169             8\'d75 : sccb_data <= {16\'h580b,8\'h0d};
170             8\'d76 : sccb_data <= {16\'h580c,8\'h08};
171             8\'d77 : sccb_data <= {16\'h580d,8\'h03};
172             8\'d78 : sccb_data <= {16\'h580e,8\'h00};
173             8\'d79 : sccb_data <= {16\'h580f,8\'h00};
174             8\'d80 : sccb_data <= {16\'h5810,8\'h03};
175             8\'d81 : sccb_data <= {16\'h5811,8\'h09};
176             8\'d82 : sccb_data <= {16\'h5812,8\'h07};
177             8\'d83 : sccb_data <= {16\'h5813,8\'h03};
178             8\'d84 : sccb_data <= {16\'h5814,8\'h00};
179             8\'d85 : sccb_data <= {16\'h5815,8\'h01};
180             8\'d86 : sccb_data <= {16\'h5816,8\'h03};
181             8\'d87 : sccb_data <= {16\'h5817,8\'h08};
182             8\'d88 : sccb_data <= {16\'h5818,8\'h0d};
183             8\'d89 : sccb_data <= {16\'h5819,8\'h08};
184             8\'d90 : sccb_data <= {16\'h581a,8\'h05};
185             8\'d91 : sccb_data <= {16\'h581b,8\'h06};
186             8\'d92 : sccb_data <= {16\'h581c,8\'h08};
187             8\'d93 : sccb_data <= {16\'h581d,8\'h0e};
188             8\'d94 : sccb_data <= {16\'h581e,8\'h29};
189             8\'d95 : sccb_data <= {16\'h581f,8\'h17};
190             8\'d96 : sccb_data <= {16\'h5820,8\'h11};
191             8\'d97 : sccb_data <= {16\'h5821,8\'h11};
192             8\'d98 : sccb_data <= {16\'h5822,8\'h15};
193             8\'d99 : sccb_data <= {16\'h5823,8\'h28};
194             8\'d100: sccb_data <= {16\'h5824,8\'h46};
195             8\'d101: sccb_data <= {16\'h5825,8\'h26};
196             8\'d102: sccb_data <= {16\'h5826,8\'h08};
197             8\'d103: sccb_data <= {16\'h5827,8\'h26};
198             8\'d104: sccb_data <= {16\'h5828,8\'h64};
199             8\'d105: sccb_data <= {16\'h5829,8\'h26};
200             8\'d106: sccb_data <= {16\'h582a,8\'h24};
201             8\'d107: sccb_data <= {16\'h582b,8\'h22};
202             8\'d108: sccb_data <= {16\'h582c,8\'h24};
203             8\'d109: sccb_data <= {16\'h582d,8\'h24};
204             8\'d110: sccb_data <= {16\'h582e,8\'h06};
205             8\'d111: sccb_data <= {16\'h582f,8\'h22};
206             8\'d112: sccb_data <= {16\'h5830,8\'h40};
207             8\'d113: sccb_data <= {16\'h5831,8\'h42};
208             8\'d114: sccb_data <= {16\'h5832,8\'h24};
209             8\'d115: sccb_data <= {16\'h5833,8\'h26};
210             8\'d116: sccb_data <= {16\'h5834,8\'h24};
211             8\'d117: sccb_data <= {16\'h5835,8\'h22};
212             8\'d118: sccb_data <= {16\'h5836,8\'h22};
213             8\'d119: sccb_data <= {16\'h5837,8\'h26};
214             8\'d120: sccb_data <= {16\'h5838,8\'h44};
215             8\'d121: sccb_data <= {16\'h5839,8\'h24};
216             8\'d122: sccb_data <= {16\'h583a,8\'h26};
217             8\'d123: sccb_data <= {16\'h583b,8\'h28};
218             8\'d124: sccb_data <= {16\'h583c,8\'h42};
219             8\'d125: sccb_data <= {16\'h583d,8\'hce};
220 //AWB(自动白平衡控制) 16\'h5180~16\'h519e -------------------------------------------------------
221             8\'d126: sccb_data <= {16\'h5180,8\'hff};
222             8\'d127: sccb_data <= {16\'h5181,8\'hf2};
223             8\'d128: sccb_data <= {16\'h5182,8\'h00};
224             8\'d129: sccb_data <= {16\'h5183,8\'h14};
225             8\'d130: sccb_data <= {16\'h5184,8\'h25};
226             8\'d131: sccb_data <= {16\'h5185,8\'h24};
227             8\'d132: sccb_data <= {16\'h5186,8\'h09};
228             8\'d133: sccb_data <= {16\'h5187,8\'h09};
229             8\'d134: sccb_data <= {16\'h5188,8\'h09};
230             8\'d135: sccb_data <= {16\'h5189,8\'h75};
231             8\'d136: sccb_data <= {16\'h518a,8\'h54};
232             8\'d137: sccb_data <= {16\'h518b,8\'he0};
233             8\'d138: sccb_data <= {16\'h518c,8\'hb2};
234             8\'d139: sccb_data <= {16\'h518d,8\'h42};
235             8\'d140: sccb_data <= {16\'h518e,8\'h3d};
236             8\'d141: sccb_data <= {16\'h518f,8\'h56};
237             8\'d142: sccb_data <= {16\'h5190,8\'h46};
238             8\'d143: sccb_data <= {16\'h5191,8\'hf8};
239             8\'d144: sccb_data <= {16\'h5192,8\'h04};
240             8\'d145: sccb_data <= {16\'h5193,8\'h70};
241             8\'d146: sccb_data <= {16\'h5194,8\'hf0};
242             8\'d147: sccb_data <= {16\'h5195,8\'hf0};
243             8\'d148: sccb_data <= {16\'h5196,8\'h03};
244             8\'d149: sccb_data <= {16\'h5197,8\'h01};
245             8\'d150: sccb_data <= {16\'h5198,8\'h04};
246             8\'d151: sccb_data <= {16\'h5199,8\'h12};
247             8\'d152: sccb_data <= {16\'h519a,8\'h04};
248             8\'d153: sccb_data <= {16\'h519b,8\'h00};
249             8\'d154: sccb_data <= {16\'h519c,8\'h06};
250             8\'d155: sccb_data <= {16\'h519d,8\'h82};
251             8\'d156: sccb_data <= {16\'h519e,8\'h38};
252 //Gamma(伽马)控制 16\'h5480~16\'h5490 -----------------------------------------------------------
253             8\'d157: sccb_data <= {16\'h5480,8\'h01};
254             8\'d158: sccb_data <= {16\'h5481,8\'h08};
255             8\'d159: sccb_data <= {16\'h5482,8\'h14};
256             8\'d160: sccb_data <= {16\'h5483,8\'h28};
257             8\'d161: sccb_data <= {16\'h5484,8\'h51};
258             8\'d162: sccb_data <= {16\'h5485,8\'h65};
259             8\'d163: sccb_data <= {16\'h5486,8\'h71};
260             8\'d164: sccb_data <= {16\'h5487,8\'h7d};
261             8\'d165: sccb_data <= {16\'h5488,8\'h87};
262             8\'d166: sccb_data <= {16\'h5489,8\'h91};
263             8\'d167: sccb_data <= {16\'h548a,8\'h9a};
264             8\'d168: sccb_data <= {16\'h548b,8\'haa};
265             8\'d169: sccb_data <= {16\'h548c,8\'hb8};
266             8\'d170: sccb_data <= {16\'h548d,8\'hcd};
267             8\'d171: sccb_data <= {16\'h548e,8\'hdd};
268             8\'d172: sccb_data <= {16\'h548f,8\'hea};
269             8\'d173: sccb_data <= {16\'h5490,8\'h1d};
270 //CMX(彩色矩阵控制) 16\'h5381~16\'h538b ---------------------------------------------------------
271             8\'d174: sccb_data <= {16\'h5381,8\'h1e};
272             8\'d175: sccb_data <= {16\'h5382,8\'h5b};
273             8\'d176: sccb_data <= {16\'h5383,8\'h08};
274             8\'d177: sccb_data <= {16\'h5384,8\'h0a};
275             8\'d178: sccb_data <= {16\'h5385,8\'h7e};
276             8\'d179: sccb_data <= {16\'h5386,8\'h88};
277             8\'d180: sccb_data <= {16\'h5387,8\'h7c};
278             8\'d181: sccb_data <= {16\'h5388,8\'h6c};
279             8\'d182: sccb_data <= {16\'h5389,8\'h10};
280             8\'d183: sccb_data <= {16\'h538a,8\'h01};
281             8\'d184: sccb_data <= {16\'h538b,8\'h98};
282 //SDE(特殊数码效果)控制 16\'h5580~16\'h558b -----------------------------------------------------
283             8\'d185: sccb_data <= {16\'h5580,8\'h06};
284             8\'d186: sccb_data <= {16\'h5583,8\'h40};
285             8\'d187: sccb_data <= {16\'h5584,8\'h10};
286             8\'d188: sccb_data <= {16\'h5589,8\'h10};
287             8\'d189: sccb_data <= {16\'h558a,8\'h00};
288             8\'d190: sccb_data <= {16\'h558b,8\'hf8};
289 //CIP(颜色插值)控制 (16\'h5300~16\'h530c) -------------------------------------------------------
290             8\'d191: sccb_data <= {16\'h5300,8\'h08};
291             8\'d192: sccb_data <= {16\'h5301,8\'h30};
292             8\'d193: sccb_data <= {16\'h5302,8\'h10};
293             8\'d194: sccb_data <= {16\'h5303,8\'h00};
294             8\'d195: sccb_data <= {16\'h5304,8\'h08};
295             8\'d196: sccb_data <= {16\'h5305,8\'h30};
296             8\'d197: sccb_data <= {16\'h5306,8\'h08};
297             8\'d198: sccb_data <= {16\'h5307,8\'h16};
298             8\'d199: sccb_data <= {16\'h5309,8\'h08};
299             8\'d200: sccb_data <= {16\'h530a,8\'h30};
300             8\'d201: sccb_data <= {16\'h530b,8\'h04};
301             8\'d202: sccb_data <= {16\'h530c,8\'h06};
302 //测试闪光灯功能 ------------------------------------------------------------------------------
303             8\'d203: sccb_data <= {16\'h3000,8\'h00}; //系统块复位控制
304             8\'d204: sccb_data <= {16\'h3004,8\'hff}; //时钟使能控制
305             8\'d205: sccb_data <= {16\'h3017,8\'hff}; //I/O控制[3:0]     00:input ff:output 
306             8\'d206: sccb_data <= {16\'h3018,8\'hff}; //I/O控制[7:2]     00:input ff:output
307             8\'d207: sccb_data <= {16\'h3016,8\'h02};
308             8\'d208: sccb_data <= {16\'h301c,8\'h02};
309             8\'d209: sccb_data <= {16\'h3019,8\'h02}; //打开闪光灯
310             8\'d210: sccb_data <= {16\'h3019,8\'h00}; //关闭闪光灯
311 //others --------------------------------------------------------------------------------------
312             8\'d211: sccb_data <= {16\'h3612,8\'h29};
313             8\'d212: sccb_data <= {16\'h3618,8\'h00};
314             8\'d213: sccb_data <= {16\'h3620,8\'h52};
315             8\'d214: sccb_data <= {16\'h3621,8\'he0};
316             8\'d215: sccb_data <= {16\'h3622,8\'h01};
317             8\'d216: sccb_data <= {16\'h302d,8\'h60}; //系统控制
318             8\'d217: sccb_data <= {16\'h3630,8\'h36};
319             8\'d218: sccb_data <= {16\'h3631,8\'h0e};
320             8\'d219: sccb_data <= {16\'h3632,8\'he2};
321             8\'d220: sccb_data <= {16\'h3633,8\'h12};
322             8\'d221: sccb_data <= {16\'h3634,8\'h40};
323             8\'d222: sccb_data <= {16\'h3635,8\'h13};
324             8\'d223: sccb_data <= {16\'h3636,8\'h03};
325             8\'d224: sccb_data <= {16\'h3703,8\'h5a};
326             8\'d225: sccb_data <= {16\'h3704,8\'ha0};
327             8\'d226: sccb_data <= {16\'h3705,8\'h1a};
328             8\'d227: sccb_data <= {16\'h3708,8\'h64};
329             8\'d228: sccb_data <= {16\'h3709,8\'h52};
330             8\'d229: sccb_data <= {16\'h370b,8\'h60};
331             8\'d230: sccb_data <= {16\'h370c,8\'h03};
332             8\'d231: sccb_data <= {16\'h3715,8\'h78};
333             8\'d232: sccb_data <= {16\'h3717,8\'h01};
334             8\'d233: sccb_data <= {16\'h371b,8\'h20};
335             8\'d234: sccb_data <= {16\'h3731,8\'h12};
336             8\'d235: sccb_data <= {16\'h3901,8\'h0a};
337             8\'d236: sccb_data <= {16\'h3905,8\'h02};
338             8\'d237: sccb_data <= {16\'h3906,8\'h10};
339             8\'d238: sccb_data <= {16\'h3b07,8\'h0a}; //帧曝光模式
340             8\'d239: sccb_data <= {16\'h4407,8\'h04}; //量化标度
341             default:sccb_data <= {16\'h300a,8\'h00}; //器件ID高8位
342         endcase
343     end
344 end
345 
346 
347 
348 endmodule

   ov5640的寄存器配置如上所示,可以配出 1024x768@30fps 的图像,该寄存器配置表同样来自正点原子的改编。注意一下,OV5640的寄存器地址是 16 位的,加上数据,sccb_data 的值为 24 位,这点和OV7670、OV7725不一样。

1、窗口输出的疑惑

其窗口输出分三个部分:

(1)ISP 输入窗口设置( ISP input size):0x3800~0x3807

(2)预缩放窗口设置( pre-scaling size) :0X3810~0X3821

(3)输出窗口设置( data output size) :0X3808~0X380B

   按照很多开发板提供的寄存器参考表确实能得到图像,但是很奇怪。首先 ISP 部分的寄存器。尽管输出分辨率很大(例如1024x768),但是很多人的ISP寄存器部分都是参照的 VGA(640x480)模式下的值,最后竟然也能输出。其次是预缩放窗口的寄存器,这个没有深究,仅仅试了下上下翻转和左右翻转。最后是输出窗口的寄存器,正点原子的还加上了0x380C~0x380F,而且和0x3808~0x380B是配合的。如果不改0x380C~0x380F,那还没什么问题,当我试着更改这些值时,有时会不出图像,有时图像会缩小或放大。

2、Pclk的疑惑

  OV7670 和 OV7725 的 Pclk 很容易通过 PLL 的调配得到,但是 OV5640 却不一样。首先,OV5640 的 PLL 有三个,如下所示:

8\'d4  : sccb_data <= {16\'h3035,8\'h21}; //PLL分频  11/1÷ 21/2÷ 32/3÷
8\'d5  : sccb_data <= {16\'h3036,8\'h69}; //PLL倍频  23/1x 46/2x 69/3x
8\'d6  : sccb_data <= {16\'h3037,8\'h03}; //PLL分频  bit[4]:0/1 bypass/÷2

   先说寄存器 16\'h3037寄存器,该寄存器默认值是03(也有很多人设为13),bit[4]的意思是旁路 PLL(即不管)或 2 分频,而 bit[3:0] 在 datasheet 中也有分频的意义,可却没有说明怎么回事。我这里设置 3037=03,即旁路pll,以下的说明都以这个为前提。

  然后是16\'h3035寄存器,该pll寄存器比较简单,其[7:4]的值代表着分频系数。

  最后是寄存器16\'h3036,这个寄存器的值就奇怪了,很多人写的是69,我研究发现 69 应该是 x3 的意思,相应的 23 是 x1,46 是 x2,当 3035 为 11 而 3036 为 23 时,fps为20,以此为基准就可以对这两个寄存器配置不同的值达到想要的帧率了,如下是我实验测得的不同配置下的 fps 值。(如何测量 fps 值在下一讲会整理)

  虽然 3036 寄存器和 3037 寄存器没有完全搞懂,但是用最傻瓜的办法还是得到了一些规律,至少可以得到一些想要的 fps 的值了。但是 Pclk 为多少呢?完全没办法知道!首先是这些测量结果和《ov5640寄存器参考列表》等PDF的值有出入,可能是设置窗口的数据和那些手册不完全一致。其次按道理说,fps 增大那么 Pclk 也会增大,但是我测量 Pclk 的结果却很诡异,根本不是那么回事。关于 Pclk 的相关资料很少,我实在搞不懂,如果有人知道,烦请指教一二。

  多说一句,OV7725 和 OV5640 的成像效果都很好,而 OV7670 的效果则非常差,我试了很多人的配置表,都是一样的效果,非常差劲。而且很奇怪的是,OV7670 的图像效果是旋转了 90 度的,非常别扭,我查看寄存器列表也没有发现改变旋转的寄存器配置。所以说,如果嫌 OV5640 贵,那可以用 OV7725,千万别为了便宜去买 OV7670,这个摄像头就是个垃圾,谁用谁恶心!

 

  至此,我们完成了 SCCB 的配置,下一讲的内容是 cmos_capture_rgb565,即 DVP 窗口输出的设置。

 

 参考资料:

[1]正点原子FPGA教程

[2]小梅哥《OV5640图像采集从原理到应用》

[3]开源骚客《SDRAM那些事儿》

[4]韩彬, 于潇宇, 张雷鸣. FPGA设计技巧与案例开发详解[M]. 电子工业出版社, 2014.

 

分类:

技术点:

相关文章: