搞FPGA的人迟早都会撞上MIPI这道坎儿。我年初接了一个双目视觉采集的项目,sensor输出端是MIPI CSI-2接口,并且D-PHY和C-PHY两种模式都支持;后级要驱动一块5.5寸的MIPI DSI屏幕。主控板是老方案,板上已经焊好一颗Xilinx 7系列K7,既有逻辑、背板走线、BOM全都定死了,根本没机会换成带MIPI硬核的MPSoC。项目卡在这个地方的时候,说实话我一度也挺头疼。
先说一个摆在台面上的现实:Xilinx 7系列FPGA本身没有D-PHY/C-PHY物理层硬核,网上很多人一上来就说“用IBUFDS接ISERDESE2就能解MIPI”,真在高速率上跑起来远没这么简单。但也不是无解,借助7系列SelectIO的可配置能力,再加上合适的片外PHY或电平转换方案,D-PHY和C-PHY工程上都能落地,只是你必须把协议、资源约束、板级信号完整性三个层面都吃透。
这篇文章我会从D-PHY、C-PHY协议最核心的概念开始讲,再落到Xilinx 7系列HP/HR Bank、ISERDESE2/OSERDESE2、IODELAY和XDC约束的具体配置上,最后给出我最终调通的收发架构以及两三个月里踩过的坑。适合两类人看:一是想在7系列上做MIPI采集或显示、但方案还没想清楚的人;二是已经动手开搞、卡在协议或时序上排查不动的人。文章不是教科书式的面面俱到,更像是我自己项目复盘后的操作笔记,只列能让你少走弯路的实操内容。
1. 项目概述:一块7系列FPGA到底能做什么
1.1 问题背景:两头都是MIPI,中间只有一颗FPGA
这个项目的输入源是双目摄像头模组,接口走MIPI CSI-2,单lane速率大概800Mbps左右,四lane模式。后级显示是一块MIPI DSI接口的屏,同样依赖D-PHY传输。整条链路的“翻译官”就是这颗K7-325T:FPGA要做CSI-2接收、简单的图像预处理、再按DSI协议把画面发出去。
如果当初能用带MIPI硬核的Zynq UltraScale+,打通这条链路可能三四天就行。但板子是早期就定下来的,换主控等于重做整块板子,时间预算完全不允许。另一条路是使用外接PHY芯片,把MIPI先转成并行RGB或LVDS,FPGA只做并行数据处理。这个方案对算法简单、功能固定的项目来说很可靠,结构也清晰,但对这种需要保留完整数据控制、后续还要换不同型号sensor的项目,就牺牲了灵活性。
所以最后我们采用的方案是“半硬半软”:物理层用一颗支持D-PHY/C-PHY的高性能桥接PHY来搞定LP/HS切换和模拟指标,FPGA侧用SelectIO的ISERDESE2/OSERDESE2在HS模式下接收/发送串行数据。LP时序和总线方向控制由FPGA的一个小型状态机接管。这套组合让FPGA仍然掌握整条数据流的调度权,又不用在物理层上跟MIPI较真那些敏感的模拟参数。
1.2 这篇文章能帮你解决什么
经过几个月的折腾,项目顺利量产。回头复盘,中间踩过的坑有不少是提前看一篇经验贴就能避开的,所以我把能沉淀的都写了出来:
- 协议层面:D-PHY的LP四态、HS转换时序、同步序列、CSI-2包结构到底是什么,哪些必须FPGA自己管,哪些可以放心交给外部PHY;
- 选型层面:D-PHY和C-PHY在工程上怎么选,7系列只用SelectIO能不能直接怼,为什么大部分量产项目还是需要一颗外部PHY撑物理层;
- 配置层面:Xilinx 7系列HP/HR Bank怎么选、VCCO怎么设、ISERDESE2/OSERDESE2的参数怎么填、IODELAY什么时候用、XDC约束里最容易被忽略的几行;
- 调试层面:示波器上怎么区分LP和HS波形,link起不来的典型原因,字节错位和lane间偏移到底怎么定位。
1.3 我对“手把手”的理解
刚开始我也在网上翻了不少资料,结果发现多数内容要么是厂商IP的GUI操作截图,要么直接丢一段RTL说“拷过去就能用”。真到自己的板子、自己的sensor、自己的布线环境下,问题往往都出在这些默认参数身上。所以这篇不是单纯教你怎么点Vivado,而是先把原理讲透,再落到配置。原理清楚了,后续换平台、换PHY、换sensor才不用推倒重来。
2. D-PHY协议核心拆解:从线态到字节流
2.1 物理通道:1条时钟lane加上1到4条数据lane
D-PHY物理层是一组差分线,每一条lane由Dp/Dn两根线组成。典型拓扑是一条时钟lane加多条数据lane,常见的是4条数据lane。时钟lane只负责传差分时钟,数据lane上的数据以DDR方式在时钟的上下边沿都采样。以800Mbps/lane为例,对应时钟频率是400MHz,一个UI(1bit时间)大约是1.25ns。
看到这个速率,很多人的第一反应就是普通IO能不能扛。答案是可以,但有两个硬前提:第一是Bank要选HP Bank,VCCO按1.2V或1.8V设置;第二是PCB上差分阻抗必须控制好,远端终端匹配不能省。HS模式下Dp/Dn的差分摆幅大概在100mV到300mV之间,对参考时钟的抖动要求很高。很多第一次上MIPI的板子,link起不来往往不是逻辑写错,而是留在了物理层信号质量这一关。
2.2 LP状态:真正发送数据之前的“握手”
D-PHY有LP(低功耗)和HS(高速)两种工作模式。LP模式是单端信号,两根线各自表示逻辑0或1,组合起来有四种线态:
| 线态 | Dp值 | Dn值 | 含义 |
|---|---|---|---|
| LP-00 | 0 | 0 | HS请求,或者HS结束后的复位 |
| LP-01 | 0 | 1 | HS-0 |
| LP-10 | 1 | 0 | HS-1 |
| LP-11 | 1 | 1 | Stop,空闲状态 |
正常待机时lane停在LP-11,也就是Stop状态。要进入HS传输前,控制器必须在总线上依次拉出LP-11 → LP-01 → LP-00的转换,这个序列完成之后差分对才能开始发送HS时钟和数据。退出HS则反过来:HS数据结束后经过一段T_HS_TRAIL时间,再回到LP-00、LP-10、LP-11。这一段顺序很多人会记错,我建议直接做成状态图,不要让代码靠临时计数器硬猜。
2.3 HS模式:真正的数据搬运阶段
HS模式下时钟lane输出差分时钟,数据lane在时钟两个沿都送数据。D-PHY协议规定每个HS数据包切人前必须先发送一个同步序列0x1D(8bit),接收端靠它锁定字节边界。CSI-2协议中,同步序列之后的字节流才是真正要解析的数据包。
FPGA接收端一般是用ISERDESE2把DDR串行流展开成4bit、6bit或8bit并行数据,再根据同步序列完成bit slip,这就是字节对齐的核心动作。HS传输本身没有“结束标志”这个概念,它靠的是EoT时序和包尾的CRC/ECC校验来保证包的完整性。所以如果CRC一直报错,往往是位流层面的字节边界没对齐,而不是包内容本身错了。
2.4 时序参数:不是每一个都得你亲自调
D-PHY规范里有一堆T参数,比如T_LPX、T_HS_PREPARE、T_HS_ZERO、T_HS_EXIT、T_HS_TRAIL等等。看到满屏公式别慌,FPGA工程师真正要面对的是两个层面。
如果用了外部PHY芯片,LP/HS切换和这些时序参数都在PHY内部完成,FPGA只需要通过类似dir/en这样的控制引脚告诉PHY“我要进HS”或者“我要退HS”,具体驱动时机由PHY保证。不少PHY还提供自动切换模式,FPGA干脆只管理并行数据面。
如果完全想用FPGA引脚硬怼,那确实要把这些时序一个个实现出来。但坦白讲,7系列IO不是原生MIPI物理层,硬怼在LP终端阻抗和HS共模电压上很容易吃亏。我的建议是:除非你只是低速验证协议、速率只有几十Mbps,否则别在自己不熟悉的领域硬来,物理层还是交给专业PHY芯片更靠谱。
2.5 从协议到FPGA:你真正要处理的只有字节流
把物理层交给外部PHY之后,FPGA的工作反而清晰了很多。接收侧把PHY解出来的字节流按CSI-2包格式解析,提取虚拟通道号、数据类型、字计数,再用ECC和CRC验证整包;发送侧把要显示的图像数据按DSI包的格式打包,交给外部DSI桥或PHY发出去。
这也是我强烈建议“先分层再动手”的原因。很多人卡住,就是把物理层和协议层混在一起查,最后非常痛苦。正确顺序是先把并行端用递增pattern打通通路,再去验证MIPI包结构,效率会高很多。
3. C-PHY协议简介:三根线的艺术
3.1 C-PHY和D-PHY到底差在哪里
C-PHY是另一个物理层标准,它的一条lane不再是一对差分线,而是三根线,叫Trio。这三根线工作在“差分三态”上,任意时刻每一根线可以是高、中、低三种电平之一。三根线一起形成有限数量的有效符号,再通过“相邻符号之间必然有跳变”的编码方式来传递信息。
这种设计的好处是时钟被直接嵌入到数据符号中,不再需要独立的时钟lane。对摄像头模组来说,少一对线意味着连接器可以更小、走线更省,系统集成度更高。代价是物理层实现和接收端时钟恢复的复杂度大幅上升。C-PHY的理论带宽也比同线数的D-PHY更高,一根Trio三根线的信息密度明显高于一对D-PHY差分线加一根时钟线的组合。
3.2 嵌入式时钟与符号率
C-PHY的时序以UI为单位,一个UI就是一个symbol interval。由于没有独立时钟,接收端必须从三根线电平的连续变化中恢复出时序。工程上常见C-PHY单lane符号率能做到1Gsps到2Gsps级别,总带宽非常可观。但正因为这些符号变化和时钟恢复都在模拟域完成,FPGA侧通常不会直接去处理C-PHY的三态差分信号,而是通过外部C-PHY PHY把符号流转成并行字节流,FPGA只处理并行数字域。
3.3 D-PHY和C-PHY怎么选
| 对比项 | D-PHY | C-PHY |
|---|---|---|
| 线结构 | 1时钟lane + 1~4数据lane,每lane两根线 | 每lane三根线(Trio) |
| 时钟 | 独立差分时钟 | 嵌在数据符号中 |
| 带宽密度 | 成熟、够用 | 同脚数下更高 |
| 物理层难度 | 中低 | 高 |
| 外部PHY生态 | 非常成熟 | 相对少、价格高 |
| FPGA侧复杂度 | 较低 | 需要专用处理或桥接 |
在FPGA项目里,我目前的结论是:能选D-PHY就优先选D-PHY。C-PHY优势明显,但生态和调试工具都还在成熟期,外部PHY芯片可选项少,价格也偏高。除非传感器型号已经定死、只能接C-PHY,否则不推荐在7系列上自讨苦吃。就算接了C-PHY,FPGA侧也是通过外部PHY完成物理层,FPGA代码主要工作在字节并行域。
3.4 如果非要上C-PHY:最少要准备什么
前提是必须外接支持C-PHY的PHY或者桥接芯片。FPGA侧IO Bank最好选HP Bank,PHY给出的并行接口通常也是LVCMOS或LVDS电平标准。C-PHY的LP/HS转换交给PHY完成,FPGA需要处理的是PHY输出的一些控制、中断、错误标志,再配合协议时序做数据解析。不要幻想用7系列SelectIO直接连C-PHY,那是Versal或者MPSoC里专用硬核或高速收发器才能稳妥搞定的事。
更现实的做法是:先看传感器能不能通过I2C切成D-PHY模式,很多传感器两种模式都支持,只是默认或某个寄存器位不同;如果确实只能C-PHY,再去找C-PHY转D-PHY或C-PHY转并行的桥接方案。
4. Xilinx 7系列SelectIO配置指南(重点)
4.1 Bank等级和VCCO怎么选
7系列IO分为HP(High Performance)和HR(High Range)两类。HP Bank最高支持1.8V的VCCO,对外差分信号的上升沿更快、抖动更小,是高速接口的首选。做MIPI D-PHY HS接收或发送时,对应Bank必须优先选HP Bank,并把VCCO设成和后端PHY或传感器IO电平匹配的1.2V、1.5V或1.8V。
HR Bank虽然支持3.3V,但边沿速率和噪声表现都偏弱,跑几十MHz的GPIO没问题,跑到几百MHz的DDR数据流就比较吃力了。基础约束上,每条差分引脚必须明确指定IOSTANDARD,同时注意VCCO不能低于该标准要求,否则综合后的布局布线工具会直接报错。7系列没有名为“MIPI_DPHY”的原生IOSTANDARD,工程上常用LVDS或LVDS_25配合外部终端来尽量逼近HS差分要求。
4.2 XDC引脚约束和终端电阻怎么设置
XDC约束里最少要写清楚三件事:引脚位置、电平标准、差分终端。写一个示例:
set_property PACKAGE_PIN AE21 [get_ports mipi_clk_p] set_property IOSTANDARD LVDS_25 [get_ports mipi_clk_p] set_property PACKAGE_PIN AF21 [get_ports mipi_clk_n] set_property IOSTANDARD LVDS_25 [get_ports mipi_clk_n] # 开启内部100欧差分终端,前提是板上没有外部终端电阻 set_property DIFF_TERM TRUE [get_ports mipi_clk_p] # 数据lane同样逐对设置 set_property PACKAGE_PIN AD22 [get_ports mipi_data_p[0]] set_property IOSTANDARD LVDS_25 [get_ports mipi_data_p[0]] set_property PACKAGE_PIN AD23 [get_ports mipi_data_n[0]] set_property IOSTANDARD LVDS_25 [get_ports mipi_data_n[0]] set_property DIFF_TERM TRUE [get_ports mipi_data_p[0]]这里有个容易踩的坑:DIFF_TERM只在部分IOSTANDARD下有效,而且如果板子上已经放了外部100Ω终端,内部终端必须关掉,否则双重终端会导致信号反射。特别是MIPI在HS模式下对阻抗匹配很敏感,反射会直接吃掉眼图余量。
4.3 ISERDESE2/OSERDESE2关键参数怎么填
这是整个工程的核心资源。以接收侧4bit DDR模式为例,ISERDESE2的关键参数如下:
- DATA_RATE = "DDR":说明是双沿采样;
- DATA_WIDTH = 4:并行输出位宽,配合内部逻辑把4bit拼成字节;
- INTERFACE_TYPE = "NETWORKING":适合独立时钟的数据采集;
- SERDES_MODE = "MASTER":如果最终需要8bit并行,就要用MASTER与SLAVE级联。
发送方向OSERDESE2的设置逻辑类似,常见配置也是DDR模式输出4bit并行转1bit串行,CLK是位时钟,CLKDIV是字节时钟。数据位顺序必须特别小心:MIPI是LSB first,如果并行端习惯性地写成MSB first,解出来的包内容会全部乱掉。建议在代码注释里强调一次。
接收侧关键例化片段如下:
ISERDESE2 #( .DATA_RATE("DDR"), .DATA_WIDTH(4), .INTERFACE_TYPE("NETWORKING"), .NUM_CE(1), .OFB_USED("FALSE"), .SERDES_MODE("MASTER") ) iserdes_rx_inst ( .O(), // 单bit时使用,这里未用 .Q1(rx_i[3]), .Q2(rx_i[2]), .Q3(rx_i[1]), .Q4(rx_i[0]), .Q5(), .Q6(), .Q7(), .Q8(), .BITSLIP(bitslip_en), .CE1(1'b1), .CE2(1'b1), .CLK(ser_clk), .CLKB(~ser_clk), .CLKDIV(byte_clk), .D(mipi_data_in), .DDLY(rx_input_delayed), .RST(!mmcm_locked), .SHIFTIN1(1'b0), .SHIFTIN2(1'b0) );发送侧OSERDESE2例化如下:
OSERDESE2 #( .DATA_RATE_OQ("DDR"), .DATA_RATE_TQ("DDR"), .DATA_WIDTH(4), .SERDES_MODE("MASTER"), .TRISTATE_WIDTH(1) ) oserdes_tx_inst ( .O(mipi_data_out), .OFB(), .Q1(tx_data[3]), .Q2(tx_data[2]), .Q3(tx_data[1]), .Q4(tx_data[0]), .Q5(), .Q6(), .Q7(), .Q8(), .TQ(), .OCE(1'b1), .CLK(ser_clk), .CLKDIV(byte_clk), .RST(!mmcm_locked), .T(1'b0) );4.4 位时钟、字节时钟和MMCM怎么配合
位时钟ser_clk就是串行数据速率对应的半速率时钟。以800Mbps/lane为例,DDR模式位时钟是400MHz,字节时钟CLKDIV就是100MHz。在4bit模式下,ISERDESE2一个CLKDIV周期送出4bit,连续两个周期正好拼成一个字节。工程中byte clock可以直接由MMCM从ser_clk分频得到,也经常由外部PHY给到FPGA。关键是必须约束好这两个时钟的关系。
create_clock -name ser_clk -period 5.000 [get_pins clk_gen_i/mmcm_inst/clkout0] create_clock -name byte_clk -period 20.000 [get_pins clk_gen_i/mmcm_inst/clkout1] set_clock_groups -asynchronous -group [get_clocks ser_clk] -group [get_clocks byte_clk]如果MIPI时钟来自传感器,外部输入一般是差分,先通过IBUFDS接收,再进MMCM倍频或分频产生串并时钟。RX侧的位域和字节域是不同时钟域,跨域采样很容易出亚稳态,要在ISERDESE2的输出端到后续逻辑之间加入异步FIFO,而不是直接拿组合逻辑硬接。
4.5 IODELAY和Bitslip:数据对齐的最后一步
ISERDESE2解出并行数据后,首先要做字节对齐。MIPI数据包开头的0x1D同步序列就是用来辅助对齐的。常见做法是在并行端对比特做滑动查找0x1D,没对齐就拉一次BITSLIP引脚,直到连续两个包都能正确找到同步序列。数据lane之间的skew则交给lane deskew状态机处理,一般会等所有lane都进入HS并各自完成字节对齐后,以最慢的lane为基准统一释放数据。
IODELAY用于微调输入路径的延迟。如果只是低速验证,可以不例化;但高速跑起来且板级走线有差异时,建议给每条数据lane都加一个IODELAY并做动态校准。7系列里IODELAYE2的延迟精度大约78ps级,可以按UI的1/4到1/2作为初始值去试,再根据实际对齐状态微调。
5. 从原理到工程:一套可落地的收发架构
5.1 整体架构和模块划分
这里给出的是我最终验证通过的架构方案:
- 物理层:一颗外部D-PHY PHY或桥接芯片,负责LP/HS切换、阻抗匹配,以及模拟信号处理。
- FPGA接收侧:IBUFDS接收PHY给出的高频差分时钟和数据(或者PHY直接输出并行数据),经过ISERDESE2解串、bit对齐、lane对齐、CSI-2包解析。
- FPGA发送侧:DSI打包、字节转并行、OSERDESE2串行化,通过外部PHY发送。
- 控制侧:I2C/GPIO配置PHY和sensor,一个上层状态机管理MIPI链路状态。
5.2 接收侧的字节流处理流程
PHY输出的并行数据通常已经是LVCMOS或LVDS并行总线。我先做了一个最简单的字节同步模块,因为每个HS包都以0x1D开头。实现思路是:
- 等待外部PHY的LP状态指示变化,进入HS后启动接收;
- 从ISERDESE2并行端逐字节比较,直到连续出现两次0x1D,确认字节边界锁定;
- 锁定后按CSI-2包解析:读取DI、WC、ECC,校验ECC后按WC接收payload,最后收CRC;
- 出现校验错误就计数并上报,连续错误则重新等待下一包。
核心状态机逻辑大致如下:
reg [7:0] rx_byte; reg byte_locked; reg bitslip_en; always @(posedge byte_clk) begin if (!mmcm_locked) begin byte_locked <= 1'b0; bitslip_en <= 1'b0; end else if (!byte_locked) begin if (rx_byte == 8'h1D) begin byte_locked <= 1'b1; bitslip_en <= 1'b0; end else begin bitslip_en <= 1'b1; // 滑移一位,继续尝试对齐 end end end这个逻辑在低速下很好用,但高速时如果连续几个包都找不到0x1D,建议加一个超时复位,避免状态机卡死。
5.3 发送侧的DSI/CSI-2打包
发送侧相对简单,关键是把图像数据按包里封好。以DSI发一帧为例,顺序是:
- 让PHY先完成LP退出序列,进入HS;
- 发送同步序列0x1D;
- 按包格式发送DI、WC、ECC、payload、CRC;
- 遇到帧空隙可以插入BLLP,也可以选择退回LP状态休息。
当时为了提速,我用字填充的形式把颜色数据按RGB565拼成半字,再按64bit位宽写入FIFO,之后再经过并转串逻辑把64bit轮转成8bit。这样可以保证FPGA内部工作频率不需要太高,1080p30的视频流实际大概在200MHz以内,给逻辑时序留了不少余量。
5.4 外部PHY和控制引脚的对接
千万不要让FPGA直接驱动MIPI差分对。选外部PHY时重点看三件事:
- 是否支持目标sensor或屏的速率,以及D-PHY/C-PHY模式;
- LP/HS切换是自动还是需要外部控制,需要外部控制时,把PHY的dir或en引脚接到FPGA普通GPIO,用状态机管理;
- 是否带I2C从站,能否通过寄存器配置终端电阻、驱动强度、均衡参数。
调试初期建议先把PHY接成“直通模式”,也就是当纯电平转换器用,让FPGA输出一个固定低频pattern验证通路,等通路稳定后再逐步提高速率。这一步能省下很多来回猜问题的时间。
5.5 时序收敛的几个心得
- 不要在ISERDESE2的输出端堆太多组合逻辑,解出来先打一拍寄存;
- 字节域和位域之间务必用异步FIFO跨时钟,避免跨时钟直接采样;
- 多lane的并行数据尽量收在同一个字节时钟域做对齐,避免各lane各用各的时钟导致约束复杂;
- 时序不过时,优先看最大延迟路径是不是落在OSERDESE2的Q端到后续数据选择逻辑之间,必要时增加流水级数。
6. 调试实录与常见问题速查
6.1 示波器怎么看LP和HS波形
MIPI差分对用示波器探头接Dp/Dn。LP模式下能看到明显的单端高低电平;HS模式下两线之间是200mV左右的差分信号。观察的重点是从LP-11到LP-01再到LP-00的转换链是否干净。如果HS波形幅度不够或者上升沿太平,先查外部终端电阻和Bank电压,不要急着动RTL。
当时我们有一个lane的幅值只有120mV,查了半天发现是终端电阻贴了双份,反射把能量抵消了。换回单份终端后幅度立刻恢复正常。这类问题用眼图看最直观,MIPI模式下示波器如果支持HS眼图模板,直接把通过门限设好跑一轮,比一个个量可快多了。
6.2 ILA抓字节流的正确姿势
FPGA内部用ILA观察并行字节流时,触发条件可以设为rx_byte == 8'h1D。如果长时间触不到,先怀疑ISERDESE2位序或者bitslip没有正常工作;如果触发到了但解析CRC一直报错,就用递增pattern法从简到繁定位,是位错还是包结构错。递增pattern就是1、2、3、4……的字节序列连续发,出错时能很清楚地看出是第几个字节开始乱。
我有一次调试发现同步序列明明抓到了,但后续数据全部错乱,后来加了一个每秒触发一次的计数器抓包,才发现是边沿采样时钟相位偏了半个UI。ILA触发不到东西的时候,记得同时监测时钟锁定信号和PHY的状态输出,别只盯数据线。
6.3 常见问题优先排查表
| 现象 | 可能原因 | 检查顺序 |
|---|---|---|
| LINK完全不启动 | Bank电压/VCCO、外部PHY供电、复位顺序不对 | 先查供电,再查PHY寄存器状态 |
| 进入HS但收不到数据 | 差分终端缺失、数据位序反了、同步序列被跳过 | 示波器看波形,再关掉bitslip观察 |
| 数据始终乱码 | 字节对齐失败、lane间skew超标 | 单lane自回环,再加IODELAY微调 |
| ECC/CRC频繁报错 | 毛刺或串扰导致单bit错误 | 降速率测试,优化PCB,看眼图 |
| 两个lane数据交错 | lane对齐没生效 | 强制所有lane锁定后再放行 |
| 偶发link drop | 时钟抖动、温度漂移、IO电平临界 | 加终端电阻,提高PHY驱动强度,做温度循环测试 |
6.4 踩过的三个坑,值得记下来
第一个坑是引脚电平标准写错。XDC里IOSTANDARD写了LVDS_25,但实际上Bank的VCCO是1.2V。综合能过,但板子一跑就异常,最后把CFGBVS和Bank电压统一改成1.8V才稳定。7系列的I/O标准和VCCO关系非常严格,一定要提前核对IBIS模型和原理图。
第二个坑是bit order。MIPI是最低有效位先发,我们第一次按照习惯把并行数据bit0接到Q1、bit7接到Q8,结果解析出来的数据标识和字计数全是反的。后来把ISERDESE2的Q1对应并行数据bit0、Q4对应bit3,方向理顺之后一切正常。
第三个坑是外部PHY的上电时序。很多PHY要求先供电再拉复位,复位之后还要等几百毫秒才能写I2C寄存器。第一版代码上电就立刻配置寄存器,导致PHY状态乱七八糟。后来在配置状态机里加了一个延时1秒后再写寄存器的保险,才终于稳定复现。
6.5 最终怎么验证链路稳定性
验证MIPI链路稳不稳定,不能只看一帧图像。我的做法是发送端循环发递增pattern,接收端统计连续正确包数,至少连续10000个包无错才算过关。之后再上模拟图像数据,观察行场时序和色彩是否有异常,最后还要做高低温循环老化测试。稳定不等于正确,正确也不等于能用,只有这三层验证都过了,我才放心把板子交出去。
最后说点个人体会。MIPI这套体系,协议栈拉长看确实吓人,但落到FPGA实现上,真正要死磕的其实就是物理层接入和字节对齐这两关。能用外部PHY分担的就不要自己硬扛,能复用成熟IP核的就别自己造轮子。我踩过最大的坑就是在物理层上花费了太多时间,后来发现把精力放到协议解析和数据通路设计上,项目推进反而快得多。如果你的项目正好也是7系列加MIPI这种组合,我的建议是:先分清楚层次,再动底层资源,最后再上高速验证。别一上来就跑满带宽,先25MHz调通,再100MHz、400MHz逐步加码,每步留足余量。祝各位早日调通自己的链路,少熬几个夜。