帧结构与数据包格式:长包与短包、帧头帧尾、Escape模式

说到MIPI CSI-2的帧结构,我个人的经验是——如果你不理解长包和短包的区别,那调试起来基本就是靠猜。网上很多教程把它讲得玄乎,其实说白了就一句话:短包管控制,长包扛数据。

咱们今天把这块彻底捋清楚。我会结合我遇到过的几个坑,帮你把帧头帧尾、Escape模式这些东西都消化掉。

什么是短包?什么是长包?

CSI-2链路上跑的有两种包:短包(Short Packet, SP) 和 长包(Long Packet, LP)。它们有完全不同的用途。

特性 短包 长包
长度 固定 4 字节(32 bit) 可变长度(4~65535+CRC字节)
内容 只含数据标识符(DI)+ 字数据或虚拟通道/数据类型 DI + 字计数 + 实际像素数据 + ECC + CRC
净荷 无净荷,仅控制信息 有净荷,存放图像数据或元数据
常用场景 帧开始(FS)、帧结束(FE)、行开始(LS)、行结束(LE) 传输实际像素行数据,或嵌入式数据块

举个实际例子:我调试一个1080p sensor时,发现画面总是上下颠倒。查了半天,发现是短包里的帧开始/帧结束顺序发反了。嗯,这里要注意——短包虽然小,但它决定了整个帧的边界。

帧头与帧尾:FS 和 FE

每帧数据的边界由两个短包划定:

  • Frame Start (FS):数据类型(DT)= 0x00(传统模式)或 0x01(带虚拟通道)。
  • Frame End (FE):DT = 0x01(传统模式)或 0x11(带虚拟通道)。

你想想看,如果没有FE,接收端就一直等数据,直到缓冲溢出或者超时。我曾经遇到一个项目,sensor输出FE丢失,结果FPGA那边一直卡在行缓冲区不释放,整个系统死锁了。所以FS和FE必须成对出现,这是CSI-2协议的基本契约。

我个人的小技巧:用逻辑分析仪抓包时,先看短包序列。如果能抓到连续的FS→(多行长包)→FE,说明协议层至少没断。如果缺FE,检查sensor配置页面里的"frame end enable"寄存器是不是被关了。别笑,我见过三次类似情况。

行起始与行结束:LS 和 LE

对于逐行传输的sensor,每一行也由短包划定边界:

  • Line Start (LS):DT = 0x02
  • Line End (LE):DT = 0x03

不过有些sensor为了省带宽,会忽略LS/LE,只用FS/FE配合长包里的字计数来识别行边界。这取决于你的数据传输模式配置。

避坑指南:我曾经在一个项目中同时启用了LS/LE和长包内的字计数,结果接收端解析时做了两次边界判断,导致每行丢失最后一个像素。后来我关掉了LS/LE,只用字计数+CRC校验,问题解决。所以——别用双重保险,协议没说让你叠加用。

长包格式详解

长包是真正搬运图像数据的主力。它的结构分为三段:

  1. 包首(Packet Header, PH):固定4字节,包含数据标识符(DI,含虚拟通道和数据类型)+ 16位字计数 + ECC。
  2. 包数据(Packet Data):长度由字计数决定,单位是字节(或word,取决于配置)。
  3. 包尾(Packet Footer, PF):固定2字节CRC-16校验。

下面是典型的长包字节序(以CSI-2传统模式为例):

Byte 0: Data Identifier (VC[1:0] + DT[5:0])
Byte 1: Word Count Low Byte
Byte 2: Word Count High Byte
Byte 3: ECC (6-bit EC + 2-bit header correction)
Byte 4 .. (Word Count)*: Raw pixel data (e.g., raw10 packed as 5 bytes per 4 pixels)
Byte (4+WordCount) .. (4+WordCount+1): CRC-16 (optional, depends on mode)

注意:字计数的单位在不同PHY配置下有差异,一般是字节数。

核心要点:ECC保护的是包首本身,CRC保护的是包尾。我曾经试过故意破坏包首的一个bit,接收端ECC能自动纠正1-bit错误,但2-bit错误直接丢包。这个丢包行为由接收端实现决定,有些芯片会丢弃整包,有些会报错中断。调试时务必确认你的SoC的CSI-2控制器是怎么处理ECC错误的。

Escape模式:不是每根线都跑CSI

Escape模式是MIPI D-PHY物理层提供的一种超低功耗数据传输模式,用于传输控制信息(如触发信号、状态查询、或低速数据传输)。它在数据传输通道(不是时钟通道)上通过特定的LP(低功耗)状态序列来进入。

其工作原理简单说:

  • 物理层从HS(高速)或LP(低功耗)空闲状态出发,发送Escape Entry序列(LP-11 → LP-10 → LP-00 → LP-01 → LP-00)。
  • 随后可以传输8位数据(或更长的Escape命令)。
  • 退出时发送Escape Exit序列(LP-00 → LP-01 → LP-00 → LP-11)。

Escape模式主要用在命令集传输(如CCP2/E)或带外控制(如触发闪光灯、更改sensor增益而不中断视频流)。我以前在安防摄像机方案里,用Escape模式传送一帧的全局曝光时间配置,省掉了一根额外的I2C线。嗯,这个用法挺妙的。

曾经遇到的一个坑:某sensor的Escape Entry序列需要严格的时序——LP-10保持时间必须≥100ns。我用的主机控制器默认只给了50ns,导致Escape模式根本进不去,花了我两天查D-PHY timing。所以如果你遇到Escape命令不起作用,先抓D-PHY的LP状态切换,看序列是否完整。

帧结构与数据包关系总图

下面这张图是我整理的典型帧传输序列,里面标出了短包、长包和Escape模式的交互位置。你先看看整体流程,再细究每个节点。

MIPI CSI-2 帧结构与数据包关系 CSI-2 帧传输序列 时间→ FS 短包 Line 0 长包 PH + 像素 + PF Line 1 长包 PH + 像素 + PF …… Escape 命令/数据 FE 短包 说明: FS和FE是短包,划定一帧的起止。中间是连续的长包(每行一个),也可夹杂Escape模式(紫色)。 实际传输时Escape模式通常放在帧间隙(如FS之前或FE之后),用于传送控制命令而不影响数据流。 长包内部结构 PH 4 bytes 包数据 像素/元数据 PF (CRC) 2 bytes ECC保护 → PH内部 CRC保护 → 从PH到PF整包 包首 有效载荷 包尾

实际调试中你需要注意的细节

我再说几个实战中碰到的高频问题:

  • 长包字计数错误:如果字计数比实际像素数据少,接收端会认为包提前结束,CRC校验算不对。如果多,接收端会卡在等待数据,直到超时。我之前用FPGA做接收端,每次遇到超时就报错复位整个链路,后来改成按CRC结果决定是否丢弃该行,稳定性好很多。
  • 短包的ECC:短包只有4字节,ECC占6位,可纠正1位错误、检测2位错误。我在一个项目中抓到过ECC不断报错的情况,原因是PCB走线过长导致信号反射,在LP状态下产生了毛刺。嗯,不要忽视短包的ECC状态寄存器,它往往是PHY层问题的先兆。
  • Escape模式的退出条件:要确保Escape Exit序列完成后DLP状态回到LP-11,否则下一个HS请求可能无法开始。我记得有个项目因为GPIO驱动配置错误,导致LP-11保持时间不够,每次Escape退出后链路就进入假死状态。

最后分享一个我个人的习惯:在调试初期,我会强制把sensor配置成「每个长包都带CRC」的模式,即使有些数据手册说可选。因为CRC能告诉我数据完整性是否OK。等链路稳定了,再根据功耗要求决定是否关闭CRC。千万别一上来就图省电把CRC关掉,那时候你连问题是sensor还是PHY都分不清。