← 返回课程

Sensor_Bringup

Camera全栈开发(Qcom Camx) 第 21 / 30 节

第 19 章:Sensor Bringup 实战 ⭐⭐⭐


本章导读

Sensor Bringup = 让一颗新的 Sensor 在你的主板上正常工作。这是 Camera 工程中最容易出现问题的环节。

本章以 xxx+ CAMSS 框架 为基准,完整覆盖 bringup 全过程——从硬件 schematic 审查、到 sensor XML 配置、kernel dtsi、上电序列、到调试方法。


19.1 Bringup 的前置准备

在开始配置之前,先要做两件事:

1. 审查硬件原理图(Schematic)

从硬件工程师拿到原理图,确认以下信息:

① 电源(regulator)
   - sensor 的 VANA/VIO/VDIG 分别接到 PMIC 的哪一路输出
   - 电压值是多少(例如 2.8V / 1.8V / 1.05V)
   - 最大电流是多少

② GPIO
   - MCLK 接到 SoC 的哪个 tlmm 引脚
   - RESET 接到哪个 tlmm 引脚
   - 是否有 STANDBY 引脚、接到哪里

③ CSI(MIPI)
   - sensor 的 MIPI 数据线接到哪个 CSIPHY
   - 使用了几条 Data Lane
   - 是否支持 D-PHY 还是 C-PHY

④ I2C(CCI)
   - sensor 的 I2C 从机地址(7bit)
   - 接在哪条 CCI 总线上

2. 从 sensor 厂商拿到 Datasheet

必须确认的参数:
  ① power up/down 时序(VANA → VIO → MCLK → RESET 的顺序和时间)
  ② CHIP_ID(用于 probe 阶段确认 sensor 在线)
  ③ 支持的分辨率和帧率
  ④ MIPI 输出格式(RAW10/RAW12、Lane 数量、速率)
  ⑤ I2C 寄存器地址(曝光/增益/帧率/测试模式等)
  ⑥ esettle time 参数(用于计算 settleTimeNs)

19.2 Bringup 需要修改的文件总览

一次完整的 sensor bringup 需要修改以下几类文件(CAMSS 框架):

文件类型 路径 修改什么
Sensor XML chi-cdk/oem/qcom/sensor/<sensor_name>/ sensor 的 slave 信息、电源时序、分辨率、寄存器地址等
Module XML chi-cdk/oem/qcom/module/ 模组信息(关联 sensor/actuator/eeprom)
Kernel DTSI camera-devicetree/\*.dtsi 电源/GPIO/CSI 的硬件连接
Sub-module XML chi-cdk/oem/qcom/actuator/eeprom/ actuator/EEPROM 配置
Build Makefile vendor/qcom/proprietary/common/config/device-vendor.mk 编译打包 BIN 文件

BIN 文件生成:Sensor XML 配置会在编译时自动生成 .bin 文件,push 到设备 /vendor/lib64/camera/ 目录下。


19.3 Sensor XML 配置(chi-cdk 层)

每个 sensor 有一个关联的 XML 文件,定义了 sensor 的所有软件配置参数。

19.3.1 完整的 sensor XML 结构

<!-- chi-cdk/oem/qcom/sensor/<sensor_name>/<sensor_name>_sensor.xml -->
<sensorDriverData>
    <!-- ① slaveInfo: sensor 的基本信息 -->
    <slaveInfo>
        <sensorName>imx586</sensorName>            <!-- sensor 名称 -->
        <slaveAddress>0x34</slaveAddress>           <!-- I2C 从机地址 -->

        <regAddrType>2</regAddrType>                <!-- 寄存器地址宽度(字节): 1/2/3/4 -->
        <regDataType>2</regDataType>                <!-- 寄存器数据宽度(字节): 1/2/3/4 -->

        <sensorIdRegAddr>0x22</sensorIdRegAddr>    <!-- CHIP_ID 寄存器的地址 -->
        <sensorId>0x0586</sensorId>                 <!-- CHIP_ID 期望值 -->
        <sensorIdMask>0xFFFFFFFF</sensorIdMask>     <!-- CHIP_ID 掩码(只比较特定位) -->

        <i2cFrequencyMode>FAST</i2cFrequencyMode>   <!-- I2C 速率:
                                                         STANDARD(100kHz)
                                                         FAST(400kHz)
                                                         FAST_PLUS(1MHz)
                                                         CUSTOM(dtsi 中自定义) -->
    </slaveInfo>

    <!-- ② powerUpSequence / powerDownSequence: 电源时序 -->
    <powerUpSequence>
        <!-- 每个 powerSetting 是一项操作,从上到下依次执行 -->
        <powerSetting>
            <configType>MCLK</configType>           <!-- 操作类型 -->
            <configValue>19200000</configValue>     <!-- MCLK 频率(Hz) -->
            <delayMs>1</delayMs>                    <!-- 操作后的等待时间(ms) -->
        </powerSetting>
        <powerSetting>
            <configType>VANA</configType>
            <configValue>2800000</configValue>       <!-- 模拟电压 2.8V -->
            <delayMs>1</delayMs>
        </powerSetting>
        <powerSetting>
            <configType>VIO</configType>             <!-- IO 电源 -->
            <configValue>1800000</configValue>
            <delayMs>1</delayMs>
        </powerSetting>
        <powerSetting>
            <configType>RESET</configType>           <!-- 拉高 RESET >
            <configValue>0</configValue>             <!-- 0 = 拉高 -->
            <delayMs>5</delayMs>                    <!-- sensor 内部初始化时间 -->
        </powerSetting>
    </powerUpSequence>

    <powerDownSequence>
        <powerSetting>
            <configType>RESET</configType>           <!-- 拉低 RESET -->
            <configValue>0</configValue>
            <delayMs>0</delayMs>
        </powerSetting>
        <powerSetting>
            <configType>VIO</configType>
            <delayMs>0</delayMs>
        </powerSetting>
        <powerSetting>
            <configType>VANA</configType>
            <delayMs>0</delayMs>
        </powerSetting>
    </powerDownSequence>

    <!-- ③ regAddrInfo: 寄存器地址映射 -->
    <regAddrInfo>
        <xOutput>844</xOutput>                       <!-- 输出宽度寄存器地址 -->
        <yOutput>846</yOutput>                       <!-- 输出高度寄存器地址 -->
        <frameLengthLines>832</frameLengthLines>     <!-- 帧长寄存器地址(VTS) -->
        <lineLengthPixelClock>834</lineLengthPixelClock>  <!-- 行长寄存器地址 -->
        <coarseIntgTimeAddr>514</coarseIntgTimeAddr>       <!-- 曝光时间寄存器地址 -->
        <globalGainAddr>516</globalGainAddr>                <!-- 增益寄存器地址 -->
    </regAddrInfo>

    <!-- ④ resolutionInfo: 分辨率配置 -->
    <resolutionInfo>
        <resolutionData>
            <!-- 第一组 resolutionData 必须是最大分辨率(full resolution) -->
            <streamInfo>
                <streamConfiguration>
                    <vc>0</vc>                       <!-- Virtual Channel -->
                    <dt>43</dt>                       <!-- MIPI Data Type (43=RAW10) -->
                    <frameDimension>
                        <xStart>0</xStart>
                        <yStart>0</yStart>
                        <width>4032</width>
                        <height>3024</height>
                    </frameDimension>
                    <bitWidth>10</bitWidth>           <!-- 位深 -->
                    <type>IMAGE</type>                <!-- 流类型 -->
                </streamConfiguration>
                <lineLengthPixelClock>4500</lineLengthPixelClock>     <!-- 行长(像素) -->
                <frameLengthLines>3100</frameLengthLines>            <!-- 帧长(行) -->
                <minHorizontalBlanking>100</minHorizontalBlanking>   <!-- 最小水平消隐 -->
                <minVerticalBlanking>76</minVerticalBlanking>        <!-- 最小垂直消隐 -->
                <framerate>30</framerate>                            <!-- 帧率 -->
                <laneCount>4</laneCount>                             <!-- MIPI Lane 数 -->
                <settleTimeNs>17</settleTimeNs>                      <!-- MIPI settle time -->
            </streamInfo>
            <!-- 初始化寄存器设置 -->
            <resSettings>
            </resSettings>
        </resolutionData>
    </resolutionInfo>
</sensorDriverData>

19.3.2 关键 XML 字段详解

slaveInfo(传感器基本信息)

slaveAddress = 0x34     → sensor 的 I2C 从机地址(7bit 左移 1 位,即 8bit 地址)
                          实际 7bit 地址是 0x1A(0x34>>1)

regAddrType = 2          → sensor 内部寄存器地址用 2 个字节表示(16bit)
                           很多 sensor 用 16bit 地址,也有用 8bit 的
regDataType = 2          → sensor 内部寄存器的值用 2 个字节表示(16bit)

sensorIdRegAddr = 0x22  → sensor 的 CHIP_ID 放在寄存器 0x22 中
sensorId = 0x0586        → 读到的值应该是 0x0586
sensorIdMask = 0xFFFFFFFF → 比较时全部 32bit 都要匹配

i2cFrequencyMode = FAST  → I2C 速率 400kHz
                           STANDARD(100k), FAST(400k), FAST_PLUS(1MHz)
                           如果 sensor 不支持高速 I2C,设 STANDARD

powerUpSequence(电源时序)

configType 支持的类型:
  MCLK    → 输出 MCLK 时钟(configValue = 19200000 表示 19.2MHz)
  VANA    → 开启模拟电源(configValue = 2800000 表示 2.8V)
  VDIG    → 开启数字电源(configValue = 1050000 表示 1.05V)
  VIO     → 开启 IO 电源(configValue = 1800000 表示 1.8V)
  VAF     → 开启 AF 马达电源
  RESET   → 拉高/拉低 RESET 引脚(configValue=0 且 delay>0 拉高,configValue=1 拉低)
  STANDBY → 拉高/拉低 STANDBY 引脚

delayMs: 每个操作执行后的等待时间(ms)
  必须在 sensor datasheet 中找到这些时序参数
  如果写得太短 → sensor 未就绪 I2C 就会失败
  如果写得太长 → 开机时间变慢

常见问题:
  如果 powerUpSequence 中忘记配 MCLK → sensor 没有时钟 → I2C 通信失败
  如果 RESET 后的 delayMs 太短(< 5ms)→ sensor 内部未初始化完成 → 后续 I2C 失败

resolutionInfo(分辨率配置)

第一组 resolutionData 必须是 sensor 的最大分辨率(full resolution)
后续的 resolutionData 是其他可选分辨率

dt (Data Type):
  43  = RAW10 (0x2B)
  44  = RAW12 (0x2C)
  42  = RAW8  (0x2A)
  例如 YUV 格式的 DT 是 0x1E

bitWidth:
  10 → RAW10
  12 → RAW12
  Sensor 的实际输出位深,必须和 DT 一致

vc (Virtual Channel):
  0~3,同一 MIPI 链路上可以传输多路数据
  主图像通常用 VC=0,PDAF 数据用 VC=1

settleTimeNs:
  MIPI D-PHY 的"稳定时间"参数
  确保 sensor 的 PHY 发送器和 SoC 的 PHY 接收器之间的时序匹配
  参考 MIPI D-PHY v1.2 规范计算
  如果设置不对 → MIPI 链路不稳定 → 丢帧、花屏

lineLengthPixelClock(行长):
  每行的总像素数 = 有效像素 + HBLANK(水平消隐)
  影响 MIPI 带宽和帧率

frameLengthLines(帧长/VTS):
  每帧的总行数 = 有效行数 + VBLANK(垂直消隐)
  决定帧率上限: 帧率 = sensor_clk / (frameLengthLines × lineLengthPixelClock)

19.4 Kernel DTSI 配置

19.4.1 Sensor kernel node 的结构

CAMSS 框架下的 dtsi sensor 节点:

&cam_cci0 {
    qcom,camera@0 {
        cell-index = <0>;
        compatible = "qcom,cam-sensor";

        // CSI 接口
        csiphy-sd-index = <0>;    // 使用 CSIPHY 0
        csid-sd-index   = <0>;    // 使用 CSID 0

        // facing/orientation
        sensor-position-roll  = <90>;
        sensor-position-pitch = <0>;
        sensor-position-yaw   = <180>;

        // 子设备引用
        actuator-src = <&actuator0>;
        eeprom-src   = <&eeprom0>;

        // 电源
        cam_vdig-supply = <&pm8150a_l1>;  // 1.05V
        cam_vio-supply  = <&pm8150a_l6>;  // 1.8V
        cam_vana-supply = <&pm8150_l18>;  // 2.8V

        regulator-names = "cam_vdig", "cam_vio", "cam_vana";
        rgltr-min-voltage = <1050000 1800000 2800000>;
        rgltr-max-voltage = <1050000 1800000 2800000>;

        // GPIO
        gpios = <&tlmm 94 0>,    // MCLK
                <&tlmm 95 0>,    // RESET
                <&tlmm 96 0>;    // VDIG ENABLE
        qcom,gpio-reset = <1>;
        qcom,gpio-vdig  = <2>;

        // 时钟
        clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
        clock-names = "cam_clk";
        qcom,clock-rates = <24000000>;

        // CCI
        cci-master = <0>;
    };
};

CAMSS 和 msm_camera_v2 的 dtsi 区别:CAMSS 使用 csiphy-sd-indexcsid-sd-index,老平台使用 qcom,csiphy-sd-index。CAMSS 的 compatible 是 qcom,cam-sensor,老平台是 qcom,sensor


19.5 上电序列——从 XML 到硬件的执行

sensor XML 中定义的 powerUpSequence 会被 chi-cdk 编译后,在 HAL 调 CSL 时由 kernel 逐条执行。

上电执行的对应关系

XML 配置                     Kernel 执行
─────────────────────────    ────────────────────────
<configType>MCLK</configType>     clock_set_rate(mclk, 19200000); gpio_set_value(mclk_pin, 1);
<configType>VANA</configType>     regulator_enable(cam_vana_regulator);
<configType>VIO</configType>      regulator_enable(cam_vio_regulator);
<configType>RESET</configType>    gpio_set_value(reset_pin, 1);

Power Down 顺序

Power Down 是 Power Up 的"逆序":
  → 先停 MIPI(sensor 进入 standby)
  → 拉低 RESET
  → 关 VIO
  → 关 VANA
  → 关 MCLK

19.6 CCI(I2C)时序与调试

I2C 通信异常的原因

最常见的原因(按概率排序):
  1. 电源(VANA/VIO)没有给上 → sensor 不上电 → I2C 不通
  2. RESET 引脚没有拉高 → sensor 处于复位状态 → I2C 不通
  3. I2C 地址错误(7bit 和 8bit 搞混)→ 找到了错误的设备或无应答
  4. 同一 CCI 总线上多个设备的 I2C 地址冲突
  5. I2C 速率太高(sensor 只支持 100kHz 但配成了 400kHz)

CCI 调试

# 检查 CCI 状态和错误计数
adb shell cat /sys/kernel/debug/cci/status

# 查看 sensor I2C 通信日志
adb shell dmesg | grep -E "cci|i2c"

19.7 Bringup 常见调试方法

Probe 阶段

# 检查 probe 是否成功
adb shell dmesg | grep -E "cam_sensor|sensor_id"
# 成功: "camera sensor probe success"
# 失败: "i2c read error" 或 "sensor_id mismatch"

MIPI 调试

# 检查 CSID 错误
adb shell dmesg | grep -i "csid"
# 如果出现 CSID_ERR_ECC → MIPI 链路不稳定
#   → 检查 Lane 数量、速率、settleTimeNs 配置是否和 sensor 匹配

# 查看 PHY 状态
adb shell dmesg | grep -i "csiphy"

帧率调试

# 检查 sensor 的当前寄存器值(VTS/帧长)
adb shell dumpsys media.camera | grep -E "frame_length|frame rate"

# 原因: 帧率 = sensor_clk / (frameLengthLines × lineLengthPixelClock)
# 如果 VTS 太大 → 帧率被帧长限制

19.8 Bringup 完整步骤清单

□ 步骤 1: 硬件审查
   - 确认 schematic 上的电源/GPIO/CSI 连接
   - 从 sensor 厂商拿到 datasheet 和寄存器配置

□ 步骤 2: 修改 Sensor XML
   - slaveInfo: sensor 名称、I2C 地址、CHIP_ID
   - powerUpSequence/powerDownSequence
   - regAddrInfo: 曝光/增益/帧长寄存器地址
   - resolutionInfo: 分辨率、VC/DT、帧率、settleTimeNs

□ 步骤 3: 修改 Module XML
   - 关联 sensor/actuator/eeprom

□ 步骤 4: 修改 Kernel DTSI
   - sensor 节点: 电源 regulator、GPIO、CSI、时钟

□ 步骤 5: 编译
   - mmm chi-cdk/oem/qcom/sensor/
   - 生成 .bin 文件

□ 步骤 6: Push 验证
   - push .bin 到 /vendor/lib64/camera/
   - push dtbo 到设备

□ 步骤 7: 检查 Probe
   - dmesg | grep cam_sensor
   - 确认 probe success

□ 步骤 8: 测试上电
   - 打开相机 → 检查 regulator 是否 enable
   - 检查 logcat 中 CSLMessageHandler 是否有帧

19.9 本章总结

Bringup 的 4 个核心配置:
  Sensor XML → sensor 的软件参数(电源时序、分辨率、寄存器)
  Module XML → 模组关联关系
  Kernel DTSI → 硬件连接(电源/GPIO/CSI)
  Build Makefile → 编译 BIN

调试工具:
  dmesg | grep cam_sensor  → probe 状态
  debugfs/regulator        → 电源状态
  dmesg | grep csid        → MIPI/CSID 错误
  logcat | grep CSLMessage  → 帧数据

动手验证

  1. 查看你的设备上 probe 日志:adb shell dmesg | grep -E "cam_sensor|sensor_id"
  2. 打开相机后查看电源:adb shell cat /sys/kernel/debug/regulator/regulator_summary | grep -i cam
  3. 在你的源码中找 sensor XML 文件(chi-cdk/oem/qcom/sensor/ 下),打开一个,找到 powerUpSequenceresolutionInfo

常见误解