第四章 图像采集接口设计:从摄像头到FPGA的最后一公里
图像采集接口,说白了就是摄像头和FPGA之间的「翻译官」。摄像头拍到的光信号转成电信号,但FPGA不认识啊,得有个接口把数据规规矩矩地送进来。我这些年做图像加速项目,踩得最多的坑就在这——接口没搞定,后面算法再牛也白搭。
今天咱们聊三个主流方案:OV5640/MT9V034的I2C配置、DVP并行接口、以及MIPI CSI-2。嗯,一个一个来。
4.1 摄像头配置:I2C总线上的「悄悄话」
摄像头传感器上电后,默认配置通常不是我们想要的。比如OV5640默认输出是640x480,但你想跑1080p,怎么办?得通过I2C总线给它写寄存器。
I2C是个双线协议:SCL(时钟)和SDA(数据)。摄像头作为从设备,FPGA作为主设备。我个人习惯把I2C控制器做成一个状态机,简单可靠。
核心要点:OV5640的I2C地址是0x3C(写)/0x3D(读),MT9V034是0x90(写)/0x91(读)。别搞反了,我刚开始就犯过这错。
写寄存器的流程很简单:
- 发起始位 + 设备地址(写)
- 等ACK
- 发寄存器高8位地址
- 等ACK
- 发寄存器低8位地址
- 等ACK
- 发数据字节
- 等ACK
- 发停止位
代码实现?给你看个核心片段:
// I2C写字节状态机 - 我自己项目里一直在用的模板
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
scl_out <= 1'b1;
sda_out <= 1'b1;
end else begin
case (state)
IDLE: begin
if (i2c_start_req) begin
state <= START;
bit_cnt <= 4'd8;
end
end
START: begin
// 拉低SDA,再拉低SCL
sda_out <= 1'b0;
state <= SEND_ADDR;
end
// ... 后续状态
endcase
end
end
我的经验:I2C时钟频率别超过400kHz,OV5640对时序挺敏感的。我曾经为了赶速度把时钟提到1MHz,结果摄像头死活不响应,查了两天才发现是时序违规。
4.2 DVP接口:并行数据的「老黄牛」
DVP(Digital Video Port)是经典的并行接口。信号线包括:
- PCLK:像素时钟,每个上升沿采一个像素
- VSYNC:帧同步,高电平表示一帧开始
- HREF:行同步,高电平表示一行有效数据
- DATA[7:0]或DATA[9:0]:像素数据
时序其实很简单:VSYNC拉高后,HREF会一行一行地拉高,每拉高一次就传一行像素。PCLK每个上升沿采一个字节(8位)或一个字(10位)。
嗯,这里要注意:OV5640的DVP模式输出是10位数据,但很多项目只用高8位。我个人习惯把低2位丢掉,省事。
避坑指南:我曾经遇到过VSYNC和HREF的极性搞反的问题。有些摄像头是低电平有效,有些是高电平有效。一定要看数据手册的时序图,别想当然。
Verilog实现的核心是行缓存:
// DVP数据采集 - 我常用的写法
always @(posedge pclk or negedge rst_n) begin
if (!rst_n) begin
pixel_data <= 16'd0;
pixel_valid <= 1'b0;
end else begin
if (href && !vsync) begin // 行有效且不在帧消隐区
// 拼接两个8位数据成一个16位像素
if (pclk_cnt == 0) begin
pixel_data[15:8] <= dvp_data;
pclk_cnt <= 1;
end else begin
pixel_data[7:0] <= dvp_data;
pixel_valid <= 1'b1;
pclk_cnt <= 0;
end
end else begin
pixel_valid <= 1'b0;
pclk_cnt <= 0;
end
end
end
DVP的优点是简单,缺点是线太多。8位数据就要10根线(8数据+2同步),要是跑1080p@60fps,PCLK得跑到148.5MHz,信号完整性就开始头疼了。
4.3 MIPI CSI-2:高速串行的「新贵」
MIPI CSI-2是现在手机摄像头的主流接口。它用差分信号传输,数据线可以1条、2条或4条lane。每对差分线传输速度能到1Gbps以上。
物理层用的是Sub-LVDS(低压差分信号),电压摆幅只有200mV左右。FPGA接收的时候需要专门的硬核(比如Xilinx的ISERDES)或者外部接口芯片。
关键区别:DVP是并行总线,MIPI是串行差分。MIPI的优势是线少、速率高、抗干扰强。但实现复杂度也高了一个数量级。
MIPI CSI-2的协议层分三层:
- PHY层:处理电气特性、时钟恢复、串并转换
- Lane管理层:数据分发、字节对齐、ECC校验
- 协议层:解析帧头帧尾、数据类型(RAW8/RAW10/YUV等)
说实话,在FPGA里完整实现MIPI CSI-2接收端是个大工程。我建议的做法是:
- 用厂商提供的IP核(Xilinx MIPI CSI-2 RX Subsystem)
- 或者用外部桥接芯片(比如TI的DS90UB系列)转成并行
- 实在要自己写,至少准备好眼图仪和高速示波器
我的建议:初学者先从DVP入手,把I2C配置和行场同步搞明白。MIPI等有高速设计经验了再碰。我当年第一次调MIPI,光眼图就调了两周。
4.4 知识体系总览
下面这张图是我自己总结的,把三个接口的关系和选择逻辑画清楚了:
4.5 实际项目中的选择策略
我做过几个图像加速项目,总结下来:
| 应用场景 | 推荐摄像头 | 接口方案 | 我的备注 |
|---|---|---|---|
| 工业检测(VGA级别) | MT9V034 | DVP | 全局快门,适合拍运动物体 |
| 安防监控(1080p) | OV5640 | DVP或MIPI | OV5640两种接口都支持 |
| 手机/车载(4K以上) | IMX系列 | MIPI CSI-2 | 必须用FPGA硬核或桥接芯片 |
重要提醒:不管选哪种接口,I2C配置都是第一步。摄像头不上电配置好,后面啥都干不了。我习惯先把I2C读写调通,再用逻辑分析仪抓一下寄存器回读,确认配置写进去了再往下走。
嗯,图像采集接口这块就聊到这儿。说白了就是根据你的分辨率和帧率需求,选一个合适的接口方案。DVP适合练手和低分辨率项目,MIPI是未来趋势但门槛高。我个人建议:先把DVP玩透,再碰MIPI,这样基础扎实。