将小组件嵌入到你自己的网站
将以下代码片段添加到你的 HTML 中:

仅使用 VHDL 状态机将 ArduCAM Mini OV2640 与 FPGA 对接:SCCB 配置、SPI 采集、BRAM 帧存储
在此了解有关该项目的更多信息
ArduCAM Mini 遇上 FPGA:纯逻辑 VHDL 方案


本项目所用物品
硬件组件

软件应用与在线服务
图像处理是 FPGA 真正大放异彩的领域之一,但将像素首先送入器件往往是任何项目中最困难的部分。MIPI 摄像头需要专门的 PHY 处理;并行 DVP 传感器占用大量引脚且需要仔细的时序收敛,而两者通常最终都需要在链路中某处有一个处理器来运行配置软件。
ArduCAM Mini 采用了不同的方法,这使其对 FPGA 开发极具吸引力。该模块将 OmniVision OV2640 传感器与 ArduChip 配对,后者在模块上的 FIFO 中缓冲完整帧,并通过仅两个简单接口呈现整个摄像头:用于传感器配置的 SCCB(本质上是 I2C)和用于控制与像素读取的 SPI。这意味着我们可以使用少量 Pmod 引脚和一些简单的数字逻辑来采集图像。
在本项目中,我们将使用VHDL开发一个完整的相机接口,设计中不包含任何处理器或软核。FPGA负责配置传感器、运行采集序列、对链路进行自检、存储帧数据并将其提供给主机。项目以Digilent Arty A7-100作为经过验证的目标平台,另有一个面向Adiuvo Spartan-7 Tile的流式传输变体,通过SPI将实时帧发送至Raspberry Pi。
所有源代码、脚本、测试平台和经过验证的比特流均可在GitHub上获取,因此你甚至无需打开Vivado即可对开发板进行编程并采集一帧图像。
ArduCAM Mini
ArduCAM Mini 2MP搭载OV2640传感器,该传感器通过并行DVP接口将帧数据输出至ArduChip。ArduChip在内部处理所有像素时钟域的时序,并将帧写入其FIFO。从连接器这一侧来看,事情要简单得多。我们与两个设备通信:
OV2640传感器通过SCCB进行配置。我们在此设置输出格式、分辨率、曝光和增益行为。在本项目中,传感器配置为RAW8 Bayer输出,分辨率为640×480,即每像素一个字节,一帧恰好为307,200字节。
ArduChip通过SPI进行控制。其寄存器集允许我们复位采集逻辑、清空FIFO、触发单帧采集、轮询完成状态、读取采集长度,最后从FIFO中突发读取像素数据。
这种分离正是该模块非常适合纯逻辑实现的原因。没有需要持续跟进的像素流;帧会耐心地停留在 ArduChip FIFO 中,直到我们准备以 SPI 时钟所支持的任何速率将其读出。
设计概述
该仓库保留了三个可综合设计,均构建在同一个底层摄像头控制器之上:
一个 AXI4-Stream 输出版本,将采集到的像素以 8 位 AXI4-Stream 形式呈现,TUSER 标记帧起始,TLAST 标记行结束。如果你想把摄像头接入现有的视频流水线,这是自然而然的选择。
一个面向 Arty A7-100 的单帧 BRAM 采集版本,将帧存储在块 RAM 中,并通过 AXI4-Lite 提供访问,由主机 PC 通过 921,600 波特的 UART 桥接访问。这是经过验证的硬件目标,也是本项目的重点。
一个面向 Adiuvo Spartan-7 Tile(XC7S25)的流式版本,完全舍弃全帧缓冲,通过 8 MHz SPI 链路将像素流式传输到 Raspberry Pi。我们将在最后讨论这个版本。
Arty设计在IP Integrator中搭建。arducam_bram_if模块包含SCCB主机、ArduChip SPI控制器、采集状态机和一个AXI4-Lite从机。UART协议桥将来自主机的简单命令包转换为AXI读写操作,这意味着PC可以检查状态寄存器并逐字读取帧缓冲区,而无需处理器参与。一个AXI GPIO提供采集使能。帧缓冲区位于地址0x0000_0000,控制寄存器位于0x4000_0000,状态、FIFO长度和ArduChip版本寄存器位于0x4001_0000起始处。
逻辑中的SCCB与SPI
两个小型控制器位于设计的底部。
SCCB主机以单一状态机实现OmniVision版本的I2C。它支持8位和16位寄存器地址(OV2640使用8位分页寄存器,而OV5642使用16位地址,该设计通过泛型参数同时支持两种传感器),在顶层通过IOBUF原语以开漏方式驱动SCL和SDA,并将完成和错误状态反馈给定序器。总线速率由时钟分频泛型参数设定为舒适的值,默认从100 MHz系统时钟分频250倍。
SPI控制器是一个模式0的主机,具有可编程分频器。使用默认分频器时,SPI时钟为6.25 MHz——完全在ArduChip的能力范围内,并且对Pmod上的飞线较为宽容。该控制器支持ArduChip突发读取所需的保持CS行为,即命令字节之后在单次片选断言中跟随任意数量的数据字节。
捕获序列
设计的核心是捕获状态机,它运行整个启动和捕获序列,这些序列通常位于Arduino库代码中。
该序列刻意保持谨慎,在每个阶段都内置了自检。启动等待之后,通过寄存器0x07复位并释放ArduChip。然后向ArduChip测试寄存器写入0x55并读回;如果暂存测试失败,则说明SPI接线或模式有误,继续操作没有意义,因此置位错误标志并停止序列。此外还读取ArduChip版本寄存器并通过AXI上报。
接下来通过SCCB验证传感器本身。对于OV2640,我们选择寄存器组1并从寄存器0x0A和0x0B读取芯片ID,预期值为0x2642。只有在两条链路都验证通过之后,状态机才遍历OV2640配置表,设置RAW8 VGA输出,启用自动曝光和增益控制,AGC上限为16倍,并启用50 Hz频闪滤波。
硬件测试中的一个实际经验值得强调:自动曝光需要时间收敛。配置后的首次采集一直是暗的,直到增加了稳定期。设计在传感器设置后等待一秒(通用参数 g_aec_settle_clks,默认在100 MHz下为100,000,000个时钟)再进行首次采集,这给了AEC环路时间对场景做出反应。如果你的应用需要更快的启动速度,这就是需要调整的参数。
采集本身遵循标准的ArduChip流程:刷新FIFO并清除标志,触发单帧采集,轮询触发寄存器直到done位置位,然后读取三个FIFO长度寄存器并与预期的307,200字节进行合理性检查。最后,通过一次突发读取将所有像素流式传入帧缓冲BRAM,帧就绪状态位被置位,Arty上的LED报告初始化完成和帧就绪。
与开发板通信
帧数据已存放在BRAM中,主机侧的操作就非常简单了。UART桥接器接受用于单字读写的小型命令包,因此整个主机应用程序就是一个使用PySerial的Python脚本。
脚本轮询状态寄存器直到init done和frame ready均已置位(状态字还携带传感器ID和SPI暂存回读值,因此自检失败可以从PC端立即发现),验证FIFO长度,然后以每次64字的方式读取帧:
python scripts\read_frame_uart.py COM6 --output frame_capture 该脚本会输出原始Bayer数据、灰度BMP图像以及双线性去马赛克后的彩色BMP图像。在921,600波特率下,传输一帧完整VGA图像需要几秒钟,这对于单帧捕获设计来说完全可以接受。
连接硬件
摄像头连接到Arty A7-100上的Pmod JA接口。该模块仅支持3.3V电压,切勿尝试使用更高电压。
UART通过Arty现有的USB-UART桥接器运行,因此主机侧无需额外接线。SCCB线路通过顶层中显式实例化的IOBUF原语以开漏方式驱动,依赖模块上的上拉电阻。
在接触任何硬件之前,设计已针对两个传感器的行为模型进行了验证。代码仓库包含自检测试平台,可对OV2640和OV5642进行建模,包括SCCB寄存器组、ArduChip寄存器行为以及FIFO突发读取。两个仿真均通过单一脚本运行:
powershell -ExecutionPolicy Bypass -File scripts\run_xsim.ps1 测试平台对完整序列进行端到端检查:验证配置写入是否正确到达、对ID读取返回预期值,并提供已知像素图案供测试平台在输出端进行校验。同时还为偏好Questa的用户提供了Questa流程。
在硬件方面,验证版本中集成了一个ILA,配合已检入的.ltx探针文件和一组Tcl脚本,可以从运行中的设计里捕获并解码SPI事务,这在调试SPI模式和突发时序时非常有价值。
流式传输到树莓派
BRAM设计方案一次捕获一帧,这对静态图像很理想,但不适合实时视频。仓库中的第三个变体面向Adiuvo Spartan-7 Tile——一块小型XC7S25板卡——采用了不同的方法:完全移除了全帧缓冲区。
该设计不再使用300 KB的帧存储,而是在块RAM中仅保留一个4 KiB的像素FIFO。像素被打包为32位字,通过SPI从设备后方的AXI协议引擎以256字节突发的方式提供给树莓派。GPIO24上的数据就绪信号线告知树莓派何时有数据块可用,而关键在于背压机制贯穿整个链路:如果树莓派暂停,ArduCAM的FIFO排空也会暂停,因此不会发生溢出,也完全不需要全帧RAM。在恰好消耗307,200字节后,下一帧会自动开始。
Pi端同样是一个使用spidev的简单Python应用程序。每次读取256字节像素数据都是一次274字节的全双工SPI事务:突发读命令、大端地址、节拍计数、若干用于覆盖协议响应延迟的填充字节,然后是像素数据。在摄像头侧SPI运行于6.25 MHz的情况下,摄像头读取成为吞吐量瓶颈,在软件开销之前,VGA RAW8的理论最大帧率约为每秒2.5帧。虽然达不到视频速率,但这是来自一颗25K逻辑单元器件的真正实时图像,而且还有余量:所实现的设计仅使用了约40%的LUT和一个Block RAM tile。
powershell -ExecutionPolicy Bypass -File scripts\build_adiuvo_s7_25_spi_project.ps1 python3 scripts/read_frame_spi_pi.py
该项目表明,一个完整的摄像头系统——从传感器配置到采集再到主机传输——可以轻松地完全用逻辑实现。ArduCAM Mini的架构对我们帮助很大,它通过FIFO隐藏了像素时钟域,只留下两个简单、低速的接口,这两个接口可以自然地映射到紧凑的VHDL状态机上。在此过程中,我们收获了一些可迁移的经验:在上电启动序列中内置自检,使故障由设计自身来诊断;给自动曝光留出稳定时间,然后再信任第一帧;在流式传输时让反压来承担帧缓冲的作用。
由此,AXI4-Stream变体显然是实际图像处理流水线的理想起点,采集到的Bayer数据馈入FPGA架构中的去马赛克、滤波或检测逻辑。
完整项目(包括源码、测试平台、构建脚本以及两块板卡的经验证比特流)可在 https://github.com/ATaylorCEngFIET/Hackster_Arducam 获取。

相关频道与标签

本页摘要由 AI 辅助整理,经编辑审核后发布;AI 仅用于提炼与分类,原文均附来源链接。