简介MIPI CSI-2 是 MIPI Alliance 制定的摄像头串行接口规范广泛用于手机、无人机与车载电子设备中摄像头模组与主机处理器之间的高速图像数据传输。这份 PDF 为 2009 年 4 月发布的草案版本 1.01.00 r0.04面向从事摄像头驱动、图像采集、嵌入式硬件与 SoC 接口设计的工程师及学习者可用于理解协议底层帧结构、物理链路与时序约束。文档系统阐述了多 Lane 并行通道配置、LVDS 差分信号编码、YUV/RGB 等像素格式与 8/10/12 位位深、包头与校验字段组成的数据包结构、CLK Lane 同步机制、低功耗电源管理、CRC 错误检测与恢复策略以及与 D-PHY、C-PHY 等其他 MIPI 规范的兼容关系。压缩包内仅含 1 个 PDF 文件大小约 2.6MB内容为规范原文便于按章节查阅协议定义与寄存器级细节。目前已有 1507 人学习下载适合希望从标准源头掌握 CSI-2 数据流与调试依据的读者作为案头参考。1. 摄像头点不亮的那两周MIPI CSI-2 到底规定了什么拿到新板子的头两周最常见的场景是电源正常、I2C 能读到芯片 ID、串口日志干净得让人心虚可一打开设备节点超时、超时、还是超时。这时候能查的东西其实很少——驱动只告诉你“没收到帧”示波器只告诉你“线上有波形”中间那几百毫秒里到底发生了什么全靠 MIPI CSI-2 这套规范来解释。它规定的不只是“摄像头怎么接线”而是从差分电平怎么翻转、一个包由哪几个字节组成、到一帧图像如何被切成一串长短包的全部细节。所以我把这份 MIPI-CSI-2.pdf 当成排错手册用链路不通时先怀疑物理层链路通但图像不对时翻协议层两边都对但数据不对时再回头看配置。这篇写的就是这条路径——先算清带宽和电平的账再拆包看协议然后落到上电时序、设备树和测试图案最后把几种翻车现场摊开讲。做嵌入式视觉、机器视觉、车载影像的同行如果你手上正有一颗 CSI-2 摄像头没跑起来或者多摄链路偶发丢帧下面的顺序应该能省掉你几天时间。2. 先把 D-PHY 的带宽账算清楚lane 数、速率和时钟模式怎么定2.1 从像素格式反推总带宽一条 lane 到底能扛多少选型会上被问得最多的一句是“这颗传感器 2 lane 够不够”。这个问题不能凭经验拍得算。CSI-2 上的数据量等于有效像素数据乘以一个开销系数再平摊到每条 lane 上。开销来自行场消隐、前后肩、包头包尾和短包实际取值通常落在 1.15 到 1.25 之间短包多、行消隐长的传感器取上限全速输出的取下限。算出来的每 lane 速率还要留 15% 以上余量因为 D-PHY 标称速率是理想条件下的数字走线、连接器、参考平面任何一处不干净眼图就会塌。用脚本把这笔账固化下来比每次开会拿计算器按要靠谱def lane_rate(width, height, fps, bpp, lanes, overhead1.20, margin1.15): 反推每条 lane 需要的速率Mbps width/height: 有效分辨率 bpp: 每像素有效位数RAW88, RAW1010, RAW1212 lanes: 数据 lane 数不含时钟 lane overhead: 消隐/包头开销系数1.15~1.25 margin: 速率余量建议 1.15 pixel_bps width * height * fps * bpp # 纯像素比特率 total_bps pixel_bps * overhead * margin # 含开销与余量 per_lane total_bps / lanes / 1e6 # 换成 Mbps return pixel_bps / 1e6, total_bps / 1e6, per_lane for lanes in (1, 2, 4): p, t, l lane_rate(1920, 1080, 30, 10, lanes) print(f{lanes} lane - 纯像素 {p:.0f} Mbps, 含开销 {t:.0f} Mbps, 每 lane {l:.0f} Mbps)脚本里的bpp用的是有效位数不是打包后的字节数。RAW10 传输时是 4 个像素打包成 5 个字节链路上一共还是 10 bit/像素只是字节边界不对齐这一点在算带宽时不用额外修正。overhead和margin分开放是因为它们的性质不同前者是协议必然产生的浪费后者是工程上主动让出的安全区。我一般把overhead按传感器手册给出的行场参数实算一遍再和 1.2 对一下差太多就说明手册里的 blanking 被改过。常见配置的结果大致是这样分辨率格式帧率纯像素速率含开销(1.20)2 lane 每 lane4 lane 每 lane1280×720RAW1060553 Mbps664 Mbps332 Mbps166 Mbps1920×1080RAW1030622 Mbps747 Mbps373 Mbps187 Mbps1920×1080RAW12601493 Mbps1792 Mbps896 Mbps448 Mbps3840×2160RAW10302488 Mbps2986 Mbps1493 Mbps747 Mbps3840×2160RAW12302986 Mbps3583 Mbps1792 Mbps896 Mbps看表能得出两个结论。一是 4K RAW12 在 2 lane 下每 lane 要接近 1.8 Gbps这已经压在很多中低端 PHY 的上限附近实测很容易出 CRC 错必须上 4 lane。二是 1080p60 RAW12 是个容易被低估的坑很多人按 1080p30 的经验配 2 lane结果帧率上不去还以为是驱动限帧。还有一个约束来自传感器侧的 PLL它能输出的链路速率是有限档位不是连续可调。算出来 373 Mbps实际可能只能选 360 或 400选完再回算帧率。这一步在写设备树之前就要定死否则后面改 link-frequencies 会牵动一片参数。2.2 HS/LP 电平与 settle time物理层三个必须对上的参数CSI-2 的物理层是差分高速加单端低功耗的双模结构。平时线路停在 LP-11两条线都是高电平要发数据时走 LP-01 → LP-00 → HS-0 的进入序列然后发送同步码 00011101接着才是有效载荷发完回到 LP-11。整个过程里最容易出问题的是从 LP 切到 HS 的那段过渡——接收端要在这段时间里完成共模电平的建立和比较器阈值的切换给的时间不够第一个比特就是不可靠的。参数含义典型取值配错的后果T-HS-SETTLE从 LP-00 到 HS 开始的有效建立时间高速率 30~50 ns低速率 60~100 ns偏小导致首字节错ECC 报错、整行丢失T-HS-ZEROHS-0 状态持续时间≥ 2 UI 且不小于 40 ns偏小导致同步码识别失败T-HS-TRAIL最后一个比特到进入 LP 的时间≥ 1 UI 且不小于 30 ns偏小导致末字节被截断T-CLK-SETTLE时钟 lane 的建立时间通常比数据 lane 再宽 10~20 ns时钟采样点漂移全链路随机错LP 电平低功耗态单端电平0 ~ 1.2 V电平不匹配会误判进入序列HS 差分摆幅高速态差分幅度约 200 mV 差分摆幅不足眼图闭合调 settle 的顺序是先用传感器默认值手册里通常给一个保守值把链路跑通再往上加压测如果出现 ECC 单比特错或偶发 CRC 错把 T-HS-SETTLE 按 10 ns 一档往上加加到错误消失后再加一档留余量。这条“血泪经验”来自柔性排线同一套参数在 5 cm 硬板上完美换到 20 cm FPC 上就开始随机丢行加到 80 ns 才稳。时钟模式是另一个必选项。连续时钟continuous clock在帧间也让时钟 lane 保持高速翻转好处是接收端不用反复唤醒采样点稳定代价是功耗高、EMI 稍差。非连续时钟non-continuous clock在帧间回到 LP 状态省电但每次重新进入 HS 都要走一遍建立流程settle 不够就直接丢帧头。我一般这样定单摄、短线、低帧率用非连续多摄、长 FPC、高帧率一律连续时钟用功耗换稳定这笔账很划算。电气上还有三个底线要守住差分阻抗 100 Ω±10%对内走线等长控制在 5 mil 以内差分对之间间距拉开到 3 倍线宽以上参考平面必须完整跨分割是眼图塌掉的头号原因。这些属于 PCB 阶段的事等板子回来再补救成本极高。2.3 lane 数与走线长度选型阶段就必须定下来的三件事lane 数不是越多越好。每加一对差分线就多一份 skew 风险和一份功耗而 SoC 侧的 PHY 往往有“支持 4 lane 但只有 2 lane 能跑满速”这种隐性限制。选型时把这三件事对齐后面的坑能少一半第一是传感器能跑的最高 lane 速率和对应 lane 数组合手册里通常给出几档比如 2 lane 1.5 Gbps 或 4 lane 0.9 Gbps 都能达到同一总带宽这时候优先选 lane 数少的那档因为走线简单、skew 好控。第二是 SoC 侧 PHY 的实际上限。很多平台的 PHY 标称 2.5 Gbps/lane但在 4 lane 全开时因为内部 PLL 分频限制实际只能到 2.0 Gbps 左右。这个数字不会写在数据手册的首页得翻 PHY 章节或者直接实测。第三是物理走线。20 cm 以上的 FPC 上跑 1.5 Gbps 已经开始需要挑连接器和加屏蔽如果结构限制只能走长线宁可降速率、加 lane 数用并行换串行的裕量。把这三条合起来实际工程里最稳的组合往往是分辨率不超过 1080p60 用 2 lane4K 用 4 lane2 lane 跑 4K 只在短硬板加散热良好的前提下考虑。3. 拆开一个 CSI-2 数据包短包、长包与包头那 4 个字节怎么读3.1 数据标识 DI 与虚拟通道 VC一张编码表管住所有格式CSI-2 链路上跑的所有东西都是包包分两类短包 4 个字节只用来传事件帧开始、帧结束、行开始、行结束长包在 4 字节包头之后跟有效载荷末尾再加 2 字节校验。两类包的开头都是同一个字节——数据标识Data Identifier高 2 位是虚拟通道号低 6 位是数据类型Data Type。数据类型决定了解析方式配错一位整帧图像就是花屏。常用的编码DT 值含义备注0x00Frame Start短包标志一帧开始0x01Frame End短包标志一帧结束0x02Line Start短包可选部分传感器不发0x03Line End短包可选0x12Embedded Data长包行内嵌统计信息0x1EYUV422 8-bit长包0x24RGB888长包0x2ARAW8长包0x2BRAW10长包4 像素打包 5 字节0x2CRAW12长包2 像素打包 3 字节0x2DRAW14长包虚拟通道只有 2 位所以一条链路上最多 4 路独立数据流。多摄方案里靠它把不同传感器的数据区分开接收端按 VC 号分流到不同 buffer。这里有个容易忽略的细节VC 是发送端决定的接收端只是照着分所以两颗传感器如果都默认 VC0同一条 lane 上就会撞车症状是两路画面交替出现、帧率减半。3.2 包头四个字节怎么读WC、ECC 与 CRC 的分工长包的包头是 4 个字节DI1 字节、WC2 字节小端、ECC1 字节。WC 是字长表示后面载荷有多少字节最大 65535所以一个长包最多装 64 KB 数据一行 4K RAW10 大约是 9600 字节装得下。短包复用这两个字节传事件参数比如帧号。ECC 是 8 位里用了 6 位的汉明码能纠正 1 比特错、检测 2 比特错载荷末尾的 CRC 是 16 位只检错不纠错。这个分工很关键包头出错会导致整包被丢弃载荷出错只是这一包数据不可信。所以排查时看 ECC 错和 CRC 错的含义完全不同——ECC 错基本指向物理层时序或者 lane 极性CRC 错更多指向信号完整性和速率超限。用一小段脚本把抓到的包头解出来是排错时最省时间的动作def parse_header(b0, b1, b2, b3): 解析 CSI-2 长包 4 字节包头 vc (b0 6) 0x03 # 高 2 位虚拟通道 dt b0 0x3F # 低 6 位数据类型 wc b1 | (b2 8) # 小端字长 ecc b3 # 6 位 ECC 的校验子计算简化仅保留位平面异或关系用于快速判 0 syndrome ecc ^ ( ((b0 5) 1) 5 | ((b1 5) 1) 4 | ((b2 5) 1) 3 | ((b0 4) 1) 2 | ((b1 4) 1) 1 | ((b2 4) 1) ) return {vc: vc, dt: hex(dt), wc: wc, ecc: hex(ecc), syndrome: syndrome} print(parse_header(0x2B, 0x80, 0x25, 0x1C)) # 示例字节实际从抓包取 print(parse_header(0x00, 0x00, 0x00, 0x00)) # Frame Start 短包vc和dt是从第一个字节直接切出来的wc要按小端拼。示例里0x2580等于 9600正好是 3840 像素 RAW10 一行打包后的字节数3840×10/84800若为双像素并行输出则翻倍拿到这个数字就能反推传感器是不是按你预期的行宽在发。示例中的syndrome只是一个快速判零的近似真要纠错得按规范里的位平面矩阵实现工程上一般直接读接收端 IP 的 ECC 错误计数寄存器比自己算快得多。3.3 行边界怎么恢复LS/LE 短包与 WC 累加两条路规范里行开始、行结束短包是可选的这就导致两种完全不同的接收端实现。一种靠 LS/LE 短包切行一种靠 WC 累加计数切行——接收端知道自己要收多少字节一行收够就切。两条路都能工作但配置必须和发送端对齐。症状很好认如果传感器不发 LS/LE 而接收端配成依赖短包切行画面会整体斜切或者上下半帧错位反过来传感器发了 LS/LE 而接收端不认会把这些短包当成异常包丢弃甚至报错帧率看起来正常但每帧开头缺几行。我一般先看传感器手册里 LS/LE 的使能位再去看接收端驱动的配置项两边对上再谈别的。另一个容易翻车的地方是 RAW10 的打包边界。一行 1920 像素的 RAW10 是 2400 字节能被 5 整除但换成 1280 像素是 1600 字节也能整除而某些裁剪窗口比如 1282 宽就不整除最后一个打包组要补零到 5 字节边界。接收端如果按“宽度×10/8”直接算字节数去取会差 1 到 4 个字节症状是每行末尾几个像素错位越往画面右边越明显。遇到这种“只有右边缘花”的现象先怀疑窗口宽度不是 4 的倍数。4. 把第一帧点出来上电时序、设备树与测试图案的最小闭环4.1 上电与 I2C 写寄存器三段式序列怎么写成可复现的点屏失败的原因里有一半不在协议上而在上电顺序。传感器通常要求三路电源按固定顺序起来比如先模拟后数字再 IO中间还要等稳定时间复位要在电源稳定之后拉低足够长。这些参数手册里都有但很多人图省事一次全拉高运气好能跑运气不好就是“有时候能出图有时候不能”。把上电拆成三段来写可复现性最好第一段拉电源并延时第二段给时钟第三段复位释放后写初始化寄存器。每段之间留出可调的延时参数出问题时先加延时比改寄存器序列收益高。# 段一电源依次使能间隔 5 ms最后等待 10 ms 稳定 gpio set pwdn 0 gpio set vdd_ana 1; sleep 0.005 gpio set vdd_dig 1; sleep 0.005 gpio set vdd_io 1; sleep 0.010 # 段二提供主时钟部分平台由 SoC 输出部分由外部晶振 gpio set mclk 1; sleep 0.005 # 段三释放复位延时后读 ID 确认通信 gpio set reset 1; sleep 0.020 i2ctransfer -y 3 w20x36 0x30 0x0a r1 # 读芯片 ID 高字节 i2ctransfer -y 3 w20x36 0x30 0x0b r1 # 读芯片 ID 低字节i2ctransfer的w20x36表示向地址 0x36 写 2 个字节寄存器高字节、低字节r1表示读 1 个字节。读 ID 这一步必须做它是把“电源和时序问题”和“配置问题”分开的分水岭ID 读不到后面所有事都别谈ID 读得到但出不了图问题在链路或配置上。我见过不止一次有人跳过这步直接调驱动最后发现是复位极性接反。初始化寄存器的写法建议用“表格 生成脚本”而不是手写数组。表格里一行一个寄存器包含地址、值、延时、依赖条件生成脚本把它转成驱动里的结构体数组。这样换传感器型号时只改表不动代码也方便对照手册逐条核。顺序寄存器值延时说明10x01030x015 ms软复位20x03010x04—模拟电路偏置30x03030x01—电源顺序控制40x30000x001 ms退出待机50x30180x02—2 lane 模式60x30310x0A—RAW10 输出70x01000x0110 ms开始出流这里的值只是结构示意实际必须照着手册填。重点在第 5、6 行lane 数和输出格式必须和接收端配置一致这两项错一个画面就完全不对。4.2 设备树与媒体管线lane 映射和链路频率写在哪Linux 平台上CSI-2 接收端的配置绝大多数落在设备树里。几个关键属性csi2_receiver { status okay; clock-noncontinuous; /* 非连续时钟连续时钟则删掉此行 */ port { csi_in: endpoint { remote-endpoint sensor_out; ># 1. 查看拓扑确认 sensor - csi - isp 的链路已经连通 media-ctl -p -d /dev/media0 # 2. 在 sensor 节点上配置格式必须与 DT 和寄存器一致 media-ctl -d /dev/media0 \ --set-v4l2 sensor 0-0036:0[fmt:SBGGR10_1X10/1920x1080] # 3. 打开测试图案具体寄存器地址按手册 i2ctransfer -y 3 w30x36 0x30 0x0a 0x01 # 4. 抓 10 帧原始数据不做任何处理 v4l2-ctl -d /dev/video0 --set-fmt-videowidth1920,height1080,pixelformatRG10 \ --stream-mmap --stream-count10 --stream-to/tmp/raw10.binmedia-ctl那条fmt:里的SBGGR10_1X10要和 sensor 的 Bayer 排列、位深、打包方式完全对上写错的话数据能出来但颜色全错。v4l2-ctl抓下来的.bin是裸数据用一段脚本按 16 位对齐展开就能看import numpy as np w, h 1920, 1080 raw np.fromfile(/tmp/raw10.bin, dtypenp.uint16) frame raw[:w*h].reshape(h, w) 6 # RAW10 存在高 10 位右移对齐到 8 位显示 print(frame.min(), frame.max(), frame.mean())如果彩条抓出来是规整的竖条、边界清晰、没有横纹说明链路、时序、打包全部正确可以放心去调真实图像如果彩条本身就有横纹或错位问题百分之百在链路层别再去改 ISP 参数。5. 避坑与排查CSI-2 链路上最常见的 5 种翻车现场5.1 先分层定位物理层、协议层、驱动层各看什么排错最怕的就是“到处改一点”。我习惯先把症状按层归类每层只看固定的几个指标症状先看哪一层抓什么完全没有 /dev/video 节点驱动层设备树 status、probe 日志、I2C 通信有节点但 open 超时、收不到帧物理层lane 极性、settle、时钟模式、FS 短包是否到达能收帧但 CRC/ECC 计数持续增长物理层 链路速率每 lane 速率是否超限、走线长度、连接器图像花屏、只有右边缘错协议层DT 值、打包边界、窗口宽度是否为 4 的倍数帧率对不上、隔帧丢配置层overhead 是否算漏、PHY 分频、buffer 数量这张表的价值在于它把“改”这个动作限制在一个层里。跨层乱改最典型的后果是本来只是 lane 顺序反了改着改着把 settle 也动了最后链路通了却不知道为什么通下次换个板子又全乱。5.2 五条血泪踩坑记录从无帧到花屏第一条ID 能读就是不出图。现象是 I2C 通信正常、probe 成功、设备节点存在但一开流就超时串口无任何错误。原因查到最后是style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;" />