← 返回课程

OTP_EEPROM

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

第 20 章:OTP / EEPROM / 校准数据


本章导读

每颗 sensor 模组都有制造偏差——镜头安装有偏差、颜色响应有偏差、AF 的无穷远位置有偏差。如果没有校准,同一款手机的不同台机器拍出来的照片,颜色不一样、对焦不准、暗角程度不同。

OTP(One-Time Programmable)或 EEPROM 存储的就是"个性化"的校准数据——每颗 sensor 模组出厂时被烧录进去的独一无二的修正参数。

OTP vs EEPROM 物理存储位置对比

这章讲清楚:OTP 是什么、存在哪里、怎么读取、怎么验证。


20.1 OTP 和 EEPROM 是什么

20.1.1 OTP

OTP = One-Time Programmable,一次性可编程存储器。

特点:
  - 只能写入一次(出厂时烧录),之后不能修改
  - 集成在 sensor 芯片内部(sensor 晶圆的一部分)
  - 容量小(通常 4~8KB)
  - 成本低(不需要单独的芯片)
  - 适合存储固定的校准数据

类比: OTP = 出厂时激光刻上去的"身份证号",不能改

20.1.2 EEPROM

EEPROM = Electrically Erasable Programmable Read-Only Memory,电可擦除存储器。

特点:
  - 可多次擦写(模组厂先烧录,后续可以更新)
  - 独立的芯片(不和 sensor 集成在一起)
  - 容量大(通常 64KB~2MB)
  - 通过 I2C 接口通信
  - 成本比 OTP 高
  - 适合存储大数据量的校准(如 LSC 表)

类比: EEPROM = 一个可以反复读写的"U 盘"(但只在模组厂手里时擦写)

20.1.3 OTP vs EEPROM 对比

特性 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 校准值)。


20.2 OTP/EEPROM 存储的数据——源码确认

OTP 数据在 EEPROM 地址空间中的布局

根据源码 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 信息
};

AF 校准数据(源码 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+)

AWB 校准数据(源码 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 参数会参考这些值做颜色补偿

LSC 校准数据(源码 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(补偿暗角)

20.3 EEPROM 的 XML 配置

源码中有 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>

OTP 数据从 Sensor/EEPROM 到 ISP 的读取路径

20.4 OTP 数据的完整路径——从硬件到 ISP

第 1 步:HwEnvironment 获取 OTP 数据

// camxsensornode.cpp:2608-2618
const EEPROMOTPData* SensorNode::GetOTPData()
{
    HwCameraInfo cameraInfo;
    HwEnvironment::GetInstance()->GetCameraInfo(m_cameraId, &cameraInfo);
    pOTPData = &(cameraInfo.pSensorCaps->OTPData);
    return pOTPData;
}

第 2 步:SensorNode 读取 OTP 数据

// camxsensornode.cpp:2765-2773
m_pOTPData = GetOTPData();
if (NULL == m_pOTPData) {
    return CamxResultEInvalidPointer;
}
m_opt_wb_grgb = m_pOTPData->WBCalibration[0].grOverGB;

第 3 步:OTP 数据传到 ISP 节点

// 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;

OTP 数据怎么读出来——setprop

# 通过 camxsettings.xml 中定义的属性触发 dump
adb shell setprop vendor.debug.camera.dumpSensorEEPROMData TRUE
# SensorNode 初始化时自动调用 DumpEEPROMData()
# logcat 中输出 OTP 数据
adb logcat | grep "EEPROM\|OTP"

20.4 OTP 数据验证指南

AWB 验证

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 都相同 → 数据可能是假的(被填充了固定值)

AF 验证

dump 出来的 AF 数据:

AF INF Position = 380  (DAC code)

验证:
  1. 是否在 actuator 的行程范围内(0~1023)
  2. 是否合理(通常在 200~500 之间)
  3. 和 sensor 厂商给出的典型值对比

如果 AF INF Position = 0 或 1023 → 数据可能损坏

LSC 验证

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)

20.5 OTP 数据损坏的后果

AWB 数据损坏 → 相机偏色(所有光源下颜色都不对)
AF 数据损坏 → 对焦不准(无穷远对不上)
LSC 数据损坏 → 镜头暗角明显(四周比中心暗得多)
CRC 校验失败 → HAL 可能拒绝使用 OTP 数据,回退到默认参数

20.6 本章总结

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 → 边缘逐渐增大

动手验证

  1. 执行 adb shell setprop vendor.debug.camera.dumpSensorEEPROMData TRUE,打开相机后检查 /data/vendor/camera/ 下是否有 dump 文件。
  2. 如果找到 dump 文件,查看 AWB 数据,检查 r/g 和 b/g 是否在合理范围内。
  3. 查看 dump 文件中 AF INF position 的值。

常见误解