3. MIPI协议层(CSI-2):分层结构、长包与短包、数据类型与虚拟通道
各位同学,今天我们来聊聊MIPI CSI-2的协议层。说实话,很多工程师做摄像头驱动调了半年,对物理层(D-PHY)的时序倒背如流,但一提到协议层就含糊其辞。我个人觉得,协议层才是真正决定你能否把图像数据“看懂”的关键。你想想看,物理层只是把0和1传过来,但怎么解析成像素、怎么区分不同摄像头的数据,全靠协议层说了算。
3.1 CSI-2的分层结构
CSI-2协议层,说白了就是一套“数据打包规范”。它从上到下分为三层:
- 应用层:处理像素数据,比如RGB、YUV、RAW等格式的转换。
- 协议层:负责数据打包、解包,包括长包和短包的生成与解析。
- 物理层:D-PHY或C-PHY,负责电气信号的传输。
嗯,这里要注意,我们平时说的“MIPI调试”,90%的时间都在和协议层打交道。我在项目中遇到过好几次,明明物理层眼图测试都过了,但图像就是花屏。最后发现是协议层的包长度计算错了,导致数据错位。所以,别小看这层。
核心要点:协议层是连接物理层和应用层的桥梁。它不关心电压高低,只关心数据怎么组织。
3.2 长包与短包
MIPI CSI-2的数据传输,分为两种包:长包和短包。我刚开始学的时候,总觉得这名字起得太随意了。但用久了你会发现,这名字其实很贴切。
3.2.1 短包(Short Packet)
短包只有4个字节,固定长度。它用来传输控制信息,比如帧同步、行同步、数据类型标识等。短包的结构很简单:
- 数据标识符(DI):1字节,包含虚拟通道号和数据类型。
- 数据字段:2字节,具体含义由数据类型决定(比如帧号、行数等)。
- ECC:1字节,纠错码,保护前3个字节。
短包最常见的用途就是帧起始(FS)和帧结束(FE)。我记得有一次调试一个800万像素的摄像头,图像总是少了几行。抓包一看,发现帧结束短包里的行数计数不对。嗯,这种问题用示波器抓D-PHY信号根本看不出来,必须用协议分析仪。
小技巧:调试时优先检查短包。如果短包里的ECC报错,那后面的长包数据大概率也是错的。我曾经因为这个习惯,省下了整整两天的排查时间。
3.2.2 长包(Long Packet)
长包用来传输真正的图像数据。它的长度是可变的,结构如下:
长包结构:
+--------+--------+--------+--------+--------+--------+--------+--------+
| DI | WC (低字节) | WC (高字节) | ECC | 数据负载 (WC字节) | CRC |
+--------+--------+--------+--------+--------+--------+--------+--------+
| 1字节 | 2字节 | 1字节 | WC字节(可变) | 2字节 |
+--------+--------+--------+--------+--------+--------+--------+--------+
- DI:数据标识符,同短包。
- WC:字计数(Word Count),表示数据负载的字节数。
- ECC:纠错码,保护DI和WC。
- 数据负载:实际的像素数据。
- CRC:循环冗余校验,保护数据负载。
你想想看,为什么要有WC?因为图像分辨率不同,每行的数据量也不同。WC告诉接收端“这一包有多少数据”,这样接收端才知道什么时候该收下一个包。我在项目中遇到过一种情况:摄像头输出的分辨率是1920x1080,但WC算出来是1922。结果每行多出2个字节,图像就斜了。排查了半天,发现是驱动里对齐设置错了。
避坑指南:我曾经因为WC计算错误,导致图像出现“锯齿状”偏移。检查WC时,一定要确认它是否包含了填充字节(padding)。有些传感器会在行尾自动补0对齐,WC里是包含这些填充字节的。
3.3 数据类型(Data Type)
数据类型(DT)是DI字段中的高6位,用来告诉接收端“这包数据是什么格式”。常见的DT值如下:
| 数据类型 | DT值(十六进制) | 说明 |
|---|---|---|
| 帧起始(FS) | 0x00 | 短包,表示一帧开始 |
| 帧结束(FE) | 0x01 | 短包,表示一帧结束 |
| 行起始(LS) | 0x02 | 短包,表示一行开始 |
| 行结束(LE) | 0x03 | 短包,表示一行结束 |
| RAW8 | 0x2A | 长包,8位RAW数据 |
| RAW10 | 0x2B | 长包,10位RAW数据 |
| RAW12 | 0x2C | 长包,12位RAW数据 |
| RGB888 | 0x24 | 长包,24位RGB数据 |
| YUV420 8位 | 0x1E | 长包,YUV420格式 |
我建议你把这张表存下来。调试时最常遇到的情况就是:摄像头输出的是RAW10,但接收端配置成了RAW8。结果图像颜色完全不对,像鬼片一样。说白了,就是数据类型没对上。
经验之谈:配置摄像头时,先确认传感器手册里支持哪些DT值。有些传感器虽然标称支持RAW10,但实际输出时DT值可能写的是0x2B还是0x2C,一定要看寄存器配置。
3.4 虚拟通道(Virtual Channel)
虚拟通道(VC)是DI字段中的低2位。它有什么用呢?简单说,就是让一条MIPI物理链路上可以同时传输多路摄像头的数据。
举个例子:你做一个双摄手机,主摄和广角共用一条MIPI总线。主摄的数据包VC=0,广角的数据包VC=1。接收端根据VC值,把数据分别送到不同的处理模块。这样就不用为每个摄像头单独拉一条MIPI线了,省引脚、省PCB面积。
虚拟通道的取值范围是0~3,共4个通道。DI字段的结构如下:
DI(1字节):
+----+----+----+----+----+----+----+----+
| DT6 | DT5 | DT4 | DT3 | DT2 | DT1 | VC1 | VC0 |
+----+----+----+----+----+----+----+----+
| 数据类型(6位) | 虚拟通道(2位) |
我在项目中遇到过一个问题:两个摄像头都配置了VC=0,结果数据混在一起,图像像“叠影”一样。排查了半天,发现是驱动初始化时忘了给第二个摄像头设置VC值。嗯,这种低级错误,犯过一次就再也不会忘了。
实用建议:多摄像头项目中,建议把主摄固定为VC=0,副摄固定为VC=1。这样调试时,看到VC=0的数据就知道是主摄的,逻辑清晰。我曾经见过一个项目,VC分配得乱七八糟,最后查问题查得想摔示波器。
3.5 总结
好了,这一章的内容就这些。总结一下:
- CSI-2协议层分为应用层、协议层、物理层,各司其职。
- 短包传控制信息,长包传图像数据。短包固定4字节,长包可变长度。
- 数据类型(DT)告诉接收端数据格式,配置错了图像就花。
- 虚拟通道(VC)让一条MIPI总线可以传多路数据,多摄像头项目必备。
说实话,协议层的东西看起来琐碎,但每一个细节都可能成为你调试路上的“坑”。我建议你找个开发板,实际抓一包数据,对照着协议手册看一遍。纸上得来终觉浅,绝知此事要躬行。
核心一句话:MIPI协议层就是一套“数据打包规则”。你理解了长包短包、DT和VC,就等于拿到了读懂MIPI数据的钥匙。