每颗 sensor 模组都有制造偏差——镜头安装有偏差、颜色响应有偏差、AF 的无穷远位置有偏差。如果没有校准,同一款手机的不同台机器拍出来的照片,颜色不一样、对焦不准、暗角程度不同。
OTP(One-Time Programmable)或 EEPROM 存储的就是"个性化"的校准数据——每颗 sensor 模组出厂时被烧录进去的独一无二的修正参数。

这章讲清楚:OTP 是什么、存在哪里、怎么读取、怎么验证。
OTP = One-Time Programmable,一次性可编程存储器。
特点:
- 只能写入一次(出厂时烧录),之后不能修改
- 集成在 sensor 芯片内部(sensor 晶圆的一部分)
- 容量小(通常 4~8KB)
- 成本低(不需要单独的芯片)
- 适合存储固定的校准数据
类比: OTP = 出厂时激光刻上去的"身份证号",不能改
EEPROM = Electrically Erasable Programmable Read-Only Memory,电可擦除存储器。
特点:
- 可多次擦写(模组厂先烧录,后续可以更新)
- 独立的芯片(不和 sensor 集成在一起)
- 容量大(通常 64KB~2MB)
- 通过 I2C 接口通信
- 成本比 OTP 高
- 适合存储大数据量的校准(如 LSC 表)
类比: EEPROM = 一个可以反复读写的"U 盘"(但只在模组厂手里时擦写)
| 特性 | OTP | EEPROM |
|---|---|---|
| 存储介质 | sensor 芯片内部 | 独立 IC 芯片 |
| 可写次数 | 1 次(出厂烧录) | 可擦写(通常 100 万次,约 1M cycles @25°C) |
| 容量 | 小(4~8KB) | 大(64KB~2MB) |
| 通信方式 | 通过 sensor 的 I2C 寄存器读取 | 独立 I2C 地址 |
| 成本 | 低(集成在 sensor 内) | 高(需要额外芯片和 PCB 空间) |
| 位置 | sensor 晶圆上 | PCB 板上(独立芯片) |
| 读取方式 | 写 sensor 寄存器 → 读指定地址 | 直接 I2C 读 EEPROM 地址 |
混用现状:很多工程师不区分这两个词,统称"OTP 数据"或"EEPROM 数据"。重要的是——不管存在哪里,里面存的东西是差不多的(AF/AWB/LSC 校准值)。

根据源码 camx/src/core/hal/camxhal3metadatatagtypes.h:509-523 中的 struct EEPROMOTPData:
struct EEPROMOTPData {
AFCalibrationData AFCalibration; // AF 校准
WBCalibrationData WBCalibration[8]; // AWB 校准(最多 8 种光源)
LSCCalibrationData LSCCalibration[8]; // LSC 校准(最多 8 种光源)
DualCameraCalibrationData dualCameraCalibration; // 双摄校准
SPCCalibrationData SPCCalibration; // 坏点校正
OISCalibrationData OISCalibration; // 光学防抖
PDAFDCCCalibrationData PDAFDCCCalibration; // PDAF 校准
PDAF2DCalibrationData PDAF2DCalibration; // PDAF 2D 校准
LensData lensDataCalibration; // 镜头数据
EEPROMInformation EEPROMInfo; // OTP/EEPROM 信息
};
camxhal3metadatatagtypes.h:355)struct AFCalibrationData {
BOOL isAvailable; // 数据是否可用
INT16 macroDAC; // 微距位置的 actuator DAC 值
INT16 infinityDAC; // 无穷远位置的 actuator DAC 值
UINT32 numberOfDistances; // 校准的距离点数
};
infinityDAC: 拍无穷远时 actuator 的 DAC 值
每个模组的镜头安装公差不同,无穷远位置在 200~500 之间变化
如果没有这个值 → AF 对焦不准
macroDAC: 拍微距时 actuator 的 DAC 值
通常接近 actuator 的最大行程(如 1023 中的 900+)
camxhal3metadatatagtypes.h:372)struct WBCalibrationData {
BOOL isAvailable; // 数据是否可用
FLOAT rOverG; // R/G 比例
FLOAT bOverG; // B/G 比例
FLOAT grOverGB; // Gr/Gb 比例
};
rOverG: 红色通道相对于绿色通道的比例
期望范围 ~0.4~0.9
bOverG: 蓝色通道相对于绿色通道的比例
期望范围 ~0.4~0.8
grOverGB: Gr 和 Gb 通道的比例
期望 ~1.0(偏差 < 5%)
这些值在不同光源下不一样(D65/TL84/A 光等)
OEM 的 tuning 参数会参考这些值做颜色补偿
camxhal3metadatatagtypes.h:382)struct LSCCalibrationData {
BOOL isAvailable;
UINT16 meshHWRollOffSize; // LSC 网格大小
FLOAT rGain[]; // R 通道增益表(每个网格点的值)
FLOAT grGain[]; // Gr 通道增益表
FLOAT gbGain[]; // Gb 通道增益表
FLOAT bGain[]; // B 通道增益表
};
每个通道的增益表覆盖了 sensor 画面的不同区域
中心点增益 ≈ 1.0(不需要补偿)
边缘点增益 > 1.0(补偿暗角)
源码中有 EEPROM 的 XML 配置示例,位于 chi-cdk/oem/qcom/eeprom/irs1645_polar_eeprom.xml。
<EEPROMDriverData>
<slaveInfo>
<EEPROMName>irs1645_polar</EEPROMName>
<slaveAddress>0x7A</slaveAddress> <!-- I2C 地址 8bit -->
<regAddrType>2</regAddrType> <!-- 地址宽度 2 字节 -->
<regDataType>1</regDataType> <!-- 数据宽度 1 字节 -->
<i2cFrequencyMode>FAST</i2cFrequencyMode>
<powerUpSequence>
<powerSetting><configType>MCLK</configType>
<configValue>24000000</configValue><delayMs>18</delayMs></powerSetting>
<powerSetting><configType>VANA</configType>
<configValue>1</configValue><delayMs>20</delayMs></powerSetting>
</powerUpSequence>
</slaveInfo>
<memoryMap>
<map>
<id>0</id>
<regAddr>0x0000</regAddr> <!-- OTP 数据在 EEPROM 中的地址 -->
<size>4</size>
<dataType>AFCalibration</dataType> <!-- 这段是 AF 校准数据 -->
</map>
<map>
<id>1</id>
<regAddr>0x0010</regAddr>
<size>12</size>
<dataType>WBCalibration</dataType> <!-- 这段是 AWB 数据 -->
</map>
<map>
<id>2</id>
<regAddr>0x0100</regAddr>
<size>1024</size>
<dataType>LSCCalibration</dataType> <!-- 这段是 LSC 数据 -->
</map>
</memoryMap>
</EEPROMDriverData>

// camxsensornode.cpp:2608-2618
const EEPROMOTPData* SensorNode::GetOTPData()
{
HwCameraInfo cameraInfo;
HwEnvironment::GetInstance()->GetCameraInfo(m_cameraId, &cameraInfo);
pOTPData = &(cameraInfo.pSensorCaps->OTPData);
return pOTPData;
}
// camxsensornode.cpp:2765-2773
m_pOTPData = GetOTPData();
if (NULL == m_pOTPData) {
return CamxResultEInvalidPointer;
}
m_opt_wb_grgb = m_pOTPData->WBCalibration[0].grOverGB;
// BPS Node: camxbpsnode.cpp:5039
m_pOTPData = &(cameraInfo.pSensorCaps->OTPData);
// 每帧处理时: moduleInput.pOTPData = m_pOTPData; (line 1504)
// IFE Node: camxifenode.cpp:4782
m_IFEInitData.pOTPData = m_pOTPData;
# 通过 camxsettings.xml 中定义的属性触发 dump
adb shell setprop vendor.debug.camera.dumpSensorEEPROMData TRUE
# SensorNode 初始化时自动调用 DumpEEPROMData()
# logcat 中输出 OTP 数据
adb logcat | grep "EEPROM\|OTP"
dump 出来的文件内容示例:
Light Source: D65
rOverG = 0.512 ← R/G 比例,正常范围 0.4~0.9
bOverG = 0.482 ← B/G 比例,正常范围 0.4~0.8
grOverGB = 1.003 ← Gr/Gb 比例,应接近 1.0
Light Source: TL84
rOverG = 0.801
bOverG = 0.551
验证要点:
1. r/g 和 b/g 应在 0.4~1.0 范围内
2. gr/gb 应接近 1.0(偏差 < 5%)
3. 不同光源下比例应有明显差异
4. 如果所有光源下 r/g 都相同 → 数据可能是假的(被填充了固定值)
dump 出来的 AF 数据:
AF INF Position = 380 (DAC code)
验证:
1. 是否在 actuator 的行程范围内(0~1023)
2. 是否合理(通常在 200~500 之间)
3. 和 sensor 厂商给出的典型值对比
如果 AF INF Position = 0 或 1023 → 数据可能损坏
LSC Table(17×13 网格):
中心 (8,6): R=1.00 G=1.00 B=1.00 ← 中心不需要补偿
角 (0,0): R=1.15 G=1.12 B=1.18 ← 边缘需要补偿
角 (16,0): R=1.16 G=1.13 B=1.19
角 (0,12): R=1.14 G=1.11 B=1.17
角 (16,12): R=1.17 G=1.14 B=1.20
验证:
1. 中心增益 ≈ 1.0
2. 四角增益 > 中心(1.0~1.5 正常)
3. R/G/B 增益变化趋势一致
4. 无 0 或异常大值(> 5.0)
AWB 数据损坏 → 相机偏色(所有光源下颜色都不对)
AF 数据损坏 → 对焦不准(无穷远对不上)
LSC 数据损坏 → 镜头暗角明显(四周比中心暗得多)
CRC 校验失败 → HAL 可能拒绝使用 OTP 数据,回退到默认参数
OTP = sensor 内部的"身份证"(一次性,出厂烧录)
EEPROM = 独立芯片(可多次擦写,容量更大)
都存在哪里:
- sensor 内部寄存器(OTP)
- 独立 I2C EEPROM 芯片
存什么:
AF Calibration → 无穷远对焦位置
AWB Golden Data → R/G、B/G、Gr/Gb 比例
LSC Table → 镜头阴影补偿增益
怎么做:
setprop → 打开相机 → dump 到 /data/vendor/camera/
怎么验证:
AWB: r/g 0.4~0.9, b/g 0.4~0.8, gr/gb ~1.0
AF: 行程范围内、和典型值对比
LSC: 中心 1.0 → 边缘逐渐增大
adb shell setprop vendor.debug.camera.dumpSensorEEPROMData TRUE,打开相机后检查 /data/vendor/camera/ 下是否有 dump 文件。