链接:https://pan.baidu.com/s/1hmWm1w8Ny4Il25DIFR74Jw?pwd=1234
提取码:1234
OV5640_V5是豪威科技生产的500W像素的CMOS图像传感器,最高支持26241964分辨率(物理尺寸),对应25921944(图像尺寸)。输出支持DVP
接口,控制接口为标准的SCCB接口(兼容IIC)。
同时OV5640摄像头支持输出2592x1944分辨率以下任意分辨率的图像。
内部结构复杂,同时也不是FPGA图像采集的重点,我们将重点放在输出接口上。
首先摄像头采集图像数据,经过内部一系列的处理(放大、数字信号转换等),最终通过DVP端口输出,DVP本身拥有10位数据线,因此可输出10位RAW数据,但大多数情况下,使用8位数据线来输出RGB888及RGB565等格式,因此我们取高8位即可,舍弃掉了低2位。
OV5640采用16位(两个字节)表示寄存器地址,器件地址 7‘h3c
如下为SCCB写寄存器的示意图,
类似于VGA的行场同步信号,这里先不多介绍。
分析像素时钟pclk:
PCLK像素时钟:一个像素时钟输出一个像素(10位/8位),由于采用8位接口输出,那么每一个工作时钟pclk输出一个字节,对于RGB565格式来说,一个像素是16位,两个字节,所以花费两个像素时钟pclk才能输出一个16位的像素
,具体的16位数据中,哪几位表示红色绿色蓝色分量,也是通过寄存器配置。
这里到底像素时钟是多少,有分歧,有比较熟悉这块的大佬可以下面留言讨论。但是可以知道的是:PCLK是 OV5640输出数据时的同步信号,它是由 OV5640 输出的信号。
而XCLK为工作时钟,可以外接晶振或由外部控制器提供。
但是如果真的需要手动计算像素时钟那么公式如下
因此这里对于DVP 640 * 480 * 30fps标准来说,像素时钟的求解方式 : 物理分辨率 * 帧率 = 784 * 510 * 30 = 12Mhz
分析帧时序:
Vsync: 帧同步信号,高电平期间,输出一帧图像数据。
Hsyn/Href:行同步信号,高电平期间输出一行图像数据。
DVP接口时序参数,和VGA类似,在OV5640官方数据手册中根据输出图像分辨率查看各部分的时序参数即可。
如下是OV5640模块接口原理图:
18引脚应该是OV5640的工作时钟,但是由于默认输入工作时钟Xclk = 24Mhz
,因此18引脚为NC。
注意:OV5640 芯片的 DVP 接口本身拥有 10 位的数据线,可以输出 10 位的 RAW 数据,但是在大多数情况下我们使用的数据是八位的,因此只要DVP输出接口的高 8 位数据即可,因此只保留D[9:2],映射到接口OV-D0-7。
注意:上述电路的 OV_SCL 和 OV_SDA 没有连接物理上拉电阻,直接使用会出现问题,因此必须在Quartus II
软件的引脚配置中对这两处开启 FPGA 的 IO 片上上拉电阻,才能正常使用。
引脚解释如下:
OV5640的24Mhz工作时钟是由FPGA的PLL提供的,然后摄像头内部有自己的PLL,即可按照内部设计供给其内部各个模块使用,使得摄像头能正常工作。
OV5640上电时序:
其中DOVDD和AVDD器件自带,无需自己设计
module power_ctrl ( //OV5640上电控制
input clk , // 50MHz
input rst_n ,
output ov5640_pwdn , // ov5640掉电使能
output ov5640_rst_n , // ov5640复位
output power_done , // power_ctrl全面有效,相当于上电完成信号标志,SCCB可以开始工作
output reg [18:0] cnt_6ms ,
output reg [16:0] cnt_2ms ,
output reg [20:0] cnt_21ms //1050000刚好可以用21位二进制表示
);
localparam T2_6MS = 30_0000 ; // T2>=5ms取6ms,6ms=1000000ns,计数次数:1000000ns/20ns = 300000
localparam T3_2MS = 10_0000 ; // T3>=1ms取2ms
localparam T4_21MS = 105_0000 ; // T4>=20ms取21ms
//ov5640_pwdn掉电使能的设计,要求至少延迟5ms才能拉低,取6ms,另外也可直接将ov5640_pwdn赋值低电平0
//设计6ms计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt_6ms <= 0;
else if(ov5640_pwdn == 1'b1) begin //高电平掉电的时候计数
cnt_6ms <= cnt_6ms + 1'b1;
end
else
cnt_6ms <= cnt_6ms;
end
//当计数值大于等于6ms的时候,ov5640_pwdn赋值低电平。
assign ov5640_pwdn = (cnt_6ms >= T2_6MS) ? 1'b0 : 1'b1;
//ov5640_rst_n复位信号的设计,该信号至少延迟1ms,这里取2ms
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_2ms <= 'd0;
end
else if(ov5640_rst_n == 1'b0 && ov5640_pwdn == 1'b0) begin //相当于从还没开始复位以及上电使能信号刚来的时候开始进行2ms的计数
cnt_2ms <= cnt_2ms + 1'b1;
end
end
//低电平复位
assign ov5640_rst_n = (cnt_2ms >= T3_2MS) ? 1'b1 : 1'b0;
//power_done 上电完成的设计,要求是复位被拉高后,延迟至少20ms,才可进行SCCB/IIC配置,取21ms
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_21ms <= 'd0;
end
else if(power_done == 1'b0 && ov5640_rst_n == 1'b1) begin //上电还没完成且处于工作状态,就开始进行21ms的计数
cnt_21ms <= cnt_21ms + 1'b1;
end
else
cnt_21ms <= cnt_21ms ;
end
assign power_done = (cnt_21ms >= T4_21MS) ? 1'b1 : 1'b0; //上电完成的标志:如果计数大于或者等于21ms的时候就代表上电完成
endmodule
tb仿真:
`timescale 1ns/1ns //时间精度
`define clock_period 20 //时间周期
module power_ctrl_tb;
reg clk ; // 50MHz
reg rst_n;
wire ov5640_pwdn ; // ov5640掉电使能
wire ov5640_rst_n; // ov5640复位
wire power_done ;
wire [18:0] cnt_6ms;
wire [16:0] cnt_2ms ;
wire [20:0] cnt_21ms;
power_ctrl u1(
.clk(clk),
.rst_n(rst_n),
.ov5640_pwdn(ov5640_pwdn),
.ov5640_rst_n(ov5640_rst_n),
.power_done (power_done),
.cnt_6ms(cnt_6ms),
.cnt_2ms(cnt_2ms),
.cnt_21ms(cnt_21ms)
);
initial
clk = 0;
always #(`clock_period/2) clk= ~clk;
initial begin
rst_n=0;
#(`clock_period*5);
rst_n=1;
#1000000000;
$stop;
end
endmodule
如下是仿真波形图:
通过时间节点可看到,6ms的时候掉电使能有效,变成低电平,然后再延迟2ms,复位信号被拉高,然后再延迟21ms才能进行SCCB的配置,设计符合要求。
常用的摄像头还有OV7670、OV7725,各方面的时序与OV5640都是一致的,只是上电配置不同。
如有错误,请指正!