V4L2摄像头驱动开发与MIPI采集JPEG编码 - 第3节

3.1 MIPI CSI-2 协议分层与虚拟通道概念

MIPI CSI-2(Camera Serial Interface 2)是移动与嵌入式摄像头领域最广泛使用的串行接口协议。在 V4L2 驱动中,理解 CSI-2 的虚拟通道(Virtual Channel, VC)与数据类型(Data Type, DT)是正确解析摄像头数据流的基础。

CSI-2 协议采用分层架构,从物理层到应用层依次为:

  • 物理层(PHY):D-PHY 或 C-PHY,负责差分信号传输。
  • 协议层(Protocol Layer):包含数据包格式、虚拟通道、数据类型标识。
  • 应用层(Application Layer):定义像素格式(RAW、YUV、JPEG)与帧结构。

虚拟通道(VC)是协议层的关键机制,允许在单条 MIPI 数据通道(Lane)上复用最多 4 个独立的逻辑数据流。每个 VC 使用 2 位标识符(VC ID),范围 0~3。

核心要点: 虚拟通道使得多摄像头(如双摄、三摄)或同一摄像头输出多种格式(RAW + YUV + JPEG)时,只需共享同一物理链路,由接收端(SoC CSI 控制器)根据 VC ID 解复用。

3.1.1 虚拟通道与数据类型在包结构中的位置

CSI-2 数据包分为长包(Long Packet)和短包(Short Packet)。长包用于传输像素数据,其包头(Packet Header)包含关键字段:

字段 位宽 说明
VC (Virtual Channel) 2 bits 虚拟通道标识,0~3
DT (Data Type) 6 bits 数据类型标识,0x00~0x3F
WC (Word Count) 16 bits 数据负载字节数(长包)
ECC (Error Correction Code) 8 bits 包头纠错码

VC 和 DT 共同决定了接收端如何解析后续数据负载。VC 决定数据流归属,DT 决定数据格式与处理方式。

MIPI CSI-2 长包包头结构 VC (2 bits) 虚拟通道 DT (6 bits) 数据类型 WC (16 bits) 字计数 ECC (8 bits) 纠错码 数据负载 (Payload) RAW / YUV / JPEG 像素数据 VC + DT 决定数据流归属与格式解析方式

3.2 数据类型 ID 详解

数据类型(Data Type, DT)是一个 6 位字段,取值范围 0x00~0x3F。CSI-2 规范将 DT 分为多个类别,涵盖帧同步、行同步、图像数据、嵌入式数据等。对于摄像头驱动开发,最常关注的是图像数据 DT。

3.2.1 图像数据类型分类

DT 值 格式名称 说明 典型应用
0x1E YUV420 8-bit YUV 4:2:0 子采样,每像素 12 bits 视频通话、预览
0x1F YUV420 10-bit YUV 4:2:0 10-bit 深度 高动态范围视频
0x20 YUV422 8-bit YUV 4:2:2 子采样,每像素 16 bits 高清视频采集
0x21 YUV422 10-bit YUV 4:2:2 10-bit 深度 专业摄像
0x22~0x27 RGB 系列 RGB888、RGB666、RGB565 等 显示直连
0x28 RAW6 6-bit Bayer RAW 低端传感器
0x29 RAW7 7-bit Bayer RAW 特殊传感器
0x2A RAW8 8-bit Bayer RAW 常见手机传感器
0x2B RAW10 10-bit Bayer RAW 高画质拍照
0x2C RAW12 12-bit Bayer RAW 专业相机
0x2D RAW14 14-bit Bayer RAW 工业/医疗
0x2E RAW16 16-bit Bayer RAW 天文/科研
0x2F RAW20 20-bit Bayer RAW 特殊应用
0x30 JPEG JPEG 压缩图像数据 拍照、编码输出
开发提示: 在 V4L2 驱动中,CSI 接收端(如 Cadence、Synopsys、NXP 等 IP)通常会在寄存器中记录接收到的 DT 值。驱动通过读取 DT 寄存器,自动配置 DMA 引擎的像素格式,无需传感器额外通知。但若传感器支持 JPEG 编码输出(DT=0x30),驱动必须特殊处理,因为 JPEG 是变长数据,不遵循固定行宽。

3.3 RAW / YUV / JPEG 数据标识与链路处理

在 MIPI CSI-2 链路上,RAW、YUV、JPEG 三种数据类型的标识方式不同,直接影响接收端的数据处理流程。

3.3.1 RAW 数据标识

RAW 数据是传感器直接输出的未处理 Bayer 格式。CSI-2 协议中,RAW 数据使用 DT 0x28~0x2F 标识。RAW 数据以行为单位传输,每行像素数由传感器分辨率决定。接收端需要根据 DT 值确定每个像素的位宽,并正确打包到内存中。

  • RAW8 (0x2A):每个像素 1 字节,内存对齐简单。
  • RAW10 (0x2B):每个像素 10 bits,4 个像素打包为 5 字节(40 bits)。
  • RAW12 (0x2C):每个像素 12 bits,2 个像素打包为 3 字节(24 bits)。

3.3.2 YUV 数据标识

YUV 数据是经过颜色处理后的格式,常见于视频流。CSI-2 使用 DT 0x1E~0x21 标识 YUV 数据。YUV 数据同样以行为单位,但每个像素包含亮度(Y)和色度(U/V)分量。

  • YUV420:每 4 个 Y 像素共享一组 UV,节省带宽。
  • YUV422:每 2 个 Y 像素共享一组 UV,质量更高。

3.3.3 JPEG 数据标识

JPEG 数据是经过压缩的图像数据,与 RAW/YUV 有本质区别:

  • DT 值:0x30 专门用于 JPEG。
  • 数据特性:变长数据,一帧 JPEG 图像可能包含多个数据包,每个包大小不固定。
  • 帧结构:JPEG 数据使用帧起始(Frame Start)和帧结束(Frame End)短包界定,但行结构不固定。
  • 接收端处理:CSI 控制器通常将 JPEG 数据视为连续字节流,直接 DMA 到内存缓冲区,由软件解码。
常见陷阱: 某些传感器在 JPEG 模式下仍会发送行同步短包(Line Start/End),但行长度可能不一致。驱动不能假设 JPEG 数据按固定行宽对齐,必须根据帧起始/结束包来界定一帧数据。否则可能导致内存越界或图像撕裂。
CSI-2 链路数据标识与处理流程 图像传感器 RAW/YUV/JPEG MIPI CSI-2 VC + DT 标识 CSI 接收器 解析 VC/DT RAW 打包 YUV 转换 JPEG 直通 数据标识决定处理路径 RAW → 按位宽打包到内存 | YUV → 颜色空间转换 | JPEG → 直接 DMA 到缓冲区

3.4 虚拟通道与数据类型在 V4L2 驱动中的映射

在 Linux V4L2 子系统中,CSI-2 的 VC 和 DT 信息通过 v4l2_subdev 和 media_pad 框架传递。驱动开发者需要关注以下映射关系:

3.4.1 VC 到 V4L2 视频节点的映射

每个虚拟通道通常对应一个独立的 V4L2 视频设备节点(/dev/videoX)。例如:

  • VC0 → /dev/video0(主摄像头 RAW 流)
  • VC1 → /dev/video1(主摄像头 YUV 流)
  • VC2 → /dev/video2(副摄像头 RAW 流)

驱动在 probe 阶段根据设备树或传感器能力,为每个 VC 注册一个 video_device。

3.4.2 DT 到 V4L2 像素格式的映射

CSI 接收驱动需要将 DT 值转换为 V4L2 定义的 v4l2_pix_format 的 pixelformat 字段。常见映射如下:

CSI-2 DT V4L2 Pixel Format 描述
0x2A (RAW8) V4L2_PIX_FMT_SRGGB8 8-bit Bayer RAW (RGGB)
0x2B (RAW10) V4L2_PIX_FMT_SRGGB10 10-bit Bayer RAW
0x1E (YUV420 8-bit) V4L2_PIX_FMT_NV12 YUV 4:2:0 半平面
0x20 (YUV422 8-bit) V4L2_PIX_FMT_UYVY YUV 4:2:2 交错
0x30 (JPEG) V4L2_PIX_FMT_JPEG JPEG 压缩数据

3.4.3 驱动代码示例:解析 DT 并配置 DMA

/* CSI 接收中断处理函数中解析 DT */
static irqreturn_t csi_rx_irq_handler(int irq, void *dev_id)
{
    struct csi_rx_device *csi = dev_id;
    u32 phdr = readl(csi->base + CSI_RX_PHDR);  /* 读取包头寄存器 */
    u8 vc = (phdr >> 30) & 0x3;                 /* 提取 VC */
    u8 dt = (phdr >> 24) & 0x3F;                /* 提取 DT */
    u16 wc = phdr & 0xFFFF;                      /* 提取 WC */

    /* 根据 DT 选择 DMA 配置 */
    switch (dt) {
    case 0x2A: /* RAW8 */
        csi->fmt = V4L2_PIX_FMT_SRGGB8;
        csi->bpp = 1;  /* bytes per pixel */
        break;
    case 0x2B: /* RAW10 */
        csi->fmt = V4L2_PIX_FMT_SRGGB10;
        csi->bpp = 2;  /* 实际 10 bits,但内存对齐为 2 字节 */
        break;
    case 0x30: /* JPEG */
        csi->fmt = V4L2_PIX_FMT_JPEG;
        csi->bpp = 0;  /* 变长,不按像素对齐 */
        break;
    default:
        dev_err(csi->dev, "Unsupported DT: 0x%02x\n", dt);
        return IRQ_HANDLED;
    }

    /* 配置 DMA 引擎 */
    csi_configure_dma(csi, vc, csi->fmt, wc);
    return IRQ_HANDLED;
}
调试技巧: 在开发初期,可以在 CSI 接收中断中打印每个包的 VC 和 DT 值,验证传感器是否按预期发送数据。使用 dev_dbg() 输出到内核日志,配合 dmesg 观察。如果发现 DT 值异常(如 RAW10 传感器发送了 RAW8 的 DT),检查传感器寄存器配置或硬件连接。

3.5 多虚拟通道场景实战

现代摄像头模组(如双摄、三摄模组)常通过单条 MIPI CSI-2 链路传输多路数据。以下是一个典型的多 VC 场景:

  • VC0:主摄像头 RAW10(DT=0x2B),用于拍照。
  • VC1:主摄像头 YUV420(DT=0x1E),用于预览。
  • VC2:副摄像头 RAW8(DT=0x2A),用于景深计算。

接收端 CSI 控制器根据 VC ID 将数据路由到不同的 DMA 通道,每个通道对应一个 V4L2 视频节点。驱动需要为每个 VC 维护独立的缓冲区队列和格式配置。

多虚拟通道数据流解复用 摄像头 模组 VC0/VC1/VC2 MIPI CSI-2 解复用 VC 解析 VC0: RAW10 /dev/video0 VC1: YUV420 /dev/video1 VC2: RAW8 /dev/video2

3.6 本章小结

  • 虚拟通道(VC):2 位标识,支持 4 个独立数据流复用同一条 MIPI 链路。
  • 数据类型(DT):6 位标识,定义数据格式(RAW、YUV、JPEG 等)。
  • RAW 数据:DT 0x28~0x2F,按位宽打包,以行为单位。
  • YUV 数据:DT 0x1E~0x21,包含亮度与色度分量,支持 420/422 子采样。
  • JPEG 数据:DT 0x30,变长压缩数据,接收端需按帧处理,不能假设固定行宽。
  • V4L2 映射:VC 对应 video 节点,DT 对应 pixelformat,驱动需在中断中解析并配置 DMA。