3. Camera Sensor驱动基础
Camera Sensor 驱动是 V4L2 Subdev 体系中最底层的硬件抽象层。开发者必须掌握 Sensor 的物理接口、控制总线以及电源管理时序,才能正确初始化 Sensor 并输出符合 ISP 要求的图像数据。本章围绕这三个核心基础展开。
3.1 Sensor硬件接口:MIPI CSI-2 与 DVP
当前主流 Sensor 与 SoC/ISP 之间的数据传输接口分为两大类:MIPI CSI-2(Camera Serial Interface 2)和 DVP(Digital Video Port)。两者在信号线数量、速率、抗干扰能力和适用场景上有显著差异。
| 对比项 | MIPI CSI-2 | DVP |
|---|---|---|
| 信号类型 | 差分串行(LVDS) | 并行 CMOS 电平 |
| 数据线数量 | 1~4 Lane(每 Lane 2 线) | 8~12 位并行数据线 + 同步信号 |
| 时钟 | DDR 时钟(双边沿采样) | 单端像素时钟 |
| 最大速率 | 每 Lane 可达 2.5 Gbps(DPHY v2.0) | 通常 ≤ 150 MHz 像素时钟 |
| 抗干扰 | 强(差分共模抑制) | 弱(易受 EMI 影响) |
| 线缆/走线 | 柔性排线或同轴,走线少 | 排线宽,走线多 |
| 典型应用 | 手机、平板、车载摄像头 | 低分辨率、低成本、短距离 |
驱动开发提示:MIPI CSI-2 驱动需要配置 DPHY 参数(LP/HS 模式、均衡、摆幅),而 DVP 驱动主要关注像素时钟极性和同步信号极性。在设备树中通过
data-lanes 和 clock-noncontinuous 等属性描述 CSI-2 拓扑。
3.2 Sensor寄存器读写:I2C 与 SPI 控制总线
Sensor 的寄存器配置(曝光、增益、帧率、输出格式等)通过低速控制总线完成。绝大多数 Sensor 使用 I2C,少数高速或高分辨率 Sensor 使用 SPI。驱动开发的核心是封装正确的读写时序。
3.2.1 I2C 读写流程
I2C 是两线制(SCL + SDA)同步串行总线。Sensor 作为从设备,驱动通过主控器(I2C adapter)发起读写事务。标准流程如下:
- START 条件:SCL 高电平时 SDA 由高变低。
- 发送从设备地址 + 写位 (W):7 位地址 + 0。
- 等待 ACK:Sensor 拉低 SDA 确认。
- 发送寄存器地址:16 位或 8 位,取决于 Sensor 规格。
- 等待 ACK。
- 发送数据(写)或 重复 START + 读位(读)。
- STOP 条件:SCL 高电平时 SDA 由低变高。
内核 I2C 读写辅助函数:
// 单字节写
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
// 多字节读(自动处理地址递增)
int regmap_bulk_read(struct regmap *map, unsigned int reg,
void *val, size_t val_count);
// 使用 i2c_smbus 接口(适用于简单 Sensor)
int i2c_smbus_write_byte_data(struct i2c_client *client,
u8 command, u8 value);
int i2c_smbus_read_byte_data(struct i2c_client *client, u8 command);
3.2.2 SPI 读写流程
SPI 是四线制(SCLK、MOSI、MISO、CS)全双工同步总线。Sensor 通常使用 SPI 模式 0(CPOL=0, CPHA=0)或模式 3。读写操作通过 16 位或 24 位命令字完成:
| 位域 | 宽度 | 说明 |
|---|---|---|
| RW | 1 bit | 1=读,0=写 |
| ADDR | 15 bits | 寄存器地址(高位在前) |
| DATA | 8 bits | 写入数据(读时忽略) |
// SPI 读写示例(使用 Linux SPI 框架)
static int sensor_spi_write(struct spi_device *spi, u16 reg, u8 val)
{
u16 cmd = (0 << 15) | (reg & 0x7FFF); // 写命令
u8 tx_buf[3] = { cmd >> 8, cmd & 0xFF, val };
struct spi_transfer t = {
.tx_buf = tx_buf,
.len = 3,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spi_sync(spi, &m);
}
static int sensor_spi_read(struct spi_device *spi, u16 reg, u8 *val)
{
u16 cmd = (1 << 15) | (reg & 0x7FFF); // 读命令
u8 tx_buf[3] = { cmd >> 8, cmd & 0xFF, 0 };
u8 rx_buf[3] = {0};
struct spi_transfer t = {
.tx_buf = tx_buf,
.rx_buf = rx_buf,
.len = 3,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
int ret = spi_sync(spi, &m);
if (ret == 0)
*val = rx_buf[2];
return ret;
}
常见陷阱:部分 Sensor 的 I2C 地址会随 VSYNC 或电源状态变化;SPI 模式下 CS 片选必须在整个事务期间保持低电平,否则 Sensor 会丢弃数据。务必查阅数据手册的时序图。
3.3 Sensor上电时序与复位
Sensor 对电源上电顺序和复位信号有严格的时间要求。错误的时序可能导致 Sensor 无法识别、输出花屏甚至损坏。典型的 Sensor 电源域包括:
- AVDD(模拟电源,通常 2.8V)
- DVDD(数字核心电源,通常 1.2V 或 1.8V)
- IOVDD(I/O 接口电源,通常 1.8V)
3.3.1 标准上电时序步骤
- 拉低 RESET 引脚(确保 Sensor 处于复位状态)。
- 依次使能电源:通常先 AVDD,再 DVDD,最后 IOVDD。间隔至少 100 μs。
- 等待电源稳定:各电源达到标称值后等待 1~10 ms。
- 释放 RESET:拉高 RESET 引脚,保持高电平。
- 等待内部初始化:Sensor 内部 PLL 和寄存器加载需要 5~20 ms。
- 通过 I2C/SPI 写入初始化序列。
3.3.2 驱动中实现上电时序
在 Linux 内核中,Sensor 驱动通常通过 struct regulator 和 struct gpio_desc 控制电源和复位。推荐在 sensor_power_on() 函数中实现完整时序:
static int sensor_power_on(struct device *dev)
{
struct sensor_dev *sensor = dev_get_drvdata(dev);
int ret;
// 1. 拉低复位
gpiod_set_value_cansleep(sensor->reset_gpio, 0);
// 2. 依次使能电源
ret = regulator_enable(sensor->avdd); // AVDD 2.8V
if (ret) return ret;
usleep_range(200, 300); // t0->t1 间隔
ret = regulator_enable(sensor->dvdd); // DVDD 1.2V
if (ret) goto err_dvdd;
usleep_range(200, 300); // t1->t2 间隔
ret = regulator_enable(sensor->iovdd); // IOVDD 1.8V
if (ret) goto err_iovdd;
msleep(5); // t2->t3 电源稳定
// 3. 释放复位
gpiod_set_value_cansleep(sensor->reset_gpio, 1);
msleep(10); // t3->t4 内部初始化
// 4. 写入初始化寄存器序列
ret = sensor_init_regs(sensor);
if (ret) goto err_init;
return 0;
err_init:
regulator_disable(sensor->iovdd);
err_iovdd:
regulator_disable(sensor->dvdd);
err_dvdd:
regulator_disable(sensor->avdd);
return ret;
}
调试技巧:使用
dev_dbg() 打印每个电源使能后的电压值(通过 regulator_get_voltage()),配合示波器或逻辑分析仪验证时序。部分 Sensor 要求 RESET 低电平持续时间 ≥ 1 ms,务必在数据手册中确认。