4、摄像头硬件接口基础:MIPI CSI-2协议概述、D-PHY物理层、摄像头模组(OV5640/IMX219)数据手册解读

好,咱们进入摄像头驱动开发的第一道门槛——硬件接口。说实话,很多做驱动的兄弟一上来就撸代码,结果板子调不通,最后发现是MIPI的时序配错了,或者干脆物理层就没起来。这活儿我干过,挺折腾的。

这一章,咱们把MIPI CSI-2、D-PHY物理层,还有两个常用模组OV5640和IMX219的数据手册,掰开揉碎了讲清楚。你想想看,搞懂这些,后面写驱动心里才有底。

4.1 MIPI CSI-2协议概述

MIPI CSI-2,全称是Camera Serial Interface 2。说白了,就是摄像头和处理器之间传图像数据的标准协议。为什么要有它?因为传统的并口摄像头(比如DVP)线太多,高分辨率下干扰大,传不远。CSI-2用差分串行传输,线少、抗干扰、速率高。

我个人习惯把CSI-2协议分成三层来看:

  • 应用层:定义图像格式,比如RAW8、RAW10、YUV422、JPEG。你从摄像头拿到的数据长什么样,这层说了算。
  • 协议层:定义数据怎么打包、怎么分包。比如一帧图像怎么拆成多个包,每个包带什么头。
  • 物理层:就是D-PHY,负责把0和1变成差分信号在线上跑。咱们下一节细说。

CSI-2的数据传输,核心是数据包。每个包分两种:

  • 长包:传图像数据。结构是:包头(32位,含数据类型、虚拟通道、字计数)+ 数据负载 + 包尾(16位CRC校验)。
  • 短包:传控制信息,比如帧同步、行同步。只有32位包头,没有数据负载。

重点:数据类型(Data Type, DT)字段决定了这包数据是RAW10还是YUV422。比如DT=0x2B表示RAW10,DT=0x1E表示YUV422 8位。驱动里解析这个字段,才能正确处理数据。

我在项目中遇到过一个问题:摄像头输出的是RAW10,但驱动按RAW8去解析,结果图像全是条纹。查了半天,才发现是数据类型配错了。嗯,这种坑踩一次就记住了。

4.2 D-PHY物理层

D-PHY是MIPI联盟定义的物理层标准。它用差分信号传输,一对线叫一个Lane。CSI-2最少需要1个Clock Lane(时钟通道)和1个Data Lane(数据通道),最多可以到4个Data Lane。

D-PHY有两种工作模式:

  • 高速模式(HS):差分信号,电压摆幅约200mV,速率从80 Mbps到2.5 Gbps per Lane。传图像数据时用这个模式。
  • 低功耗模式(LP):单端信号,电压摆幅1.2V,速率只有10 Mbps左右。用于控制信号,比如进入省电状态。

这里有个关键点:D-PHY的时序。从LP模式切换到HS模式,需要经过一个叫"Escape Mode"的序列。具体来说:

LP->HS切换序列:
1. LP-11 (空闲状态)
2. LP-01 (准备)
3. LP-00 (桥接)
4. HS-0 (高速模式开始)

这个序列如果时序不对,物理层就起不来。我曾经在QNX上调试一个IMX219模组,发现D-PHY一直报错,用示波器一抓,发现LP-00的保持时间不够。调整了SoC的D-PHY配置寄存器,问题解决。

注意:D-PHY的时钟通道必须一直运行,数据通道可以按需开关。驱动里要确保时钟通道的PLL锁定后,再使能数据通道。否则数据会丢包。

4.3 摄像头模组数据手册解读

拿到一个摄像头模组,第一件事不是上电,而是读数据手册。我见过有人不看手册直接抄代码,结果摄像头死活不出图。咱们以OV5640和IMX219为例,讲讲怎么看手册。

4.3.1 OV5640数据手册要点

OV5640是OmniVision的500万像素传感器,支持RAW10和JPEG输出。手册里我最关注这几个部分:

  • 寄存器映射:OV5640的寄存器地址是16位,数据是8位。比如寄存器0x3008是系统控制,写0x80可以软复位。
  • PLL配置:手册里有个PLL计算表,输入主时钟(XVCLK)和输出像素时钟的关系。公式是:VCO = XVCLK * M / N,然后分频得到像素时钟。
  • 输出格式设置:寄存器0x4300控制输出格式。比如设成0x6F表示RAW10,设成0x30表示YUV422。

我的习惯:拿到手册先看"Register Table"章节,找到系统控制、PLL、输出格式这三个关键寄存器组。其他寄存器可以后面再细看。

举个例子,配置OV5640输出640x480 RAW10的步骤:

1. 软复位:写0x80到0x3008,等待10ms
2. 配置PLL:设置0x3034~0x3036,让像素时钟为24MHz
3. 设置分辨率:写0x3808=0x0280 (640),0x3809=0x01E0 (480)
4. 设置输出格式:写0x4300=0x6F (RAW10)
5. 启动输出:写0x3008=0x02

我记得第一次调OV5640时,忘了设置输出格式,默认是YUV422,结果ISP那边一直报格式错误。后来加上格式配置,图像就出来了。

4.3.2 IMX219数据手册要点

IMX219是Sony的800万像素传感器,常用于树莓派Camera v2。它的手册比OV5640更详细,但结构类似。我重点看:

  • 模拟增益和数字增益:IMX219的增益控制很精细。模拟增益寄存器0x0157,范围0x00~0xFF,对应1x到16x增益。数字增益寄存器0x0158~0x0159,是12位值。
  • 曝光控制:曝光时间由寄存器0x015A~0x015B控制,单位是行时间。比如设成0x03E8(1000行),帧率30fps时,曝光时间约33ms。
  • MIPI配置:IMX219支持2-lane MIPI。寄存器0x0112控制lane数,0x0113控制时钟频率。
参数 OV5640 IMX219
分辨率 500万 (2592x1944) 800万 (3280x2464)
输出格式 RAW10, JPEG, YUV422 RAW10, RAW8
MIPI Lane数 1~4 Lane 2 Lane
主时钟 6~27 MHz 6~27 MHz
寄存器地址 16位 16位

IMX219有个坑:它的寄存器写入需要先解锁。寄存器0x0100是模式选择,写0x01进入流模式。但写之前必须确保0x0103=0x01(解锁)。我刚开始没注意,写0x0100没反应,查了半天手册才发现这个解锁步骤。

避坑指南:IMX219的寄存器0x0103是"Register Bank Select",默认是0x00。写0x01才能访问所有寄存器。很多驱动初始化时忘了这步,导致配置无效。

4.4 实战:从数据手册提取关键参数

好了,理论讲完了,咱们来点实际的。假设你要在QNX上驱动一个OV5640模组,你会怎么从手册里提取参数?

我个人习惯按这个顺序来:

  1. 确定MIPI配置:手册里找"Output Interface"章节,看支持几Lane、最大速率。OV5640支持4 Lane,每Lane最高800 Mbps。
  2. 计算像素时钟:根据分辨率和帧率,算出需要的像素时钟。比如640x480@30fps,像素时钟约18.4 MHz。
  3. 配置PLL:根据输入时钟(比如24MHz)和需要的像素时钟,算PLL的M/N分频系数。
  4. 设置输出格式:找到格式控制寄存器,设成RAW10或YUV422。
  5. 初始化序列:手册里通常有推荐的初始化序列,直接抄过来用。

举个例子,OV5640的PLL配置计算:

输入时钟:24 MHz
目标像素时钟:24 MHz
PLL配置:
  M = 1 (倍频系数)
  N = 1 (分频系数)
  VCO = 24 * 1 / 1 = 24 MHz
  像素时钟 = VCO / 1 = 24 MHz
寄存器设置:
  0x3034 = 0x1A (使能PLL)
  0x3035 = 0x21 (M=1, N=1)
  0x3036 = 0x46 (分频系数)

嗯,这里要注意:不同版本的OV5640,PLL寄存器地址可能不一样。我遇到过手册版本v1.0和v2.0,寄存器0x3035的定义就变了。所以一定要看对应版本的手册。

最后,总结一下这一章的核心:

  • CSI-2协议分三层:应用层、协议层、物理层。驱动主要关注协议层的数据包解析。
  • D-PHY的LP/HS切换时序很关键,错了物理层起不来。
  • 读数据手册时,先找系统控制、PLL、输出格式这三个关键寄存器组。
  • IMX219需要先解锁寄存器,OV5640要注意PLL配置的版本差异。

下一章,咱们开始写真正的QNX摄像头驱动。到时候,这些硬件知识都会用上。