Sensor Bringup = 让一颗新的 Sensor 在你的主板上正常工作。这是 Camera 工程中最容易出现问题的环节。
本章以 xxx+ CAMSS 框架 为基准,完整覆盖 bringup 全过程——从硬件 schematic 审查、到 sensor XML 配置、kernel dtsi、上电序列、到调试方法。
在开始配置之前,先要做两件事:
从硬件工程师拿到原理图,确认以下信息:
① 电源(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 总线上
必须确认的参数:
① power up/down 时序(VANA → VIO → MCLK → RESET 的顺序和时间)
② CHIP_ID(用于 probe 阶段确认 sensor 在线)
③ 支持的分辨率和帧率
④ MIPI 输出格式(RAW10/RAW12、Lane 数量、速率)
⑤ I2C 寄存器地址(曝光/增益/帧率/测试模式等)
⑥ esettle time 参数(用于计算 settleTimeNs)
一次完整的 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/目录下。
每个 sensor 有一个关联的 XML 文件,定义了 sensor 的所有软件配置参数。
<!-- 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>
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)
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-index和csid-sd-index,老平台使用qcom,csiphy-sd-index。CAMSS 的 compatible 是qcom,cam-sensor,老平台是qcom,sensor。
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 Up 的"逆序":
→ 先停 MIPI(sensor 进入 standby)
→ 拉低 RESET
→ 关 VIO
→ 关 VANA
→ 关 MCLK
最常见的原因(按概率排序):
1. 电源(VANA/VIO)没有给上 → sensor 不上电 → I2C 不通
2. RESET 引脚没有拉高 → sensor 处于复位状态 → I2C 不通
3. I2C 地址错误(7bit 和 8bit 搞混)→ 找到了错误的设备或无应答
4. 同一 CCI 总线上多个设备的 I2C 地址冲突
5. I2C 速率太高(sensor 只支持 100kHz 但配成了 400kHz)
# 检查 CCI 状态和错误计数
adb shell cat /sys/kernel/debug/cci/status
# 查看 sensor I2C 通信日志
adb shell dmesg | grep -E "cci|i2c"
# 检查 probe 是否成功
adb shell dmesg | grep -E "cam_sensor|sensor_id"
# 成功: "camera sensor probe success"
# 失败: "i2c read error" 或 "sensor_id mismatch"
# 检查 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 太大 → 帧率被帧长限制
□ 步骤 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 是否有帧
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 → 帧数据
adb shell dmesg | grep -E "cam_sensor|sensor_id"adb shell cat /sys/kernel/debug/regulator/regulator_summary | grep -i camchi-cdk/oem/qcom/sensor/ 下),打开一个,找到 powerUpSequence 和 resolutionInfo。slaveAddress 中配置,不在 dtsi 的 reg 字段中。