2、摄像头硬件基础
摄像头驱动开发的第一步,是理解摄像头模组的硬件构成与通信接口。本章将拆解一个典型的嵌入式摄像头模组,从光学组件到电气接口,为后续 V4L2 驱动开发打下硬件认知基础。
2.1 摄像头模组核心组成
一个完整的摄像头模组(Camera Module)通常由以下三大核心部件构成:
| 组件 | 功能 | 关键参数 |
|---|---|---|
| 镜头(Lens) | 将外界光线聚焦到传感器感光面 | 焦距、光圈(F-number)、视场角(FOV) |
| 图像传感器(Sensor) | 将光信号转换为电信号(模拟/数字) | 分辨率、像素尺寸、帧率、动态范围 |
| 图像信号处理器(ISP) | 对原始 RAW 数据进行图像处理 | 去噪、自动白平衡、色彩校正、HDR |
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 的输入格式、输出尺寸、帧率以及各种图像增强参数。
2.2 摄像头模组架构图
下图展示了一个典型嵌入式摄像头模组的内部数据流与通信关系:
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 | 工业相机、车载、安防 |
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 读写传感器寄存器的典型流程如下:
- 起始条件: SDA 在 SCL 高电平时由高变低。
- 发送从机地址: 7 位地址 + R/W 位(0 写 / 1 读)。
- 等待 ACK: 从机拉低 SDA 表示应答。
- 发送寄存器地址: 16 位或 8 位寄存器偏移。
- 发送/接收数据: 每字节后跟 ACK。
- 停止条件: 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
};
};
};
};
2.5 本章小结
摄像头硬件基础是驱动开发的基石。本章涵盖了:
- 摄像头模组的三大核心组件:镜头、传感器、ISP
- 图像数据接口 MIPI CSI 与 LVDS 的差异与选型
- I2C 控制总线的通信原理与 Linux 驱动实现