高通Camera HAL层Sensor驱动调试 - 第3节

3.1 I2C 与 SPI 通信协议对比

在 Sensor 驱动开发中,I2C 和 SPI 是最常用的两种板级通信总线。它们负责承载 Host(AP/ISP)与 Sensor 之间的寄存器读写、数据流控制以及固件下载。理解两者的电气特性、时序差异和适用场景,是正确配置 Sensor 驱动的基础。

对比维度 I2C(Inter-Integrated Circuit) SPI(Serial Peripheral Interface)
信号线数量 2 线:SCL(时钟)、SDA(数据) 4 线:SCLK(时钟)、MOSI、MISO、CS(片选)
通信模式 半双工,主从架构 全双工,主从架构
最大速率 标准模式 100 kHz,快速模式 400 kHz,高速模式 3.4 MHz 通常 10–50 MHz,部分可达 100 MHz
寻址方式 7 位或 10 位设备地址 + 寄存器地址 通过硬件 CS 引脚片选,无设备地址
数据帧结构 起始条件 → 设备地址 + R/W → ACK → 数据字节 → ACK → 停止条件 CS 拉低 → 发送命令/地址 → 数据交换 → CS 拉高
多设备支持 总线挂载多个设备,通过地址区分 每个设备独占 CS 引脚,或通过菊花链
典型应用场景 寄存器配置、参数读取、低功耗控制 高帧率图像数据流、固件批量下载
实战经验: 高通 Camera 平台中,大部分 Sensor 的寄存器读写使用 I2C,而 RAW 数据输出通常走 MIPI CSI。部分高速 Sensor(如全局快门、ToF)会使用 SPI 进行配置或固件更新,此时驱动中需要切换通信句柄。

3.1.1 I2C 读写时序与驱动实现

I2C 的每次传输以 START 条件开始,以 STOP 条件结束。Sensor 寄存器写入通常采用“先写寄存器地址,再写数据”的组合格式。读取时则需要先发送寄存器地址,然后重新发送 START 条件(重复起始)并切换为读方向。

// I2C 写寄存器示例(伪代码)
int sensor_i2c_write(struct i2c_client *client, uint16_t reg, uint8_t val) {
    uint8_t buf[3];
    buf[0] = (reg >> 8) & 0xFF;   // 寄存器高字节
    buf[1] = reg & 0xFF;          // 寄存器低字节
    buf[2] = val;                 // 写入数据
    return i2c_master_send(client, buf, 3);
}

// I2C 读寄存器示例(伪代码)
int sensor_i2c_read(struct i2c_client *client, uint16_t reg, uint8_t *val) {
    uint8_t addr_buf[2];
    addr_buf[0] = (reg >> 8) & 0xFF;
    addr_buf[1] = reg & 0xFF;
    i2c_master_send(client, addr_buf, 2);   // 发送寄存器地址
    return i2c_master_recv(client, val, 1); // 接收数据
}
关键点: 高通平台 I2C 驱动基于 Linux I2C 子系统,Sensor 驱动通过 i2c_transfer 或 i2c_smbus_read/write 系列函数操作。务必确认 Sensor 的寄存器地址宽度(8 位 / 16 位)以及是否支持自动地址递增。

3.1.2 SPI 读写时序与驱动实现

SPI 通信由主设备控制时钟并驱动 CS 片选。Sensor 作为从设备,在 CS 拉低期间接收命令并返回数据。SPI 模式(CPOL、CPHA)必须与 Sensor 数据手册严格匹配,否则通信将完全失败。

// SPI 写寄存器示例(伪代码)
int sensor_spi_write(struct spi_device *spi, uint16_t reg, uint8_t val) {
    uint8_t tx_buf[3];
    tx_buf[0] = 0x02;                // 写命令(由 Sensor 定义)
    tx_buf[1] = reg & 0xFF;          // 寄存器地址
    tx_buf[2] = val;                 // 数据
    struct spi_transfer t = {
        .tx_buf = tx_buf,
        .len = 3,
    };
    return spi_sync_transfer(spi, &t, 1);
}

// SPI 读寄存器示例(伪代码)
int sensor_spi_read(struct spi_device *spi, uint16_t reg, uint8_t *val) {
    uint8_t tx_buf[2] = {0x03, reg & 0xFF}; // 读命令 + 地址
    uint8_t rx_buf[2] = {0};
    struct spi_transfer t = {
        .tx_buf = tx_buf,
        .rx_buf = rx_buf,
        .len = 2,
    };
    spi_sync_transfer(spi, &t, 1);
    *val = rx_buf[1];  // 第二个字节为读取的数据
    return 0;
}
常见陷阱: SPI 模式下,Sensor 可能要求 CS 在连续读写之间保持低电平(连续传输模式),也可能要求每字节 CS 拉高一次。高通平台 SPI 控制器支持 cs_change 标志位控制片选行为,务必根据 Sensor 手册配置。

3.2 Sensor 寄存器读写原理

Sensor 内部通过寄存器映射表控制曝光、增益、帧率、输出格式、测试图案等所有行为。驱动层的核心任务就是将上层下发的参数(如曝光时间、模拟增益)转换为寄存器地址和数值,并通过 I2C/SPI 总线写入 Sensor。

3.2.1 寄存器地址空间与分组

不同 Sensor 的寄存器地址空间差异较大,常见的有 8 位地址(256 字节)和 16 位地址(64 KB)。高通 Camera HAL 层通过 sensor_lib_t 结构体中的 reg_addr_type 字段来区分。

地址宽度 地址范围 典型 Sensor 示例 驱动配置
8 位 0x00 – 0xFF OV5640、GC2053 reg_addr_type = 0
16 位 0x0000 – 0xFFFF IMX298、IMX586 reg_addr_type = 1
16 位 + 页选 多页,每页 256 字节 AR1335、某些安森美 Sensor 需额外写页选寄存器

3.2.2 寄存器读写流程

一次完整的 Sensor 寄存器写入流程包含以下步骤:

  1. 构造寄存器表: 将曝光、增益、帧长等参数转换为 {reg_addr, reg_value} 键值对。
  2. 分组与排序: 按寄存器地址递增排序,合并连续地址的写入(批量写入优化)。
  3. 页选处理: 如果跨页,先写入页选寄存器切换页面。
  4. 总线写入: 调用 I2C/SPI 驱动接口发送数据。
  5. 校验(可选): 回读关键寄存器确认写入成功。
性能优化: 高通平台支持 i2c_msgs 批量传输,将多个寄存器写入合并为一次 I2C 事务,可显著降低帧切换延迟。在 sensor_setting 中尽量使用 reg_setting 数组一次性下发。

3.3 I2C/SPI 通信架构图

下图展示了高通 Camera 系统中,HAL 层、Sensor 驱动库、I2C/SPI 控制器与 Sensor 硬件之间的分层通信架构。

高通 Camera I2C/SPI 通信分层架构 Camera HAL / 上层调用 Sensor 驱动库 (sensor_lib) I2C 控制器 (qup_i2c) SPI 控制器 (spi_qsd) I2C 物理总线 (SCL/SDA) SPI 物理总线 (SCLK/MOSI/MISO/CS) Sensor 硬件 (寄存器阵列) 说明:HAL 层通过 sensor_lib 调用 I2C/SPI 控制器驱动,最终在物理总线上完成寄存器读写

3.4 寄存器读写实战要点

  • 地址对齐: 16 位地址 Sensor 在 I2C 传输时,高字节在前(Big Endian),低字节在后。SPI 则通常先发命令字节,再发地址字节。
  • 批量写入优化: 对于连续地址的寄存器(如增益、曝光的一组配置),使用 I2C 的“重复起始”或 SPI 的“连续传输模式”可减少总线开销。
  • 延迟与等待: 某些寄存器写入后需要等待若干帧(Frame)或若干毫秒才能生效,驱动中应加入 msleep 或帧同步等待。
  • 调试手段: 使用高通 i2cget/i2cset 工具或 spidev_test 在用户空间验证寄存器读写是否正确,再集成到驱动中。
避坑指南: 部分 Sensor 的寄存器是“只写”或“只读”的,驱动中如果错误地回读只写寄存器,可能导致总线挂死。务必仔细阅读 Sensor 数据手册的寄存器描述表。

3.5 本章小结

I2C 和 SPI 是 Sensor 驱动与硬件之间的通信桥梁。掌握两者的时序差异、驱动接口和寄存器读写原理,是后续进行 Sensor 上电序列、流控、曝光控制等调试工作的前提。在高通平台上,I2C 用于低速配置,SPI 用于高速批量传输,驱动开发者需要根据 Sensor 规格书正确选择总线并配置控制器参数。