2. Sensor驱动基础:I2C/SPI通信协议、Sensor寄存器读写、MIPI CSI-2物理层与协议层解析
在骁龙平台Camera系统中,Sensor驱动是连接硬件与ISP的桥梁。本章将深入剖析Sensor驱动的三大核心基础:I2C/SPI通信协议、Sensor寄存器读写机制以及MIPI CSI-2物理层与协议层。理解这些基础是进行后续ISP调优和驱动开发的前提。
2.1 I2C与SPI通信协议
Camera Sensor通常通过I2C或SPI总线与主控(AP)进行控制指令交互,用于配置寄存器、读取状态等。两者在引脚数、速率、拓扑结构上存在显著差异。
| 特性 | I2C (Inter-Integrated Circuit) | SPI (Serial Peripheral Interface) |
|---|---|---|
| 信号线 | SDA (数据线), SCL (时钟线) | MOSI, MISO, SCLK, CS (片选) |
| 拓扑 | 多主多从,总线式 | 一主多从,主从式 |
| 速率 | 标准模式 100kbps,快速模式 400kbps,高速模式 3.4Mbps | 通常 10Mbps ~ 50Mbps,甚至更高 |
| 通信方式 | 半双工,需应答(ACK) | 全双工,无应答机制 |
| 寻址 | 7位或10位设备地址 | 通过CS片选信号选择从设备 |
| 适用场景 | 寄存器配置、状态读取(低速控制) | 固件下载、高速数据流控制 |
2.1.1 I2C通信时序与寄存器读写
I2C协议以起始条件(SCL高电平时SDA下降沿)开始,以停止条件(SCL高电平时SDA上升沿)结束。每个字节后跟随一个ACK位。Sensor寄存器读写通常采用复合格式:先发送设备地址+写位,再发送寄存器地址,最后发送数据或重新发起起始条件进行读操作。
// I2C 写寄存器示例 (伪代码)
int i2c_write_reg(struct i2c_client *client, uint16_t reg_addr, uint8_t data) {
uint8_t buf[3];
buf[0] = (reg_addr >> 8) & 0xFF; // 高字节地址 (16位地址)
buf[1] = reg_addr & 0xFF; // 低字节地址
buf[2] = data; // 写入数据
return i2c_master_send(client, buf, 3);
}
// I2C 读寄存器示例 (伪代码)
int i2c_read_reg(struct i2c_client *client, uint16_t reg_addr, uint8_t *data) {
uint8_t addr_buf[2];
addr_buf[0] = (reg_addr >> 8) & 0xFF;
addr_buf[1] = reg_addr & 0xFF;
// 先发送寄存器地址
i2c_master_send(client, addr_buf, 2);
// 再读取数据
return i2c_master_recv(client, data, 1);
}
2.1.2 SPI通信时序与寄存器读写
SPI通信通过CS片选信号选中从设备,在SCLK时钟控制下,MOSI和MISO同时传输数据。SPI有四种模式(CPOL和CPHA组合),Sensor通常使用模式0(CPOL=0, CPHA=0)或模式3(CPOL=1, CPHA=1)。
// SPI 写寄存器示例 (伪代码)
int spi_write_reg(struct spi_device *spi, uint16_t reg_addr, uint8_t data) {
uint8_t tx_buf[3];
tx_buf[0] = (reg_addr >> 8) & 0xFF; // 地址高字节
tx_buf[1] = reg_addr & 0xFF; // 地址低字节
tx_buf[2] = data; // 数据
struct spi_transfer t = {
.tx_buf = tx_buf,
.len = 3,
};
return spi_sync_transfer(spi, &t, 1);
}
// SPI 读寄存器示例 (伪代码)
int spi_read_reg(struct spi_device *spi, uint16_t reg_addr, uint8_t *data) {
uint8_t tx_buf[3];
uint8_t rx_buf[3];
tx_buf[0] = (reg_addr >> 8) | 0x80; // 读标志位 (最高位置1)
tx_buf[1] = reg_addr & 0xFF;
tx_buf[2] = 0x00; // 发送任意数据以产生时钟
struct spi_transfer t = {
.tx_buf = tx_buf,
.rx_buf = rx_buf,
.len = 3,
};
spi_sync_transfer(spi, &t, 1);
*data = rx_buf[2]; // 第三个字节为读取的数据
return 0;
}
2.2 MIPI CSI-2物理层与协议层解析
MIPI CSI-2是Camera Sensor与AP之间传输图像数据的主流接口标准。它分为物理层(D-PHY/C-PHY)和协议层(CSI-2)。在骁龙平台上,D-PHY是最常见的物理层实现。
2.2.1 D-PHY物理层详解
D-PHY采用差分信号传输,每个Lane由一对差分线(Dp/Dn)组成。时钟Lane提供DDR(双数据率)时钟,数据Lane在时钟的上升沿和下降沿各传输1位数据。D-PHY支持两种工作模式:
- 高速模式(HS): 用于传输图像数据,差分摆幅约200mV,速率可达80Mbps ~ 4.5Gbps per Lane。
- 低功耗模式(LP): 用于控制信号传输(如帧同步、线同步),单端信号,摆幅约1.2V,速率约10Mbps。
| 参数 | HS模式 | LP模式 |
|---|---|---|
| 信号类型 | 差分 (Dp-Dn) | 单端 (Dp, Dn独立) |
| 电压摆幅 | 200mV (典型) | 1.2V (典型) |
| 数据传输率 | 80 Mbps ~ 4.5 Gbps | ~10 Mbps |
| 功耗 | 高 | 低 |
| 用途 | 图像数据 | 控制/状态信号 |
2.2.2 CSI-2协议层数据包格式
CSI-2协议层定义了两种数据包:短包(Short Packet)和长包(Long Packet)。短包用于传输帧起始(FS)、帧结束(FE)、线起始(LS)等同步信息;长包用于传输像素数据。
2.2.3 虚拟通道与数据交织
CSI-2支持最多4个虚拟通道(Virtual Channel, VC),通过数据标识(DI)字节的高4位区分。这使得多个Sensor或同一Sensor的不同数据流(如RAW、YUV、元数据)可以共享同一MIPI总线,实现数据交织传输。
2.3 Sensor寄存器读写实战
在Linux内核Camera驱动中,Sensor寄存器读写通常通过封装好的I2C/SPI读写函数实现。骁龙平台使用V4L2框架,Sensor驱动需要实现s_power、s_stream、enum_mbus_code、s_fmt等回调函数,其中寄存器配置是核心操作。
// 骁龙平台 Sensor 驱动寄存器读写示例 (基于ov5645)
static int ov5645_write_reg(struct i2c_client *client, u16 reg, u8 val)
{
struct i2c_msg msg;
u8 buf[3];
int ret;
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
buf[2] = val;
msg.addr = client->addr;
msg.flags = 0;
msg.len = 3;
msg.buf = buf;
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret < 0) {
dev_err(&client->dev, "write reg error: %d\n", ret);
return ret;
}
return 0;
}
static int ov5645_read_reg(struct i2c_client *client, u16 reg, u8 *val)
{
struct i2c_msg msg[2];
u8 buf[2];
int ret;
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = 2;
msg[0].buf = buf;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = 1;
msg[1].buf = val;
ret = i2c_transfer(client->adapter, msg, 2);
if (ret < 0) {
dev_err(&client->dev, "read reg error: %d\n", ret);
return ret;
}
return 0;
}