ARTICLE DETAIL

资讯详情

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

FPGA读写OV5640摄像头显示例程:图像采集与显示路径详解

FPGA读写OV5640摄像头显示例程:图像采集与显示路径详解 简介本资源是一套完整的FPGA驱动OV5640摄像头并实现视频显示的工程实践方案面向数字电路与嵌入式图像处理方向的初学者及进阶开发者解决高分辨率图像采集、SDRAM缓存与多接口显示VGA/LCD协同设计等典型难点。压缩包共1027个文件包含267个Quartus编译数据库cdb/hdb、81个Verilog源码v、42个内存初始化文件mif、19个Quartus项目配置qip、16个综合报告rpt及3个PDF文档说明总大小22.31MB覆盖从I²C配置、像素时序控制、SDRAM读写仲裁到VGA时序生成的全链路逻辑。已有2620人学习下载提供可直接编译运行的Quartus 17.1工程EP4CE6F17C8平台含顶层模块top.v及完整引脚约束、寄存器配置参数与RGB565数据流路径注释便于理解图像流水线架构与跨时钟域处理设计。 FPGA读写OV5640摄像头显示例程这类工程在初学者和进阶工程师之间一直有着很高的关注度。它不像点灯、按键那么基础也不像图像识别算法那样需要大量数学基础而是恰好卡在需要一点逻辑设计能力、又能很快看到实际图像效果的位置。拿到这套Verilog源码加Quartus工程文件时我第一反应是这套资料的价值不在于代码本身而在于它完整串起了一条图像采集、缓存、显示的硬件数据通路。这套工程跑通一遍等于把FPGA开发里最核心的跨时钟域处理、状态机设计、时序约束这些硬功夫都过了一遍而且摄像头模块价格不高开发板也便宜作为进阶练习非常合适。先说清楚一个前提OV5640这颗传感器在入门级FPGA开发板上的出场率极高但它并不是一个插上就能用的器件。它上电后默认输出可能是UXGA格式分辨率、帧率、输出格式都不一定符合你的显示需求所以必须先通过SCCB接口兼容I2C协议对它做寄存器配置。然后DVP并行接口会持续输出PCLK、VSYNC、HREF和8位像素数据FPGA需要按照严格的时序把这些数据采集下来缓存在FIFO里最后在显示端按VGA或RGB LCD的时序逐行读出。这条链路任何一个环节出错表现出来都是花屏、黑屏或者颜色错乱。下面我按照从整体到细节的顺序把这套例程的关键设计思路、代码实现方式和调试经验完整拆一遍。1. 项目整体设计与方案选型思路1.1 这套例程解决的核心问题这套例程要解决的核心问题可以概括成一句话让FPGA稳定地从OV5640摄像头拿到实时图像数据并流畅地显示到屏幕上。听起来简单但实际拆解下来涉及不少环节。OV5640输出的是并行数字视频流它和FPGA之间没有专门的握手协议所有同步信息都包含在VSYNC、HREF、PCLK这三个信号里。FPGA要做的事情就是识别出每一帧的起始位置、每一行的有效数据区间然后把数据按顺序存下来再按目标显示设备的时序要求送出去。这里有一个典型的工程选型问题为什么很多例程选择OV5640而不是更便宜的OV7725或者其他传感器原因在于OV5640的输出格式非常灵活它内部自带ISP能直接输出RGB565省去了在FPGA里做色彩插值和白平衡的麻烦。对于FPGA初学者来说能拿到干净的RGB数据相当于把最重要的精力集中在数据通路上而不是花大量时间调图像质量算法。1.2 整体架构中的数据流与控制流整个工程可以按照数据流和控制流两条主线来理解。数据流从摄像头开始经过DVP接口进入FPGA的采集模块采集模块把并行字节流拼接成16位RGB565像素随后写入异步FIFO显示驱动模块再从FIFO读出一行行数据按扫描时序送到屏幕。控制流则相对独立主要通过SCCB接口操作OV5640内部寄存器。这个模块不受像素时钟控制而是在上电后按顺序把寄存器地址和配置值写进传感器配置完成后就不再动作。把控制流和数据流分离是这套工程结构清晰的关键。很多初学者写代码时喜欢把寄存器配置和数据采集混在一起结果调试时分不清问题是出在传感器没配置好还是采集逻辑有bug。1.3 为什么选择Verilog和Quartus组合Verilog和Quartus是FPGA开发里最经典的一套组合尤其对于Intel原Altera系列芯片来说Quartus是官方工具链对自家器件支持最完善无论是综合、布线还是在线调试都集成在一个环境里新手上手成本低。选择Verilog而不是VHDL主要是因为图像处理领域的开源资料和参考代码绝大多数都是Verilog写的你在网上搜OV5640 Verilog源码能搜出大量可参考的工程但搜VHDL版本就少得多了。对于学习来说资料数量决定了你踩坑后能多快找到答案。另外这套例程用的是模块化设计每个功能块一个.v文件这种组织方式在多人协作或工程复用时有明显优势移植到Vivado工程也相对容易。2. 核心模块拆解与关键细节2.1 SCCB控制器配置OV5640的起点整个工程的第一个难点出现在SCCB控制器上。OV5640的SCCB协议和I2C非常相似但存在一些细微差别比如SCCB的读操作不支持连续读写操作也需要在发送从机地址后紧跟寄存器高字节地址和低字节地址总共三个字节的地址信息这和标准I2C的寄存器写操作不同。实现SCCB控制器时状态机的设计至关重要。我推荐使用一个状态机配合字节计数器和移位寄存器的结构一进入发送字节状态就按位把8位数据放到SDA上每个SCL高电平期间数据必须稳定发送完一个字节后切换到等待ACK状态释放SDA线在SCL高电平期间采样SDA的电平低电平表示从机应答正常。需要注意的是一旦检测到NACK不要再继续后续配置而是应该回到IDLE状态并上报错误标志位。时钟分频方面OV5640的SCCB接口最高支持400kHz但为了波形稳定和时序裕量我通常把SCL频率配置在100kHz~200kHz之间。在主时钟50MHz的情况下分频系数选250可以很干净地得到200kHz。这个频率在实际使用中完全没有问题而且对线材的容忍度更高不容易出现偶发配置失败。2.2 寄存器配置表的结构与配置顺序OV5640的寄存器多达几百个但绝大多数保持默认值即可正常输出图像。这套工程里的配置表通常包含几类关键的寄存器系统控制软复位、时钟配置、输出格式RGB565还是YUV、分辨率设置包括窗口裁剪和输出尺寸、以及镜像翻转等控制位。配置顺序上有一个非常重要的细节必须先软复位再写其他配置最后延时等待内部PLL稳定后再执行一次软复位。如果不按这个顺序操作部分寄存器可能无法生效表现为画面颜色不对或者分辨率修改无效。很多人在调试时遇到寄存器写进去但画面不变的问题八成就是配置顺序不对写在复位之前的寄存器都被复位逻辑清掉了。寄存器配置表在代码里通常实现为一个常量数组或ROM通过查表方式逐个发送。这种实现方式的好处是后续想切换分辨率或者输出格式只需要改数组内容不用动状态机逻辑。我在实际工程中会把寄存器配置表单独放在一个.v文件中并且加上注释说明每个配置项的作用方便以后对照datasheet排查问题。2.3 DVP接口时序理解VSYNC/HREF/PCLKDVP接口的时序理解是整个工程的基石。PCLK是像素时钟每个上升沿对应8位数据的有效传输HREF为高电平时表示当前正在输出一行有效像素数据VSYNC则标记一帧的开始。这里需要特别注意OV5640的VSYNC极性默认是低电平有效也就是说VSYNC拉低表示新的一帧开始了。以640x48030fps模式为例PCLK大约为24MHz每行包含640个有效像素加上若干消隐像素HREF高电平期间正好对应640个有效像素。FPGA在这段时间内每个PCLK上升沿采样一次数据两个8位数据拼接成一个16位RGB565像素。我踩过一次坑是代码里直接用了HREF作为数据有效信号但忽略了HREF内部的毛刺或者亚稳态问题。HREF和数据线DATA是相对PCLK对齐的从传感器内部同步输出理论上不需要再打拍但工程上为了安全我会在采集模块入口对HREF、VSYNC、DATA先做一次寄存器打拍消除可能的亚稳态。代价是数据延迟一拍需要在后续处理里做对齐补偿。2.4 跨时钟域FIFO从PCLK域到显示时钟域摄像头输出的PCLK和显示驱动的像素时钟是两个完全独立的时钟域频率不一定相同相位更是毫无关系。直接把一端的信号交给另一端使用必然产生亚稳态问题。工程中标准的解决方式是使用异步FIFO写入端使用PCLK读出端使用显示像素时钟。在Quartus中可以直接调用FIFO IP核设置读时钟和写时钟为不同的时钟内部会自动处理跨时钟域同步逻辑。FIFO深度建议不要选太小至少能装下一整行数据我这里选的是2048x16位装一行640像素绰绰有余还能预留一定的容错空间。如果选得太浅显示端偶尔会因为FIFO空而出现行撕裂现象。关键点是FIFO的复位信号。很多例程在VSYNC到来时对FIFO做同步复位希望保证每一帧从干净状态开始写。但我发现这种复位方式在高速PCLK下容易出问题因为FIFO IP核的复位信号本身需要满足一定的时序要求如果复位脉冲宽度不足反而会导致FIFO写指针状态异常。更稳妥的做法是在上电初始化完成后保持FIFO不复位写端在检测到VSYNC下降沿后的第一个有效HREF时才开始写读取端等待FIFO达到半满阈值后才开始读。2.5 显示驱动VGA还是RGB LCD显示驱动模块相对模式化无论是VGA还是RGB LCD本质都是按照固定的行场时序产生同步信号和数据。工程里如果用VGA输出时序参数需要查标准规范640x48060Hz的行周期是800个像素时钟其中有效区640个同步脉冲96个前后肩分别16和48场周期是525行其中有效行480行同步脉冲2行前后肩分别10和33。显示驱动的核心是由两个计数器产生像素位置信息然后根据位置确定当前是否处于有效显示区。当处于有效区时从FIFO读出像素数据并送到RGB输出端口同时置位数据有效信号处于消隐区时输出默认的消隐电平。需要留意的是VGA的行场同步信号极性是负极性也就是说同步脉冲是低电平而很多RGB LCD屏要求的是正极性如果直接用同一套代码接不同设备就会出现画面偏移或者完全无显示的现象。3. 实操过程与核心环节实现3.1 工程结构规划与文件组织拿到压缩包后第一步我建议先把工程文件在目录里重新组织一下不要直接暴力解压到桌面就开搞。推荐按功能划分目录rtl目录放所有Verilog源文件其中按模块分开命名比如i2c_master.v、ov5640_init.v、ov5640_capture.v、fifo_wrapper.v、vga_driver.vip目录放Quartus生成IP核doc目录放寄存器配置表和调试记录quartus目录放工程文件。这种结构的好处是后续如果要换FPGA型号或者移植到Vivado只需要处理接口适配部分核心逻辑模块可以原样复用。Quartus工程里添加文件时建议通过Project Navigator里的Add/Remove Files操作而不是手动把文件复制进目录列表这样工程文件路径会自动处理避免路径错误导致的编译失败。3.2 顶层模块的信号规划顶层模块是整个工程的总装图需要规划好所有对外接口和内部模块之间的信号连接。对外接口可以分为三类系统时钟与复位、摄像头接口、显示接口。摄像头接口包括SCCB的scl和sda注意sda是双向信号以及DVP的pclk、vsync、href、data[7:0]。显示接口则根据选择的是VGA还是RGB LCD来定义VGA需要rgb[15:0]或rgb[11:0]、hsync、vsyncRGB LCD则可能需要de、clk和同步信号。内部模块之间的信号连接要注意几个容易出错的地方。SCCB控制器的sda是inout类型在顶层要用三态缓冲处理采集模块输出的fifo_wrreq信号必须只在像素有效时拉高显示驱动模块从FIFO读取时要判断空标志防止读出无效数据。复位模块的设计也建议认真对待。整体复位采用异步复位、同步释放的方式避免复位信号释放时和时钟沿竞争产生亚稳态。对于摄像头采集部分还要额外生成一个由PCLK同步的软复位信号用于在寄存器配置完成后复位采集状态机保证从一帧的起始位置开始采集。3.3 采集模块的Verilog实现思路采集模块的状态机是整个工程的核心。设计时要考虑三个关键的边界情况帧起始位置、行起始位置、像素数据对齐。帧起始通过检测VSYNC下降沿来识别但VSYNC存在消隐区所以更稳健的做法是检测到VSYNC下降沿后等待第一个HREF上升沿作为帧有效数据的开始。行内数据则通过HREF高电平来选通每个PCLK上升沿采一个字节。这里需要注意RGB565模式下每个像素需要两个字节所以要定义一个位计数器偶数位到达时拼成16位数据同时产生一个像素有效脉冲。一个典型的采集逻辑可以用always块描述检测到HREF拉高时启动字节计数每个PCLK上升沿采样数据写入移位拼接寄存器。当计数器计到1第二个字节时把拼接好的16位数据锁存到输出寄存器同时拉高fifo_wrreq一个周期。HREF拉低时清空计数器等待下一行。每检测到一个新帧清零相关计数器确保帧内数据连续正确。这里我要特别提一个处理细节fifo_wrreq信号的时序。写入FIFO的数据和写请求信号应该对齐而且写请求是在PCLK上升沿之后产生所以建议使用非阻塞赋值在一次时钟沿同时更新数据总线和写请求信号避免出现数据比写请求早一个周期导致写入错误像素的情况。3.4 在Quartus中创建工程与IP核配置具体操作上打开Quartus后选择File - New Project Wizard指定工程目录和工作目录选择目标FPGA型号。创建完成后在Project Navigator里添加所有.v源文件。然后通过IP Catalog添加PLL和FIFO。PLL配置时输入时钟频率根据开发板晶振设置输出时钟根据模块需求设置。一般配置三路输出一路24MHz给SCCB控制器分频使用一路24MHz给采集模块采样参考一路25.175MHz给VGA驱动标准VGA像素时钟实际上25MHz也可以刷新率会稍有偏差但不影响显示。FIFO IP核配置时重点注意时钟设置选项选择独立时钟模式并勾选上自动清空选项show-ahead模式。数据宽度为16位深度为2048。读侧设置预读first-word fall-through模式可以简化显示驱动的读取逻辑因为数据提前出现在总线上读取端只需在有效显示区持续拉高读请求即可。3.5 编译、约束与下载调试编译完成后需要处理时序约束。Quartus会自动根据时钟约束进行时序分析但在代码里还是要写一条主时钟约束指明板载晶振的时钟频率。一个简单的SDC约束如下create_clock -period 20.0 [get_ports {clk_50m}]针对FIFO和跨时钟域部分Quartus可能会报出跨时钟域警告这是正常的因为两个时钟域原本就没有同步关系只要FIFO IP核内部做了同步处理就可以。如果时序报告中出现建立时间违规优先检查采集模块组合逻辑是否过于冗长必要时插入流水线寄存器比如在DVP数据输入到拼接逻辑之间打一拍。下载调试常用工具是SignalTap II Logic Analyzer。建议在工程中添加一个STP文件观察FIFO的写计数、读计数、wrreq、rdreq以及VSYNC和HREF的实时状态。通过观察FIFO空满标志的变化频率能直接判断采集速率和显示速率是否匹配。如果FIFO经常处于满状态说明显示端速度跟不上需要调高显示时钟或降低采集帧率如果FIFO经常为空则说明写入数据不足需要检查采集模块的像素有效信号是否正常产生。4. 常见问题与排查技巧4.1 画面全黑或灰屏的原因全黑或灰屏问题出现概率最高但定位起来也比较直接。首先确认摄像头是否工作看OV5640的XVCLK引脚是否有24MHz时钟输入传感器电源电压是否正常特别是DVDD和AVDD是否达到手册要求的电压值。使用杜邦线连接时经常出现SCCB的SDA或SCL接触不良导致寄存器配置失败最直接的现象就是画面全黑且I2C状态机处于无响应状态。寄存器配置失败时建议先用逻辑分析仪或者SignalTap抓取I2C时序确认设备地址是否正确各寄存器的ACK应答是否正常。如果从机始终不回ACK大概率是模块没有正常上电复位或者SDA上拉电阻缺失。检查I2C总线上是否加了3.3V上拉电阻上拉电阻阻值建议在2.2k到4.7k之间。另一个容易被忽略的原因是初始化等待时间不足。OV5640上电后需要至少1ms的稳定时间之后才能开始写寄存器配置否则部分配置会写入失败。工程里的初始化模块最好加入一个上电延时计数器等待时间在2ms以上再开始SCCB写操作。4.2 画面花屏或条纹状干扰花屏通常意味着像素数据错位或FIFO读写速度不匹配。如果是竖条纹或斜条纹优先检查采集模块的像素拼接逻辑。RGB565模式下高字节和低字节的顺序本文还有配套的精品资源点击获取
返回列表