2、摄像头硬件基础

摄像头驱动开发的第一步,是理解摄像头模组的硬件构成与通信接口。本章将拆解一个典型的嵌入式摄像头模组,从光学组件到电气接口,为后续 V4L2 驱动开发打下硬件认知基础。

2.1 摄像头模组核心组成

一个完整的摄像头模组(Camera Module)通常由以下三大核心部件构成:

组件 功能 关键参数
镜头(Lens) 将外界光线聚焦到传感器感光面 焦距、光圈(F-number)、视场角(FOV)
图像传感器(Sensor) 将光信号转换为电信号(模拟/数字) 分辨率、像素尺寸、帧率、动态范围
图像信号处理器(ISP) 对原始 RAW 数据进行图像处理 去噪、自动白平衡、色彩校正、HDR
驱动视角: 驱动工程师最关注的是 Sensor 和 ISP 的寄存器控制接口(I2C/SPI)以及图像数据输出接口(MIPI CSI / LVDS)。镜头通常由模组厂商固定选型,驱动中只需读取其 EEPROM 参数。

2.1.1 镜头(Lens)

镜头是摄像头模组的“眼睛”。在嵌入式系统中,镜头通常采用定焦或手动调焦设计,少数高端模组会集成 VCM(音圈马达)实现自动对焦。驱动工程师需要关注镜头的 红外截止滤光片(IR-Cut) 和 畸变参数,这些会影响 ISP 的校正算法。

2.1.2 图像传感器(Sensor)

传感器是模组的核心。当前主流嵌入式传感器使用 CMOS 工艺,输出格式包括 RAW(Bayer)、YUV 或 JPEG。传感器通过 I2C 总线接收配置命令(如曝光时间、增益、帧率),并通过 MIPI CSI 或 LVDS 接口输出图像数据。

2.1.3 图像信号处理器(ISP)

ISP 可以集成在传感器内部(SoC Sensor),也可以是独立的芯片(如安霸、海思方案),或者由主控 SoC 的 ISP 硬件模块完成。驱动中需要配置 ISP 的输入格式、输出尺寸、帧率以及各种图像增强参数。

实战要点: 在调试摄像头驱动时,如果图像偏色或噪点严重,首先检查 ISP 的 AWB(自动白平衡)和去噪模块是否被正确初始化,而不是怀疑传感器硬件损坏。

2.2 摄像头模组架构图

下图展示了一个典型嵌入式摄像头模组的内部数据流与通信关系:

摄像头模组内部架构与数据流 镜头 (Lens) 图像传感器 ISP 处理器 主控 SoC 光线 聚焦光 RAW 数据 YUV/JPEG I2C 控制总线 (SCL / SDA) 说明: • 数据流方向:光线 → 传感器 → ISP → 主控 SoC • 控制流方向:主控 SoC 通过 I2C 总线配置传感器和 ISP 寄存器 • 传感器输出 RAW 数据(Bayer 格式),ISP 处理后输出 YUV 或 JPEG

2.3 图像数据接口:MIPI CSI 与 LVDS

传感器与 ISP 或主控 SoC 之间通过高速串行接口传输图像数据。嵌入式领域最常用的两种接口是 MIPI CSI 和 LVDS。

特性 MIPI CSI LVDS
标准组织 MIPI 联盟 IEEE / 各厂商私有
物理层 差分对(D-PHY / C-PHY) 差分对(LVDS)
最大速率 D-PHY 4.5 Gbps / lane 通常 1.0 ~ 3.0 Gbps / lane
典型 Lane 数 1 / 2 / 4 Lane 4 / 8 / 16 对
协议层 CSI-2 / CSI-3 标准协议 各厂商自定义(如 SubLVDS)
适用场景 手机、平板、嵌入式 Linux 工业相机、车载、安防
驱动开发注意: MIPI CSI 接口在 Linux 内核中已有成熟的 V4L2 子设备 框架支持,驱动开发工作量相对较小。LVDS 接口通常需要厂商提供私有驱动或适配层,调试难度更高。

2.3.1 MIPI CSI 数据包格式

MIPI CSI-2 协议将图像数据封装为 长数据包 和 短数据包。驱动开发中需要关注 虚拟通道(Virtual Channel) 和 数据类型(Data Type),以正确解析多路摄像头数据。

// MIPI CSI-2 数据包结构示例
// 短数据包(帧同步)
[ 0x00 | VC | DT=0x00 ]  // 帧开始 (Frame Start)
[ 0x00 | VC | DT=0x01 ]  // 帧结束 (Frame End)

// 长数据包(图像数据)
[ 0x00 | VC | DT=0x2B ]  // RAW10 数据
[ 0x00 | VC | DT=0x2C ]  // RAW12 数据
[ 0x00 | VC | DT=0x1E ]  // YUV420 8-bit

2.4 I2C 控制总线

摄像头模组的所有寄存器配置(曝光、增益、帧率、输出格式)都通过 I2C 总线 完成。I2C 是一种两线制(SCL + SDA)同步串行总线,支持多主多从。

2.4.1 I2C 通信时序

驱动中通过 I2C 读写传感器寄存器的典型流程如下:

  1. 起始条件: SDA 在 SCL 高电平时由高变低。
  2. 发送从机地址: 7 位地址 + R/W 位(0 写 / 1 读)。
  3. 等待 ACK: 从机拉低 SDA 表示应答。
  4. 发送寄存器地址: 16 位或 8 位寄存器偏移。
  5. 发送/接收数据: 每字节后跟 ACK。
  6. 停止条件: SDA 在 SCL 高电平时由低变高。
// Linux 内核 I2C 读写示例(伪代码)
#include <linux/i2c.h>

static int sensor_write_reg(struct i2c_client *client, u16 reg, u8 val)
{
    struct i2c_msg msg;
    u8 buf[3];

    buf[0] = (reg >> 8) & 0xFF;  // 寄存器高字节
    buf[1] = reg & 0xFF;         // 寄存器低字节
    buf[2] = val;                // 写入值

    msg.addr = client->addr;
    msg.flags = 0;               // 写操作
    msg.len = 3;
    msg.buf = buf;

    return i2c_transfer(client->adapter, &msg, 1);
}

static int sensor_read_reg(struct i2c_client *client, u16 reg, u8 *val)
{
    struct i2c_msg msg[2];
    u8 reg_buf[2];

    reg_buf[0] = (reg >> 8) & 0xFF;
    reg_buf[1] = reg & 0xFF;

    msg[0].addr = client->addr;
    msg[0].flags = 0;            // 写寄存器地址
    msg[0].len = 2;
    msg[0].buf = reg_buf;

    msg[1].addr = client->addr;
    msg[1].flags = I2C_M_RD;     // 读数据
    msg[1].len = 1;
    msg[1].buf = val;

    return i2c_transfer(client->adapter, msg, 2);
}

2.4.2 I2C 地址与多摄像头配置

每个 I2C 从设备都有一个唯一的 7 位地址。在驱动中,通常通过设备树(Device Tree)指定传感器的 I2C 地址和挂载的总线编号。

// 设备树中摄像头节点示例
&i2c2 {
    status = "okay";
    clock-frequency = <400000>;  // 400kHz 快速模式

    ov5640: camera@3c {
        compatible = "ovti,ov5640";
        reg = <0x3c>;            // I2C 从机地址
        clocks = <&clks IMX8MM_CLK_CLKO1>;
        reset-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
        powerdown-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;

        port {
            ov5640_ep: endpoint {
                remote-endpoint = <&mipi_csi_ep>;
                data-lanes = <1 2>;  // 使用 2 Lane MIPI
            };
        };
    };
};
实战经验: 在调试 I2C 通信时,如果读写寄存器返回 -EIO 或 -EREMOTEIO,首先检查 I2C 地址是否正确(7 位地址左移 1 位后与设备树对比),其次用示波器测量 SCL/SDA 波形确认时序是否满足传感器要求。

2.5 本章小结

摄像头硬件基础是驱动开发的基石。本章涵盖了:

  • 摄像头模组的三大核心组件:镜头、传感器、ISP
  • 图像数据接口 MIPI CSI 与 LVDS 的差异与选型
  • I2C 控制总线的通信原理与 Linux 驱动实现