ARTICLE DETAIL

资讯详情

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

FPGA双目工业相机板级集成:MIPI+DDR3+USB3.0全链路设计实战

FPGA双目工业相机板级集成:MIPI+DDR3+USB3.0全链路设计实战 1. 双目工业相机板级集成的整体设计思路双目视觉在工业检测、机器人导航、三维重建这些场景里已经不算新鲜事了但真正要把两个摄像头、一颗FPGA、DDR3缓存和USB3.0上行链路全部塞进一块紧凑的板子上还要保证长时间稳定运行这件事的难度远比想象中大。我前后做过三版双目相机的硬件方案从最早的ARM双MIPI CSI方案到后来改用FPGA做实时预处理再到现在的MIPIDDR3USB3.0全板级集成每一版踩的坑都不一样。这篇文章就把第三版方案的完整设计思路、关键细节和实操经验整理出来给正在做类似项目的朋友一个可参考的路径。先明确这个方案要解决的核心问题两路MIPI CSI-2摄像头同时输入FPGA做实时图像预处理去马赛克、坏点校正、简单的ISP流水线处理后的数据写入DDR3做帧缓存和乒乓缓冲再通过USB3.0把数据传到上位机。整个链路要求低延迟、不丢帧、长时间运行不崩溃。适合谁看有FPGA基础、做过摄像头接口或者想入门工业相机设计的工程师以及正在选型板级方案的产品开发者。为什么选FPGA而不是直接用SoC或者ARM方案原因很直接双目同步采集对时序要求极高两路MIPI的帧同步误差要控制在微秒级ARM方案在中断响应和DMA调度上很难做到确定性延迟。FPGA可以用纯硬件逻辑做帧同步信号对齐两路摄像头的HSYNC和VSYNC在逻辑里做相位对齐误差只取决于时钟域 crossing 的处理可以做到几十纳秒级别。另外FPGA做实时预处理可以大幅降低USB3.0的带宽压力比如Bayer转RGB如果放在上位机做传输量是原始Bayer数据的三倍放在FPGA里做只需要传RGB或者压缩后的数据。DDR3在这个方案里的角色是帧缓存和带宽缓冲。两路1080p60fps的Bayer RAW10数据单路带宽大约是1920×1080×60×10/8 ≈ 155MB/s两路就是310MB/s。如果做去马赛克后变成RGB888单路带宽变成1920×1080×60×3 ≈ 373MB/s两路746MB/s。USB3.0的理论带宽是5Gbps约625MB/s实际有效带宽大概400MB/s左右所以必须用DDR3做缓冲把突发数据先存下来再以USB3.0能承受的速率往外送。DDR3的带宽远高于这个需求选DDR3而不是DDR4主要是成本和FPGA IO兼容性的考虑工业相机对成本敏感DDR3的颗粒和布线都更成熟。USB3.0选型上我最终用的是Cypress FX3现在归InfineonCYUSB3014这颗芯片在工业相机领域用得非常多GPIF II接口可以跟FPGA直接对接固件开发资料也全。另一条路是FTDI的FT601FIFO接口更简单但灵活性不如FX3。选FX3的另一个原因是它的DMA通道可以做到多缓冲配合FPGA的流控信号基本不会丢数据。2. 核心接口的硬件设计与信号完整性要点2.1 MIPI CSI-2接收端的FPGA实现MIPI CSI-2在FPGA上的实现有两种路径一种是用硬核MIPI D-PHY比如Xilinx的某些器件自带MIPI硬核另一种是用普通LVDS IO加软核D-PHY。我用的器件没有MIPI硬核所以走的是LVDS IO加IDELAY/ISERDES的方案。这里的关键点是D-PHY的时钟 lane 是双沿采样数据lane 是DDR所以FPGA端需要用ISERDES做1:8或者1:4的串并转换配合IDELAY做时序校准。实际调试时MIPI时钟信号的示波器波形是第一个要看的。D-PHY的时钟频率一般在200MHz到500MHz之间差分摆幅大约200mV用示波器看的时候要注意探头带宽至少是时钟频率的3倍以上。我遇到过时钟波形看起来正常但数据就是解不出来的情况后来发现是IDELAY的tap值不对导致采样点落在数据跳变沿上。解决办法是用Xilinx的IDELAYE2原语配合一个简单的训练模式让摄像头输出已知的测试图案然后扫描IDELAY的tap值找到误码率最低的那个点。MIPI CSI-2协议层的事情也不简单。CSI-2是包格式每帧图像被切成多个packet有长包和短包之分。短包是帧同步和行同步信息长包是实际像素数据。FPGA端要做一个packet解析器把长包里的像素数据提取出来同时根据短包里的帧号和行号做同步。这里有个坑不同摄像头的packet打包方式不一样有的把一行像素打成一个长包有的把多行打成一个长包解析器要能适配。我一般会在解析器里加一个参数化的配置寄存器通过I2C配置摄像头的时候同时配置解析器的行为。2.2 DDR3控制器的选型与AXI4接口读写DDR3控制器我直接用Xilinx的MIGMemory Interface Generator没有自己写。自己写DDR3控制器不是不行但调试周期太长而且MIG已经经过大量验证没必要重复造轮子。MIG生成的控制器对外是AXI4接口用户逻辑通过AXI4做读写。这里的关键是AXI4的突发长度和DDR3的页命中率要匹配。DDR3的读写效率跟访问模式关系很大。如果每次只读一个32位数据那DDR3的带宽利用率可能只有20%不到。我一般用AXI4的INCR突发模式突发长度设成64或者128这样一次突发能覆盖DDR3的一个或多个页效率能到70%以上。具体设多少要看图像数据的访问模式如果是按行扫描写入突发长度设成一行像素的整数分之一比较合适如果是按块读写那突发长度要跟块大小匹配。DDR3布线规则这块我踩过的坑最多。DDR3的地址线和控制线要走fly-by拓扑数据线要走点对点每组数据线DQ/DQS/DM要等长组内误差控制在5mil以内组间误差可以放宽到50mil。时钟线要差分走跟地址线的长度关系要满足tDQSS等时序参数。我第一次画DDR3的时候没注意VREF的分压电阻精度用了5%的电阻结果DDR3跑不到标称频率后来换成1%的电阻才稳定。还有一点DDR3的电源要干净VDD和VDDQ的纹波要控制在50mV以内我一般会在每颗颗粒旁边放一个0.1uF加一个10uF的电容电源平面用完整的铜皮。2.3 USB3.0上行链路的硬件与固件设计USB3.0的硬件设计相对简单因为FX3已经把USB3.0的PHY和链路层都集成好了FPGA只需要跟FX3的GPIF II接口对接。GPIF II是一个可配置的并行接口可以配成从FIFO模式、同步从FIFO模式等。我用的是同步从FIFO模式FPGA作为masterFX3作为slaveFPGA通过GPIF II把数据写进FX3的FIFOFX3再通过USB3.0发给上位机。这里的关键是流控。FX3的FIFO有满标志FPGA看到满标志要暂停写入否则数据会丢。但FX3的满标志有延迟从FIFO实际满到标志拉高有几个时钟周期的延迟所以FPGA端要留足够的余量。我的做法是在FPGA里做一个FIFO做缓冲FX3的满标志触发FPGA FIFO的暂停FPGA FIFO的深度要能覆盖FX3满标志的延迟加上USB3.0的突发延迟。实测下来FPGA FIFO深度设成4KB以上比较安全。FX3的固件开发用EZ-USB FX3 SDK主要工作是配置GPIF II的状态机和DMA通道。GPIF II Designer这个工具可以图形化配置状态机生成的头文件直接放到固件工程里。DMA通道我配了两个一个用于图像数据一个用于控制命令。图像数据的DMA用auto模式FX3自动把FIFO里的数据搬到USB端点控制命令的DMA用manual模式固件里手动处理。这里有个细节FX3的USB端点要配成Bulk传输Bulk的包大小设成1024字节这样USB3.0的突发效率最高。3. 从摄像头到上位机的完整数据通路实现3.1 双目同步采集的时序对齐双目同步是这个方案里最核心也最难的部分。两个摄像头即使型号完全相同上电后的时钟相位也可能不一样而且MIPI的帧同步信号是通过短包传输的短包到达FPGA的时间受lane skew和packet解析延迟的影响。我的做法是在FPGA里做一个帧同步对齐模块两路摄像头的帧同步短包解析出来后分别打上FPGA的本地时间戳然后比较两个时间戳的差值如果超过阈值就调整其中一路的帧起始位置。具体实现上我用了一个简单的状态机每帧开始时两路都等待对方的帧同步信号先到的那一路把帧数据先存到DDR3的一个临时区域等到另一路也到了再把两路数据一起搬到正式的输出缓冲区。这样做的代价是增加了一帧的延迟但换来了严格的帧同步。如果对延迟要求极高可以用行同步对齐但行同步对齐的实现复杂度更高而且对摄像头的行同步信号质量要求也高。注意双目同步的阈值设置很关键。设得太小摄像头本身的抖动会导致频繁调整反而引入不稳定设得太大同步精度不够。我一般设成一行时间的1/4比如1080p60fps一行时间是14.8us阈值设成3.7us左右。3.2 DDR3乒乓缓冲与带宽分配DDR3的乒乓缓冲设计要考虑几个因素写入速率、读出速率、缓冲深度。写入速率是两路MIPI的像素速率读出速率是USB3.0的有效带宽。如果写入速率大于读出速率那缓冲会逐渐填满最终溢出如果写入速率小于读出速率那缓冲会逐渐排空USB3.0会空闲。实际场景中摄像头的输出速率是恒定的USB3.0的带宽受上位机的影响会有波动所以缓冲深度要能覆盖USB3.0的波动。我的做法是把DDR3分成四个区域两个用于乒乓缓冲一个用于帧同步的临时存储一个用于控制寄存器和查找表。乒乓缓冲的每个区域大小是一帧图像的大小比如1080p的RGB888是6MB两个区域就是12MB。DDR3的容量一般选256MB或者512MB足够用。带宽分配上DDR3的控制器要保证写入和读出的公平性不能让写入饿死读出也不能让读出饿死写入。MIG的AXI4接口有QoS服务质量配置可以给读写通道分配不同的优先级。这里有个经验DDR3的刷新操作会占用带宽而且刷新期间不能读写。MIG的刷新周期一般是7.8us每次刷新占用几个时钟周期。如果DDR3的带宽利用率已经到70%以上刷新带来的延迟就会变得明显。解决办法是提高DDR3的频率或者用更宽的位宽。我用的是16位位宽、800MHz频率的DDR3理论带宽是1.6GB/s实际有效带宽大概1.1GB/s对于746MB/s的需求来说余量足够。3.3 FPGA图像预处理流水线FPGA里的图像预处理流水线包括几个模块Bayer去马赛克、坏点校正、白平衡、Gamma校正。去马赛克我用的是双线性插值虽然效果不如自适应算法但胜在资源占用少、延迟低。坏点校正用的是一个简单的阈值判断如果某个像素跟周围像素的差值超过阈值就用周围像素的中值替代。白平衡和Gamma校正都是查表实现查找表存在DDR3里上电时从Flash加载。去马赛克的实现要注意边界处理。双线性插值需要周围像素图像边界上的像素没有完整的周围像素需要特殊处理。我的做法是在图像外围补一圈虚拟像素虚拟像素的值用边界像素复制得到。这样去马赛克模块就不用关心边界了统一处理。坏点校正的阈值要可配置因为不同摄像头的坏点特性不一样有的摄像头坏点多但差值小有的摄像头坏点少但差值大。提示FPGA图像处理流水线的延迟要跟DDR3的乒乓缓冲配合好。如果流水线延迟太大乒乓缓冲的切换时机就要相应调整否则会出现半帧数据的情况。我一般会在流水线末端加一个FIFO做延迟补偿FIFO的深度根据流水线的最大延迟来设。4. 调试过程中遇到的典型问题与排查方法4.1 MIPI链路不稳定的排查思路MIPI链路不稳定是最常见的问题表现是图像偶尔出现花屏、条纹或者完全无数据。排查的时候我一般按这个顺序来先看时钟再看数据最后看协议。时钟方面用示波器看MIPI时钟的差分波形重点看摆幅、频率、抖动。摆幅不够可能是驱动能力不足频率不对可能是摄像头配置错误抖动大可能是电源噪声。数据方面用FPGA的ILA抓ISERDES的输出看串并转换后的数据是否稳定。如果数据偶尔错位那多半是IDELAY的tap值不对需要重新校准。协议方面用ILA抓CSI-2的packet解析状态机看短包和长包的解析是否正确。我遇到过一个很隐蔽的问题MIPI链路在常温下正常但温度升高后就开始丢数据。后来发现是FPGA的IDELAY对温度敏感温度变化后tap值需要重新校准。解决办法是在FPGA里加一个温度监控温度变化超过阈值就重新做IDELAY校准。这个校准过程很快大概几毫秒对图像传输的影响可以忽略。4.2 DDR3读写错误的定位方法DDR3读写错误的表现是图像数据错乱、颜色不对或者帧不完整。排查DDR3问题我一般用MIG自带的内建自测试BIST先跑一遍确认DDR3的物理层没问题。如果BIST通过但用户逻辑读写还是错那多半是AXI4的时序或者地址映射有问题。AXI4的时序问题包括握手信号不满足、突发长度不对、地址对齐不对。地址映射问题包括bank地址和row地址的映射方式不对导致页命中率低。我踩过的一个坑是AXI4的写响应通道没有正确处理。AXI4的写操作有写地址、写数据、写响应三个通道写响应是slave发给master的表示写操作完成。如果master不处理写响应那写操作的完成状态就不知道可能会导致后续写操作覆盖前面的数据。我的做法是在写通道加一个计数器每发一个写请求就加一每收到一个写响应就减一计数器的值表示未完成的写操作数超过阈值就暂停新的写请求。4.3 USB3.0丢数据的排查与解决USB3.0丢数据一般有三个原因FX3的FIFO溢出、USB端点的带宽不足、上位机的读取速度跟不上。FX3的FIFO溢出可以通过FX3的GPIF II状态机里的满标志来判断如果满标志频繁拉高说明FPGA写入太快需要降低写入速率或者加大FIFO深度。USB端点的带宽不足可以通过FX3的DMA通道的传输计数来判断如果传输计数小于预期说明USB链路有问题可能是线缆质量不好或者主机控制器的带宽被其他设备占用。上位机的读取速度跟不上可以通过上位机的缓冲区状态来判断如果上位机的缓冲区经常满说明上位机的处理速度不够需要优化上位机的读取逻辑或者降低数据速率。我遇到过一个USB3.0丢数据的问题排查了很久才发现是USB线缆的问题。那根线缆看起来是USB3.0的但实际上只有USB2.0的线芯USB3.0的差分对是假的。换了一根正规的USB3.0线缆后问题就解决了。所以调试USB3.0的时候线缆一定要用正规的不要贪便宜。4.4 常见问题速查表问题现象可能原因排查方法解决方案MIPI无数据时钟未起振、lane极性反、摄像头未配置示波器看时钟、ILA看ISERDES输出、I2C读摄像头寄存器检查时钟源、调整lane极性、重新配置摄像头MIPI花屏IDELAY tap不对、电源噪声、lane skew大ILA抓数据、示波器看电源纹波、扫描IDELAY重新校准IDELAY、加去耦电容、调整lane走线DDR3读写错AXI4时序不满足、地址映射错、刷新冲突MIG BIST、ILA抓AXI4信号、调整刷新周期修正AXI4握手、调整地址映射、提高DDR3频率USB3.0丢数据FIFO溢出、线缆质量差、上位机慢FX3满标志、DMA传输计数、上位机缓冲区状态加大FIFO、换线缆、优化上位机双目不同步帧同步阈值不当、摄像头时钟差异大ILA抓帧同步时间戳、比较两路时间差调整阈值、用同一时钟源给两个摄像头5. 板级集成中的电源与散热设计5.1 多路电源的分配与去耦这块板子的电源种类不少FPGA核心电压一般是0.9V或1.0VDDR3是1.5VMIPI和USB3.0的IO是1.8V或3.3VFX3的核心是1.2V。这么多电压域电源分配要仔细。我的做法是用一颗多路输出的PMIC做主干每路输出再经过LDO做二次稳压。FPGA核心电流大用开关电源效率高MIPI和USB3.0的模拟部分对噪声敏感用LDO供电。去耦电容的布局很关键。FPGA的每个电源引脚旁边都要放一个0.1uF的电容距离越近越好最好在同一个焊盘上。DDR3的VREF分压电阻旁边要放一个0.1uF加一个1uF的电容。FX3的电源引脚旁边放0.1uF和10uF。电源平面的分割要注意数字电源和模拟电源要分开分割槽的宽度至少20mil跨分割的信号线要加缝合电容。5.2 散热设计与温控风扇FPGA和FX3的功耗都不小FPGA在跑图像处理流水线的时候功耗大概2W到3WFX3大概1W。板子尺寸小散热是个问题。我的做法是在FPGA和FX3上面贴散热片散热片用导热胶固定。如果环境温度高还要加风扇。风扇的控制可以用FPGA的PWM输出根据温度传感器的读数调整转速。温度传感器可以用FPGA内部的XADC也可以用外部的I2C温度传感器。温控风扇的逻辑我一般这样写温度低于40度风扇不转40到60度风扇半速60到80度风扇全速超过80度报警。风扇的PWM频率设成25kHz左右这个频率在人耳听觉范围之外不会有噪音。风扇的电源要单独走线不要跟FPGA的电源混在一起否则风扇的电流波动会干扰FPGA。注意散热片的固定要可靠工业相机的振动环境可能比较恶劣散热片脱落会短路板子。我一般用螺丝固定散热片或者在散热片底部涂导热胶后再用卡扣固定。6. 一些实操心得与后续扩展方向这个方案从第一版到第三版中间经历了无数次调试和改板。最大的体会是板级集成项目的难点不在单个模块而在模块之间的配合。MIPI、DDR3、USB3.0每个单独拿出来都不算太难但三个凑在一起时序、带宽、电源、散热的问题会互相影响。比如DDR3的电源噪声会耦合到MIPI的时钟上导致MIPI链路不稳定USB3.0的突发传输会拉低电源电压导致FPGA逻辑出错。解决这些问题没有捷径只能一个一个排查用示波器和ILA把每个信号都看清楚。后续如果要扩展有几个方向可以考虑。一是加一路HDMI或者DisplayPort输出做本地显示二是把USB3.0换成千兆以太网或者万兆以太网做远程传输三是在FPGA里加更复杂的ISP算法比如HDR合成或者3D降噪。每个方向都有不同的挑战但核心思路是一样的先把数据通路打通再优化每个环节。最后分享一个小技巧调试这种复杂板子的时候一定要留足够的测试点。我一般在MIPI的时钟和数据线上留测试点在DDR3的电源和VREF上留测试点在USB3.0的差分对上留测试点。测试点不用大1mm的焊盘就够了但关键时刻能省很多时间。还有就是FPGA的ILA一定要用起来ILA能抓到的信号比示波器多得多而且能看协议层的状态是调试FPGA项目最有力的工具。
返回列表