第4章 MIPI CSI-2接口驱动:从物理层到DMA引擎

好,咱们今天来啃一块硬骨头——MIPI CSI-2接口驱动。说实话,这玩意儿是摄像头数据进入SoC的第一道关卡,搞不定它,后面ISP处理得再好也是白搭。我在Exynos平台上调过不下十款sensor,每次遇到CSI-2的问题,十有八九都是时序或者协议理解不到位。

这一章,我会从D-PHY物理层讲起,再到CSI-2的包协议,最后落到Exynos的CSIS控制器和DMA配置。你跟着我走一遍,基本就能把这条链路打通了。

4.1 MIPI D-PHY物理层:信号是怎么跑的?

MIPI D-PHY,说白了就是摄像头和SoC之间的物理传输通道。它用的是差分信号——一对线传一个数据bit。为什么用差分?抗干扰能力强啊。我当年在实验室用示波器看单端信号,噪声大得离谱,换成差分立马干净了。

D-PHY有两种工作模式:

  • 高速模式(HS):数据传输时用,电压摆幅小(约200mV),速率高,最高能到2.5Gbps/lane
  • 低功耗模式(LP):控制信号用,电压摆幅大(1.2V),速率低,但省电

这里有个关键点——lane的概念。一条lane就是一对差分线。常见的配置有1-lane、2-lane、4-lane。你想想看,4-lane就是4对线同时传数据,带宽直接翻4倍。Exynos的CSIS控制器最多支持4-lane,我建议你直接用满,除非你的sensor只支持2-lane。

重要参数:D-PHY的速率决定了你能跑多大的分辨率。举个例子,4-lane、每lane 1.5Gbps,总带宽就是6Gbps。去掉协议开销(大概20%),实际可用约4.8Gbps。1080p@60fps的原始数据大概需要3Gbps左右,所以绰绰有余。但如果是4K@60fps,那就得算清楚了。

4.2 CSI-2协议层:长包和短包

物理层搞定信号传输,那数据怎么组织呢?这就轮到CSI-2协议层了。CSI-2定义了两种包:长包和短包。

短包(Short Packet):只有32位数据,用来传控制信息。比如帧开始(FS)、帧结束(FE)、行开始(LS)、行结束(LE)。嗯,这里要注意——短包不传图像数据,只传同步信号。

长包(Long Packet):这才是传图像数据的。结构如下:

  • 包头部(4字节):数据类型 + 虚拟通道 + 字计数
  • 有效数据:图像像素数据
  • 包尾部(4字节):校验和(ECC/CRC)

我遇到过一个问题:sensor输出的数据类型是RAW10,但Exynos CSIS配置成了RAW8。结果图像全是乱的,像打翻的调色盘。查了半天才发现是数据类型没对上。所以,数据类型(Data Type)必须和sensor完全一致,这是血泪教训。

个人技巧:调试CSI-2时,我习惯先用逻辑分析仪抓一下短包。如果FS/FE的时序不对,那后面长包肯定也收不到。先确认短包正常,再去看长包的数据内容。

4.3 三星Exynos MIPI CSIS控制器

Exynos的CSIS(Camera Serial Interface Subsystem)是MIPI CSI-2的硬件控制器。它负责从D-PHY接收数据,解析包协议,然后把图像数据送到内存或者ISP。

CSIS的主要模块:

  • D-PHY接口:直接对接物理层,处理时钟和数据lane
  • 协议解析器:解析短包和长包,提取数据类型、虚拟通道等信息
  • 虚拟通道(VC):支持最多4个虚拟通道,可以同时接收多个sensor的数据
  • DMA引擎:把解析后的数据搬到内存

配置CSIS时,有几个寄存器必须设对:

寄存器 作用 我的建议
MIPI_CSIS_CTRL 使能CSIS和D-PHY 先关再开,避免残留状态
MIPI_CSIS_DPHYCTRL 配置D-PHY速率和lane数 速率要和sensor匹配,别超规格
MIPI_CSIS_ISPCONFIG 设置数据类型和虚拟通道 仔细核对sensor的datasheet
MIPI_CSIS_DMA_CTRL 配置DMA传输模式 建议用连续模式,省CPU

我曾经在Exynos 5433上调试CSIS,发现图像总是缺行。查了三天,最后发现是D-PHY的时钟极性设反了。你想想看,时钟极性反了,数据采样点就错了,能不出问题吗?

避坑指南:配置CSIS时,一定要先确认D-PHY的锁定状态。如果D-PHY没锁定,后面的所有操作都是白费。我习惯在初始化时加一个超时检查——如果500ms内D-PHY还没锁定,就报错并重试。

4.4 DMA引擎配置:数据怎么进内存?

CSIS解析完数据后,得靠DMA把数据搬到内存。Exynos的CSIS内置了DMA引擎,支持两种模式:

  • 单帧模式:每帧数据传完就停,需要CPU重新触发
  • 连续模式:自动循环,帧数据连续写入内存

我个人习惯用连续模式。为什么?省事啊。你配置好DMA的地址和长度,它自己就跑起来了,CPU可以干别的活。但要注意——连续模式下,内存地址要预留足够大,至少能存3-4帧数据,否则新数据会覆盖旧数据。

DMA配置的关键参数:

// 伪代码示例
dma_config.addr = framebuffer_phys;  // 物理地址
dma_config.size = width * height * bpp;  // 一帧大小
dma_config.stride = width * bpp;  // 行跨度
dma_config.mode = DMA_CONTINUOUS;  // 连续模式
dma_config.irq_enable = true;  // 开启帧中断

这里有个坑——地址对齐。Exynos的DMA要求地址按32字节对齐。如果不对齐,DMA会报错或者数据错位。我刚开始没注意,结果图像总是偏移了几个像素,查得我头大。

性能优化:DMA传输时,建议用双缓冲(ping-pong buffer)。一个buffer在DMA写,另一个buffer给ISP读。这样读写不冲突,帧率能提升不少。我在Exynos 9820上实测,双缓冲比单缓冲帧率提升了约15%。

4.5 实战经验:一条完整的CSI-2初始化流程

好,咱们把前面讲的串起来。一条完整的CSI-2初始化流程应该是这样的:

  1. 配置D-PHY:设置lane数、速率、时钟极性
  2. 配置CSIS协议层:设置数据类型、虚拟通道、包格式
  3. 配置DMA:设置内存地址、帧大小、传输模式
  4. 使能CSIS:先使能D-PHY,再使能协议层,最后使能DMA
  5. 启动sensor:通过I2C发送stream on命令
  6. 等待帧中断:收到中断后,检查数据是否正确

我建议你在第6步加一个校验——检查帧大小是否和预期一致。如果帧大小不对,说明有数据丢失,可能是D-PHY速率不够或者DMA配置有误。

嗯,这一章的内容就到这里。CSI-2接口驱动说难不难,说简单也不简单。关键是把物理层、协议层、控制器和DMA这四块吃透。你只要按我讲的流程走一遍,基本不会出大问题。下一章咱们会讲ISP的前端处理,到时候这些数据就要进ISP了。