ARTICLE DETAIL

资讯详情

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

FPGA实战:Xilinx 7系列MIPI DPHY/CPHY接口设计与调试

FPGA实战:Xilinx 7系列MIPI DPHY/CPHY接口设计与调试 做FPGA图像处理这几年我接过的项目里十个有八个绕不开MIPI接口。要么是摄像头采集端要么是LCD显示端DPHY、CPHY这两个词几乎成了图像类FPGA开发的标配。这次我把自己在Xilinx 7系列上实现MIPI DPHY/CPHY接口的完整过程整理出来包含方案选型、物理层原语配置、协议封包、初始化序列以及最让人头疼的调试排查希望能帮你少踩几个坑。这套内容适合已经在做或准备做MIPI相关项目的FPGA工程师也适合正在评估“用FPGA接MIPI摄像头/屏幕”可行性的朋友。我会尽量把关键参数和实现细节讲透你拿到板卡后可以照着思路直接上手改。1. 项目定位先想清楚你要做接收还是发送1.1 DPHY和CPHY的差异选错会多写一倍代码MIPI接口按物理层区分现在主流就两种DPHY和CPHY。DPHY是差分信号时钟通道和数据通道分离每条通道本质就是一对差分线和FPGA里LVDS接收长得非常像所以DPHY在FPGA上实现相对顺手。CPHY则完全不同它没有独立时钟线三根线组成一个“三合一”通道靠线间电压差编码一条通道能同时传时钟和数据。从引脚数量和速率两个维度对比一下你就知道该怎么选了项目DPHYCPHY通道结构1对差分时钟 1~4对差分数据1组3线通道triplet可扩展到3组有无独立时钟有无时钟嵌在信号中单通道最大速率约2.5Gbps/lane约5.7Gbps/trio实际有效带宽接近DPHY同频的2倍以上FPGA实现难度中等类似LVDS接收较高需要专门三线编码解码逻辑Xilinx 7系列支持度可用普通IO原语需要额外写编码/解码逻辑速率高时建议用GTP/GTX从我实际项目看绝大多数传感器和屏幕还是DPHY接口CPHY多用于高端手机摄像头。如果你的传感器是DPHY接口那直接用7系列HP Bank的普通IO做物理层配合IDELAY做字对齐就够了。如果非要做CPHY建议把接口速率控制在2.5Gbps/trio以内否则7系列普通IO不一定稳。1.2 7系列FPGA的IO资源够不够为什么不用GTX收发器很多第一次接触MIPI的朋友上来就问是不是得用GTP/GTX这种高速串行收发器我用过的Xilinx 7系列项目里DPHY基本用不到。DPHY单lane速率一般在800Mbps到1.5Gbps这个速率刚好落在7系列HP Bank的IO能力范围内。7系列HP Bank支持百万兆位的差分信号输入关键是它内部有IDELAY和ISERDES可以做bit级延迟和串并转换。GTX不是不能用但GTX需要参考时钟、需要差分端接匹配而且GTX是为PCIe、SRIO这种连续串行协议设计的MIPI这种带有LP态低功耗状态和HS突发传输的协议用GTX反而要处理一大堆空闲态和唤醒逻辑复杂度不降反升。我做过一个项目开始想用GTX接MIPI DSI屏折腾两周后改用普通IO方案三天就调通了。所以结论很明确DPHY接口用普通IO ISERDES IDELAY不要想GTX。CPHY接口如果单通道速率不高也可以用普通IO配合自定义三线解码状态机。非要跑CPHY全速再考虑GTX方案但那种项目基本都是给高端手机摄像头做采集普通开发板遇不到。1.3 接收还是发送CSI-2和DSI的协议栈差异MIPI协议在物理层之上还分协议层。摄像头方向走CSI-2显示屏方向走DSI。两者在物理层和链路层上高度相似都是lane-based、都有短包长包但数据内容组织方式不同。CSI-2典型的应用场景是图像传感器把RAW Bayer或YUV数据通过MIPI发送给FPGAFPGA接收后做ISP、存储、显示。DSI则是把RGB像素从FPGA发往屏幕驱动IC所以发送端要把并行RGB数据组包成MIPI差分信号。我做过一个工业相机项目FPGA同时做两件事从OV5640传感器接收CSI-2经过去马赛克和色彩校正再通过MIPI DSI接口输出到LCD屏。这套架构看起来简单但实际做下来发现接收侧要处理Sensor的HS突发信号和帧同步发送侧要按屏幕时序不断刷新数据两侧的时钟域还不一样。我建议第一次做的人先把两端拆开分开验证不要一上来就搞全链路。2. 物理层搭建用原语把MIPI信号拉回FPGA2.1 最基础的IBUFDS/OBUFDS链路搭建MIPI DPHY的物理层信号在电气特性上接近LVDS但电压摆幅更低HS模式约200mV差分共模电压大约在200mV左右所以不能直接接普通LVDS接收器。好在Xilinx的IBUFDS有差分输入缓冲可以通过DIFF_TERM和IBUF_LOW_PWR选项调整端接和功耗模式。我之前用K-7系列芯片做DPHY接收的引脚约束时最常用的是这种原语实例// DPHY时钟通道输入 IBUFDS #( .DIFF_TERM(TRUE), .IOSTANDARD(LVDS_25) ) ibufds_clk_p ( .I (mipi_clk_p), .IB (mipi_clk_n), .O (clk_int) ); // DPHY数据通道输入 IBUFDS #( .DIFF_TERM(TRUE), .IOSTANDARD(LVDS_25) ) ibufds_d0_p ( .I (mipi_d0_p), .IB (mipi_d0_n), .O (d0_int) );这里有个容易忽略的细节MIPI HS信号的共模电压和LVDS_25不匹配Xilinx官方其实推荐使用MIPI专用的DIFF_SSTL或直接给Bank配1.2V的VCCO。我在实际测试中把Bank VCCO设为1.2V并用LVDS_25的IOSTANDARD也能工作只是眼图和抖动会差一些。如果你要量产建议按Xilinx应用笔记里的标准来用HR Bank时甚至要加外部电阻端接网络。2.2 LP态和HS态切换别小看这个状态机MIPI DPHY每条数据通道有两类状态HSHigh-Speed状态和LPLow-Power状态。HS状态是真正传数据的时候速率高LP状态用来传控制命令和进入退出HS态速率低走的是单端信号。很多人以为FPGA只要接差分线就行其实在实际调试中LP态的时序判断才是第一个坑。摄像头在发送HS数据前会先把所有数据通道拉Lane进入LP-00再按固定时序切换成LP-01最后进入HS-0、HS-1。FPGA侧必须检测到这个“LP-11 - LP-01 - LP-00”的跳变过程才能判断数据通道进入了HS状态然后才能开始采样。这个状态机我在项目中是用纯组合逻辑加两级同步器实现的// lane状态检测 wire lp_dp d0_p_sync; // 单端高电平 wire lp_dn d0_n_sync; // 单端低电平 localparam [2:0] LP_HS_RQ 3b011; // LP-01, 请求进入HS localparam [2:0] LP_HS_TERM 3b010; // LP-00, 确认终端 reg [1:0] lp_state; always (posedge clk_200m) begin case (lp_state) 2d0: if (lp_dp !lp_dn) lp_state 2d1; // 检测到LP-01 2d1: if (!lp_dp !lp_dn) lp_state 2d2; // 检测到LP-00 2d2: if (lp_dp lp_dn) lp_state 2d0; // 回到LP-11 default: lp_state 2d0; endcase end这里强调的是LP检测的时钟域最好用200MHz以上的独立时钟不要用像素时钟。因为HS采集时钟和LP检测时钟的相位没有关联如果LP检测也用MIPI恢复时钟会出现采样时钟不稳定导致误判。用200MHz固定时钟做LP状态机检测窗口比较干净。2.3 DPHY的DDR采样与字节对齐为什么要做deskewMIPI DPHY的数据通道在HS模式下是DDR传输时钟的上升沿和下降沿都有数据。FPGA侧一般用ISERDESE2原语来做串并转换把1.0Gbps的比特流变成4bit或8bit的并行数据。但这里有个问题数据线和时钟线长度、PCB走线差异、芯片工艺差异都会导致每条lane的相位漂移。如果只是简单地把所有lane都对齐到时钟边沿输出字节序会错乱。所以MIPI协议在每个帧开始前会发送一段固定的训练序列比如0xB8接收端需要用这段序列做lane内bit对齐和lane间字节对齐。我调试时用过一个笨办法先用ILA抓ISERDES输出的原始并行数据看是否出现固定的0xB8或0x3C等帧同步字。如果抓到的是0x1D70之类错位的数说明bit位置偏了需要调整IDELAY的tap值。Xilinx提供了IDELAYCTRL和IDELAYE2原语tap数从0到31可调每个tap约78ps具体取决于参考时钟频率。实际项目中我写了一个自动对齐模块利用MIPI数据包中的同步序列逐lane调整IDELAY值直到并行数据里的同步头对准。这个方法比手动加约束再编译快太多尤其当你接的是非标准Sensor时序余量特别小的时候自动对齐几乎是必选项。3. 协议层从Sensor寄存器初始化到像素流3.1 CSI-2包结构长包/短包解析物理层调通后进入FPGA的就是一串比特流。CSI-2协议把数据组织成包头Packet Header、数据负载Payload和包尾Packet Footer三段。包头有32bit其中8bit数据标识、16bit字计数、8bit错误检测码ECC。刚开始解析CSI-2时很多人会犯一个错误直接把数据流按字节塞进FIFO然后找0xB8这种同步字。这样做遇到长包会丢数据。正确做法是先做字节同步解析出包结构。短包如帧开始FS、帧结束FE、行开始LS只有6字节不带负载长包则带长度可变的像素数据。我解析CSl-2时用的状态机大致如下SOF短包来之前要先收到LP态的转场信号收到SOF后状态切到“等待包头”解析包头根据Data Type判断是长包还是短包长包按WordCount接收接收完成后校验CRC可选收到EOF短包一帧结束输出帧同步脉冲这段逻辑看起来不复杂但实际吞吐量大时比如4K分辨率60fps带宽接近1.2Gbps包头解析和负载FIFO可能导致FIFO溢出。我建议接收侧用异步FIFO写时钟用MIPI恢复时钟读时钟用后端ISP或VDMA的像素时钟深度至少做到2KB才能扛住突发。3.2 用I2C初始化Sensor以OV5640和ST7701S为例MIPI链路不通有一半原因是Sensor寄存器没配好。比如接OV5640摄像头时上电后Sensor默认可能输出并行DVP信号或者MIPI接口没使能、lane数设置不对、HS速率偏差过大。我调试时一般先把I2C读到Sensor ID再接一套固定的初始化序列。先放一个我在项目里常用的OV5640初始化顺序片断配置项比较典型// 配置I2C地址0x3C // 1. 复位 {0x3103, 0x11}, // system reset delay(5); {0x3103, 0x03}, // clock enable {0x3008, 0x02}, // soft reset delay(20); // 2. 设置PLL使MIPI时钟输出720MHz {0x3035, 0x11}, // PLL ON {0x3036, 0x46}, // PLL multiplier {0x3037, 0x5E}, // PLL sys divider // 3. 选择MIPI输出2 lane {0x3006, 0x43}, // clock pad enable {0x3008, 0x42}, // MIPI mode {0x3018, 0x04}, // MIPI 2 lane这套初始化的核心是控制PLL倍频把像素时钟和MIPI bit时钟稳定在Sensor内部设定的目标值。每条Sensor的初始化序列都不完全一样建议用官方驱动例程做baseline再根据实际FPGA端接收的波形微调。屏幕侧就不一样了。ST7701S是一款常用的MIPI DSI转LCD驱动芯片它接收DSI命令输出RGB并行信号点亮LCD屏。调试ST7701S时初始化命令里最关键的是PLL配置和Line/Frame时序参数。我遇到过一上电白屏的情况排查到最后发现是ST7701S的同步脉冲极性配置反了。写ST7701S的初始化数组时我习惯在每条命令后边加注释比如这是在设置“调屏顺序”还是“伽马修正”。这类屏驱芯片的命令树很复杂没有注释过两周回头看完全认不出哪条是管亮度的。3.3 字节转像素以及行场同步恢复CSI-2的payload不是直接就能当RGB用的。以RAW10格式为例每个像素10bit但MIPI传输时把4个像素打包成5个字节。RGB888通常是3字节一像素。所以FPGA里必须有字节到像素的转换逻辑。核心是做一个FIFO配合字节计数。每次从CSI-2包解析模块拿到按字节排序的有效负载写入FIFO像素形成逻辑按格式要求的字节数读取。比如RGB888读取逻辑// 每3字节出一个RGB像素 if (byte_cnt 0) r_byte data_in; if (byte_cnt 1) g_byte data_in; if (byte_cnt 2) begin rgb_valid 1b1; rgb_data {r_byte, g_byte, data_in}; byte_cnt 0; end else byte_cnt byte_cnt 1b1;帧同步恢复同样重要。CSI-2的FSFrame Start和FEFrame End信号要转成后端处理用的frame_valid、line_valid信号。FPGA内部ISP、VDMA都需要这些同步信号。我吃了不少亏之后养成一个习惯把恢复出的行场同步信号引到开发板的LED或者示波器GPIO上方便实时观察帧率是否正常。4. Xilinx 7系列配置指南引脚约束、时钟约束与IP集成4.1 MIPI引脚分配与Bank电压域用7系列做MIPI第一件事是确认MIPI信号落在哪个Bank。Bank的VCCO要跟MIPI信号域匹配。MIPI通常工作电压在1.2V所以建议放在HP BankVCCO设置为1.2V或1.35V。如果你用了LVDS_25的IOSTANDARDVCCO又设成1.8V编译能过但上板大概率不稳定。我最开始犯过这个错误把所有MIPI信号随便分配到FPGA的HR Bank结果接收到的数据眼图烂得不行。后来把所有MIPI信号移到HP Bank现象立刻改善。注意7系列FPGA的HP Bank是在FPGA的上侧和右侧布局布线时尽量让MIPI信号集中在一个Bank避免跨Bank的IO延迟不一致。在XDC里约束引脚时MIPI的高速时钟通道最好也加上位置约束确保时钟输入的走线最短。我还会把所有数据lane的引脚放在同一个Bank的相邻位置减少布线延迟差。4.2 时钟约束与IDELAY校准物理层除了引脚最关键的约束是时钟约束。MIPI恢复时钟不能用PLL直接生成通常用MMCM恢复但初始化过程需要时间。这里最常见的问题是没有给IDELAYCTRL提供正确的参考时钟。IDELAYCTRL需要200MHz参考时钟如果这个时钟不稳定IDELAY的tap时间会漂移数据对齐就全乱。约束示例create_clock -name mipi_clk -period 3.333 [get_pins {clk_wiz_inst/CLKOUT0}] set_input_delay -clock mipi_clk -max 1.0 [get_ports d0_p] set_input_delay -clock mipi_clk -min 0.5 [get_ports d0_p]这里mipi_clk是MMCM恢复出来的字节时钟周期取决于MIPI链路速率。如果1.2Gbps/laneDDR时钟就是600MHz字节时钟150MHz。IDELAY的tap数可以在运行时通过AXI接口动态调整也可以在约束里设初始值。我建议初始值设为一半上电后再用训练序列做微调。还有一点要注意MIPI时钟是突发的不是常开。Sensor一帧一帧地传数据时钟只在HS期间出现。所以时钟约束要用虚拟时钟不能直接把MIPI时钟设为周期时钟否则时序分析会报告一堆违反路径。4.3 与VDMA/HDMI输出的联动调试MIPI接收模块调通后下一步是把图像数据送去显示。我常用的方案是Xilinx VDMA IP AXI4-Stream。MIPI接收输出为AXI4-Stream格式VDMA把流写入DDR再通过HDMI TX读出。先说数据宽度匹配。MIPI模块输出的RGB888是24bitAXI4-Stream通常配成32bit。我用了一个简单的位拼接把24bit像素加8bit的sideband信号凑成32bit因为VDMA的Data Width参数只支持8的倍数。再提一个容易犯的错误VDMA的S2MM通道和MM2S通道要配成一样的Frame Buffer数量而且帧同步信号要和VDMA的tlast对齐。如果tlast没对齐VDMA可能把两帧数据拼接在一起图像会上下错位。最后HDMI输出分辨率最好与Sensor分辨率一致如果不一致缩放逻辑要自己做或者用Video Processing Subsystem。我最初做720P Sensor接1080P屏时没做缩放图像只显示在屏幕左上角折腾好久才搞明白。5. 实测与排查示波器波形、常见问题与实战心得5.1 MIPI时钟信号示波器波形怎么看很多朋友调试MIPI时第一反应是用示波器去戳MIPI数据线。这里给你一个比较实用的建议不要直接看高速数据线先把MIPI时钟通道找出来。DPHY在HS传输时时钟通道是连续翻转的。差分时钟幅度约200mV如果用的示波器带宽低于500MHz看到的基本是一条模糊的带状波形很难数清边沿。我用的是1GHz带宽的示波器配合差分探头。把探头接在时钟通道的P和N上打开差分模式触发方式选择上升沿。HS传输期间你会看到一串稳定的差分时钟脉冲每个周期对应一个bit周期。如果脉冲幅度明显偏低或者时钟频率严重偏离设定值多半是Sensor寄存器PLL没配好或者PCB端接不正确。LP状态在示波器上看起来像单端的0~1.2V方波。HS态则是叠加在200mV共模上的差分小信号。两者切换边界是排查重点如果LP到HS的切换时间过长FPGA内部的LP状态机会检测不到正确时序。我实测过一两次每次切换大约需要100ns左右超过200ns基本就会丢帧。5.2 常见问题速查表这些是我在几个项目中真正遇到并解决过的问题整理成了表格遇到类似现象可以直接对照。现象可能原因解决办法I2C读Sensor ID不稳定I2C上拉电阻过大时序过快检查上拉到1.8V还是3.3V换4.7k电阻时钟波形正常数据全为0ISERDES位宽配置不对抓ILA看并行输出确认同步字位置画面出现彩色细条纹byte-to-pixel转换错位检查RAW格式字节打包顺序一帧画面上下错位VDMA帧同步tlast不对检查MIPI模块输出的frame_valid是否对齐温度升高后图像花屏IDELAY tap值漂移上电运行自动对齐或用DDR的training算法屏幕白屏ST7701S初始化序列顺序错逐条比对官方驱动重点看PLL寄存器信号检测到LP-01但无HSCSI-2时序握手不完整示波器看LP转HS的过渡波形加长LP检测窗口5.3 关于国产FPGA的一些补充和我的避坑经验做这行不可能只碰Xilinx。最近我也在用高云FPGA做低功耗MIPI采集高云有专门的MIPI硬核不需要像7系列这样用原语拼但配置过程和Xilinx差异很大。如果你未来有国产化需求建议在7系列上把逻辑模块做成RTL级通用封装不要依赖Xilinx专用原语后面移植到高云或易灵思会快很多。调试MIPI的几条经验我写在这里先I2C后MIPI。Sensor寄存器读不通后面全白搭。我一般上板先写一个I2C扫描程序把Sensor挂在的总线上所有设备地址扫一遍确认通信链路正常再往下走。每条lane独立对齐。不要想着一上来就把所有lane一起对齐。先用ILA逐条lane抓数据确认每条lane都能解出同步头再统一做lane-to-lane对齐。保留复位开关。MIPI调试过程复位必不可少建议把Sensor复位、FPGA MIPI模块复位分开控制方便定位问题。多用逻辑分析仪少猜波形。ILA虽然占用BRAM但抓包直观。我每次抓包都在FS和FE短包处打标记通过看标记间隔判断帧结构是否正确。我实际用这套方法调过不少Sensor像OV5640、IMX290也调过ST7701S、ILI9881C这类DSI屏。走完一遍流程后你会发现MIPI并没有想象中那么玄乎它本质上就是一组高速差分信号和一套明确的打包时序。只要把物理层对齐做好协议层解析写清楚剩下的都是熟练工。最后分享一个小技巧给MIPI恢复出来的字节时钟加一个计数器每收到一帧数据增加一再把计数器值显示在板载LED上。这个土办法比看示波器快得多上电那一瞬间就能判断链路是否在持续传帧省去了一堆猜测。
返回列表