ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于FPGA的OV7725摄像头VGA显示:时序与SDRAM缓存设计

基于FPGA的OV7725摄像头VGA显示:时序与SDRAM缓存设计 简介这份基于FPGA的OV7725摄像头采集与VGA显示工程面向嵌入式视觉开发者与FPGA学习者完整演示了CMOS图像传感器数据采集、图像处理、同步时序生成到640x480 VGA输出的全流程可作为摄像头显示项目的参考原型。压缩包共133个文件以Verilog源码.v为核心配套.ucf引脚约束、.bit配置文件、.ngc网表、.xise工程文件及仿真/综合日志另含PDF说明文档。整体仅6.58MB结构清晰便于快速定位各模块。已有520人学习下载。工程涵盖OV7725寄存器配置I2C、像素数据同步与缓存、RGB色彩转换以及VGA行场时序控制等关键环节源码分层明确注释细节有助于理解FPGA图像处理与Spartan系列器件资源分配。通过综合、实现与下载流程读者能直接将设计部署到开发板适合作为课设、竞赛或入门实战的参考。1. OV7725 接 VGA 显示 640x480问题往往不在摄像头而在时序一个 OV7725 摄像头模块、一块带 SDRAM 的 FPGA 开发板、一个 VGA 接口目标是把实时图像显示在 640x480 分辨率的显示器上。这个需求在 FPGA 入门项目里非常经典但很多人在第一次上板时会发现摄像头能出图VGA 有彩条合在一起却黑屏或者花屏。原因往往不是摄像头坏了而是 OV7725 的输出时序和 VGA 的输入时序没有对齐中间缺了一个完整的数据通路设计。这篇文章要解决的就是这条链路里最关键的三件事OV7725 的寄存器配置、VGA 的 640x48060 时序参数、以及 SDRAM 帧缓存的数据调度。适用对象是已经会写基础 Verilog、想完成一个带摄像头的完整图像项目的开发者。读完你能直接照参数配置也能根据现象判断问题出在哪个模块。2. 先把 OV7725 的 DVP 接口和 VGA 显示时序对齐2.1 DVP 接口的信号组成与极性问题OV7725 属于典型的 DVPDigital Video Port接口摄像头引脚不多但每个信号都有自己的时序要求。它输出的信号包括 PCLK像素时钟、VSYNC帧同步、HREF行有效、D[7:0]像素数据。其中 HREF 高电平期间每个 PCLK 上升沿输出一个像素一个行周期内有 640 个有效 PCLK 就是 640 像素宽VSYNC 标志一帧的开始和结束。这里有一个经常被忽略的点OV7725 的 VSYNC 有极性选项由寄存器 0x0D 的第 6 位控制。默认情况下是低电平有效但有些开发板原理图上加了反相器导致波形极性反了。如果你在 FPGA 里用posedge VSYNC来同步帧起点一旦极性和实际不符采集的起始位置就会偏移表现出来就是图像上下错位。HREF 同样要注意。DVP 接口在 HREF 为高时输出有效像素但某些配置下 HREF 会变成行场复合信号。为了避免这类问题建议固定采用独立 VSYNC HREF模式并把寄存器 0x0D 的 VSYNC 极性设为与硬件原理图一致。VGA 这边的 HSYNC、VSYNC 极性也有标准下面会给出具体参数表。2.2 640x480 的 VGA 时序参数表VGA 640x48060 是行业标准时序来自 VESA 的 DMT 规范。你需要关心的不只是有效区 640x480而是完整的一行和一帧包含同步、后沿、有效、前沿四个阶段。FPGA 工程师通常把这四个阶段合成一个行计数器和一个场计数器。下面的表格是实际工程中直接可用的参数单位像素时钟周期像素时钟 25 MHz项目行方向场方向同步脉冲962后沿4833有效区640480前沿1610合计800525注意行方向合计 800 个像素时钟帧方向合计 525 行。25 MHz x 800 x 525 10.5 MHz x 1000 10.5e6 x 50 实际刷新率约 59.5 Hz接近 60。这个参数下 HSYNC 和 VSYNC 都是低电平有效。图像在显示器上要稳定必须保证行场计数器的起始位置和显示器期望的同步头一致差一个计数周期都不会黑屏但画面会有偏移。2.2.1 VGA 针脚定义与 FPGA 引脚约束VGA 接口是模拟 RGB 数字同步的混合接口。FPGA 输出的 RGB 是数字信号需要通过电阻网络通常是 R-2R 或权电阻转换成模拟电压。红、绿、蓝各 3 位是常见的低端配置共 262144 色。引脚约束时注意 HSYNC 和 VSYNC 要分配到 FPGA 的普通 IORGB 信号走同一 bank 并尽量靠近。一个常见错误是没有约束 IO 标准为 LVCMOS33导致信号电平太低显示器显示颜色偏暗。在 Xilinx 的 XDC 或 Altera 的 QSF 里VGA 相关引脚都要显式设置 IO 标准不能依赖默认值。2.3 为什么必须加 SDRAM 缓存如果直接把 OV7725 的像素数据接到 VGA你会发现画面是滚动的、撕裂的。原因很简单OV7725 的输出像素时钟和 VGA 所需的 25 MHz 像素时钟并不同源频率有差异相位更不可能对齐。就算你用 PLL 把两个时钟调到非常接近行场信号的频率不同步依然会撕裂。缓存的意义不是存一帧数据而是解耦摄像头写时钟和 VGA 读时钟。常见方案是 SDRAM 帧缓存。摄像头连续把数据写入 SDRAM 的一个帧区域VGA 端在同一时间从另一个帧区域读取数据。当摄像头写完一整帧交换读写区域这就是乒乓操作。至于 SDRAM 的选型入门开发板上最常见的 SDR SDRAM 16 位宽、时钟 100 MHz 就足够应付 640x48060。因为一帧像素约 614400 个每个像素 16 位一帧数据约 1.2 MB。SDRAM 在 100 MHz 时带宽约 200 MB/s而摄像头和 VGA 两端合计带宽约 50 MB/s余量充足。关键是 SDRAM 控制器要有突发读写能力否则频繁换行会浪费大量时钟周期。3. OV7725 寄存器配置直接照抄的初始化清单3.1 SCCB 接口的 I2C 时序要点OV7725 的寄存器读写走的是 SCCB形式上和三线 I2C 几乎一样。FPGA 端只要实现一个标准 I2C 主机控制器即可工作频率建议不高于 400 kHz。OV7725 的器件地址固定为 0x428 位写地址对应 7 位地址 0x21。很多人在这一步卡住因为部分资料写的是 7 位地址 0x21而你在 I2C 发送时要左移一位变成 0x42。具体写寄存器的流程是发送起始位、发送器件写地址 0x42、等待 ACK、发送寄存器地址、等待 ACK、发送寄存器值、等待 ACK、发送停止位。整个流程用状态机实现非常简单。下面给出一个最简 Verilog 单字节写控制器的核心代码框架module i2c_wr_byte #( parameter CLK_FREQ 50_000_000, parameter SCL_FREQ 200_000 )( input wire clk, input wire rst_n, input wire start, input wire [7:0] dev_addr, // 7bit 左移后的地址通常直接传 8h42 input wire [7:0] reg_addr, input wire [7:0] reg_data, output reg done, output reg ack_err, inout wire scl, inout wire sda ); // 分频计数每 bit 的时钟周期数 localparam BIT_CNT CLK_FREQ / SCL_FREQ; reg [15:0] cnt; reg [3:0] bit_idx; // 9 bit 8 数据 1 ACK reg [3:0] state; reg [7:0] tx_data; reg scl_out; reg sda_out; reg sda_oe; // SCL 高电平期间才采样 SDA这是 I2C 时序的核心 // 状态机按 SCL 低/高/低切换推进每个 SCL 周期采样一次 SDA // 起始条件SCL 高时 SDA 拉低 // 停止条件SCL 高时 SDA 拉高 // 数据发送高位在前每 bit 在 SCL 低电平时准备好 SDA endmodule上面的代码只给出了接口和关键思路因为完整 I2C 控制器代码接近两百行很多开发板例程里都有现成的。我更想强调的是几个容易出错的细节第一SDA 在 SCL 为高时必须保持稳定只有 SCL 为低时才能变化。第二ACK 检测要在第 9 个时钟周期进行OV7725 在收到正确地址后会将 SDA 拉低表示应答。如果 ACK 信号一直高说明摄像头没有正常上电或者地址不对。第三每次写寄存器之间最好加一个小的延时不需要很长几十微秒即可让摄像头内部逻辑有时间稳定。3.2 必配寄存器清单与参数说明OV7725 的寄存器很多但做 640x480 RGB565 输出真正必须动的手不超过八个。下面的参数表是我在多个工程里验证过、可以直接用于初始化的最小集合。地址寄存器名值说明0x12COM70x060x06 是 RGB565 输出bit7 清零表示不复位0x15COM100x00PCLK 不反相VSYNC 低有效HREF 高有效0x0DCOM40x41使能 PLLPLL 倍频系数 4 倍0x11CLKRC0x00内部时钟不分频取决于外部输入时钟0x17HSTART0x26水平有效窗口起始位置高字节0x18HSIZE0xA0水平窗口尺寸640 对应 0xA00x19VSTART0x07垂直有效窗口起始位置0x1AVSIZE0xF0垂直窗口尺寸480 对应 0xF00x2AEXHCH0x00窗口尺寸高位扩展默认即可关于窗口寄存器需要多说两句。OV7725 内部感光区实际上是 640x480 的整数倍窗口寄存器决定从哪个位置开始截取数据。如果 HSTART、VSTART 配错图像会偏但不会花屏。花屏通常不是窗口问题而是格式问题。RGB565 输出时每个像素需要两个 PCLK 周期分高低字节输出顺序由寄存器 0x2A 的 bit1 控制。默认是低字节在前而 VGA 端拼接时如果顺序反了图像颜色会完全错乱表现为红蓝互换或彩色噪点。这是一个非常隐蔽的坑我在调试时一度以为是 SDRAM 数据位接反了最后查出来是输出顺序配置。3.3 初始化的状态机顺序寄存器的写入顺序也有讲究。OV7725 手册建议先把时钟相关寄存器配好再配置输出格式和窗口。一个可靠的状态机顺序是上电延时 → 复位往 0x12 写 0x80→ 延时 → 配置 PLL 和时钟 → 配置输出格式 → 配置窗口 → 配置测试图案可选。上电后至少等待 20 ms确保晶振稳定 写 0x12 0x80让摄像头软复位 延时 10 ms 写 0x0D 0x41打开 PLL 写 0x11 0x00PCLK 分频 写 0x12 0x06RGB565 写 0x15 0x00时序极性 写窗口寄存器 0x17~0x1A这个顺序里最容易出错的是复位后没有等待足够长时间。有人写完 0x120x80 后立刻继续写其他寄存器此时摄像头还在复位状态后续配置全部丢失。上板调试时如果摄像头没有输出先加长复位后的延时再试。4. VGA 时序发生器与 SDRAM 读写调度实现4.1 VGA 时序生成器的 Verilog 实现VGA 时序发生器是整个项目里最容易验证、也最适合做自检的模块。标准做法是两个计数器一个像素计数器 h_cnt 和一个行计数器 v_cnt。h_cnt 从 0 数到 799v_cnt 从 0 数到 524然后根据前面的参数表生成 HSYNC、VSYNC 和 DE数据有效信号。reg [9:0] h_cnt; reg [9:0] v_cnt; always (posedge clk_25m or negedge rst_n) begin if (!rst_n) begin h_cnt 0; v_cnt 0; end else begin if (h_cnt 799) begin h_cnt 0; if (v_cnt 524) v_cnt 0; else v_cnt v_cnt 1; end else begin h_cnt h_cnt 1; end end end assign hs (h_cnt 96) ? 1b0 : 1b1; // 行同步低有效 assign vs (v_cnt 2) ? 1b0 : 1b1; // 场同步低有效 assign de (h_cnt 144) (h_cnt 784) (v_cnt 35) (v_cnt 515); // 有效区这段代码里 h_cnt 和 v_cnt 都是 10 位足够容纳 800 和 525。de信号的边界就是 VGA 的有效显示区域行方向从 144 到 783共 640 个像素场方向从 35 到 514共 480 行。当 de 为高时把 SDRAM 读出的像素数据送到 RGB 引脚。这里有一个调试技巧先把 RGB 绑定成几个固定值比如把红色通道在 de 区域全部置 1绿色和蓝色清零。如果显示器出现一个标准的红色纯色块说明时序完全正确。再用同样的方法逐一切换红、绿、蓝就能确认三条颜色通道的电阻网络都正常。这个自检步骤要在接摄像头之前做否则无法区分是时序问题还是摄像头数据问题。4.2 SDRAM 控制器的跨时钟域策略SDRAM 控制器本身是一个相对独立的大模块这里不展开全部代码重点讲清楚数据通路的组织方式。摄像头端的写时钟是 PCLKVGA 端的读时钟是 25 MHz两者都进 SDRAM 控制器所在的 100 MHz 时钟域。为了隔离时钟域PCLK 进来的数据先写入一个异步 FIFO。FIFO 的写端口是 PCLK 域读端口是 SDRAM 控制器时钟域。当 FIFO 里积累了一行或半行数据SDRAM 控制器就发起一次突发写。VGA 端同理SDRAM 控制器先从内存突发读出一行数据放入另一个 FIFOVGA 时序模块在 de 有效时从 FIFO 读取像素。这个方案的核心价值在于SDRAM 控制器只面对一个时钟域不需要在控制器内部做跨时钟处理而是用两个 FIFO 在两端做缓冲。FIFO 的深度至少能容纳一行数据640 像素 x 16 位 1280 字节实际取 2048x16 比较保险。更小的深度会因为 SDRAM 刷新或换行操作而出现空读或溢出。4.2.1 乒乓帧存实现细节帧存乒乓操作通过一个帧索引寄存器实现。摄像头端写满第 0 帧后把写地址切换到第 1 帧同时置一个标志位告诉 VGA 端可以读第 0 帧了。VGA 端检测到这个标志后在下一个场消隐期切换读地址。要注意的是切换必须在场消隐期进行不能在屏幕扫描中间切。否则画面会出现一条明显的横向撕裂线。最稳妥的做法是摄像头端写满一帧后先不切换等 VGA 端的 vsync 信号到来再切换写地址这样读写切换落在同一时间点显示器完全感觉不到变化。VGA 端的场消隐时间是 35 行大约 1.4 毫秒摄像头这边一帧数据有 480 行在这个窗口内完成切换绰绰有余。带宽评估也简单。一帧 640x480x2 字节约 614400 字节60 帧每秒约 36.9 MB/s。SDRAM 端实际上要同时承担读写总带宽约 74 MB/s 加上刷新开销。100 MHz 的 SDRAM 带宽 200 MB/s使用率不到一半所以不需要做多端口仲裁简单的时分复用就够。4.3 OV7725 像素采集模块的对齐问题像素采集模块在 PCLK 的上升沿采样 D[7:0]但要注意 OV7725 的 RGB565 输出在一个像素周期里分两次传输第一次传低字节第二次传高字节。你需要用 HREF 的低位或者 PCLK 的边沿来区分。一个常用的实现是维护一个字节计数器在 HREF 高电平时每个 PCLK 计数一次偶数时拼接成 16 位像素写入 FIFO。用直方图的方式统计 HREF 高电平期间的 PCLK 数量如果一组 PCLK 数量不是偶数说明你的采样时刻没有对准数据切换点图像会整体偏移颜色通道。这个对齐问题在仿真里很难发现因为仿真模型的数据变化时刻是理想的但实际芯片存在建立保持时间。排查方法是用 ILA 或逻辑分析仪抓 HREF 和 D 总线看数据是否在 HREF 为高后第一个 PCLK 就有效。5. 上板必查项与调试技巧5.1 用 OV7725 测试图案快速定位故障域OV7725 内置了一个测试图案发生器开启后不需要镜头和外部光线就能输出彩条。这在你手上没有示波器或者不想对着光照调试时非常有用。开启方法是往寄存器 0x12COM7写入 0x46即保留 RGB565 输出格式同时置位 bit2 使能测试图案。测试图案检查顺序 1. 将 0x12 设为 0x46观察 VGA 是否出现彩条 2. 如果出现彩条说明摄像头 I2C 配置和 VGA 通路正常 3. 如果出现固定颜色或灰屏先查 VGA 时序和 SDRAM 读写 4. 如果完全没有输出用逻辑分析仪查 I2C 是否有 ACK这个测试的神奇之处在于它能帮你把问题快速分成两半。彩条正常而镜头图像有问题问题一定在摄像头窗口配置或者光圈、镜头聚焦而不是 FPGA 逻辑。彩条不正常才有必要继续查时序和缓存。5.2 排查 VGA 花屏的三个层次第一层是颜色错乱比如红色变绿色通常是 RGB 引脚的约束顺序错误或者 SDRAM 数据位接反。第二层是图像倾斜但有完整内容一般是 HSTART 窗口偏了调整寄存器。第三层是横向撕裂大概率是帧切换没有同步到场消隐。VGA 无信号的排查要看 HSYNC 和 VSYNC 的极性。早期显示器对极性不敏感但部分 LCD 显示器对极性有严格要求。如果你的行场计数器都对显示器却说无信号试着把低有效改成高有效或者在输出端加一个简单的一级 RC 滤波。5.3 最后一个实用的验证技巧当你把镜头对准一个移动物体画面出现拖影或物体边缘有彩色镶边时不要急着怀疑 SDRAM 带宽。先在 OV7725 的测试图案模式下抓一帧如果彩条边界清晰锐利说明 SDRAM 时序是好的问题出在摄像头的曝光或者自动增益设置上。OV7725 的自动曝光在光线快速变化时会有明显的延迟这是传感器的正常行为不是 FPGA 的 bug。反过来如果测试图案的边界是模糊的、边缘有一两个像素的渐变那就是 SDRAM 突发读和 FIFO 之间的衔接有问题需要在 VGA 端再多缓冲几个像素或者在 SDRAM 读数据时提前一拍取数。这个提前取数的时间差通常是 0 到 2 个像素时钟做一次全扫描比对就能找到最佳值。本文还有配套的精品资源点击获取
返回列表