Camera Module一般会采取两种方式来记录该Sensor的一些信息
-
OTP:One Time Programmable。
在嵌入式系统中,所有代码和系统数据都被存储在FLASH芯片内部。FLASH芯片可多次擦写,且掉电数据不丢失。为了保护FLASH中的数据,厂商提供OTP寄存器,OTP这个寄存器只可以编写一次,之后不能修改。
-
EEPROM:全称“电可擦除可编程只读存储器”( Electrically Erasable Programmable Read – Only Memory),手机中camera模块的EEPROM主要用来存储OTP数据,用来进行校准,来保持模组一致性。
加入知识星球与更多Camera同学交流
- 星球名称:深入浅出Android Camera
- 星球ID: 17296815
OTP介绍
OTP数据包括
-
Module Info:物料ID、日期、镜头、VCM等基本信息
-
LSC:lens shading calibration data
-
AWB:R、Gr、Gb、B的通道值或比值
-
AF:远、近焦的position对应DAC值
-
PDAF:SPC和DCC的data
Platform OTP
Sensor没有OTP自校准功能,需要我们BB端进行校正。从存储空间(外挂eeprom或者sensor内部存储空间)中读出数据,然后将数据送到BB端进行校正
Sensor OTP
Sensor有OTP自校准功能, 从存储空间(外挂eeprom或者sensor内部存储空间)中读出数据,然后写回sensor寄存器,送到BB端的Raw Data是已经校准过的数据
OTP存储方式
-
Sensor内:在sensor芯片中ROM,和sensor公用I2C bus和read/write id
OTP数据烧录在sensor的寄存器中。 这种方案省钱,不需要额外的存储器件,但是存储空间小,如果需要烧录的数据量过大,就不适用。
-
Sensor外:sensor外挂的EEPROM,和sensor公用I2C bus,但具有不同的read/write id
该方案优势是存储空间大,如果数据量过多,就需要这种方案,缺点是多一个独立的EEPROM存储器件。
OTP作用
OTP是用来给camera sensor做calibration(校准)用的。 因为模组生产出来会有很大的差异性,为了保证效果一致性, 模组厂会挑选一部分模组作为golden,然后将其他模组的相应参数校准到和这些golden一样, (golden不是最好的模组,也不是最差的模组,而是各方面最平均的模组)
代码实现
MTKOTP代码
Platform OTP
如果是MTK平台,首先需要读文档:MT6779_OTP_Porting_Guide.pdf
Using eeprom_drive.c, cam_cal_list.c as OTP adapter
Kernel modification:
/Kernel-4.9/arch/arm64/boot/dts/mediatek/cust_tb8768_camera.dtsi
/kernel-4.9/drivers/misc/mediate/dws/mediatek/mt6765/tp8768tp1_64_bsp.dws
/Kernel-4.9/arch/arm64/configs/achilles6_prc_wifi_defconfig
/Kernel-4.9/arch/arm64/configs/ achilles6_prc_wifi_debug_defconfig
/kernel-4.9/drivers/misc/mediatek/cam_cal/src/common/v1/eeprom_drive.c
/kernel-4.9/drivers/misc/mediatek/cam_cal/src/mk6765/cam_cal_list.c
Hal modification
/vendor/mediatek/proprietary/custom/mt6765/hal/imgsensor_src/camera_calibration_cam_cal.cpp
Platform OTP 框架
Step1:check dtsi and defconfig
/kernel-4.9/drivers/misc/mediate/dws/mediatek/mt6765/tp8768tp1_64_bsp.dws
配置main/sub eeprom地址,不能配置一样就行避免冲突(但实际上这块配置在不同CHANNEL,不会有冲突)。这块有工具配置(dws 工具路径:
./vendor/mediatek/proprietary/scripts/dct/DrvGen.exe)
通过上述截图可以发现,CAMERA_MAIN_EEPROM、CAMERA_SUB_EEPROM的通讯地址分别是0x50、0x52。对应生成cust.dtsi文件
cust.dtsi在对camera的配置:
文件路径:
/out/target/product/tb8768tp1_64_bsp/obj/KERNEL_OBJ/arch/arm/boot/dts/ tb8768tp1_64_bsp /cust.dtsi
代码中想要成功调用到对应的 eeprom_hw_i2c_probe() 和eeprom_hw_i2c_probe2() 函数需要分别匹配上 cust.dtsi 文件中的 compatible 节点 “mediatek,camera_main_eeprom” 和 "mediatek,camerasub eeprom "
配置defconfig 文件
/Kernel-4.9/arch/arm64/configs/achilles6_prc_wifi_defconfig
/Kernel-4.9/arch/arm64/configs/ achilles6_prc_wifi_debug_defconfig
Step2:OTP Adapter
/kernel-4.9/drivers/misc/mediatek/cam_cal/src/mk6765/cam_cal_list.c
Step3:OTP Hal
NULL表示不支持OTP,否则表示支持
/vendor/mediatek/proprietary/custom/mt6765/hal/imgsensor_src/sensor_list.cpp
/vendor/mediatek/proprietary/custom/mt6765/hal/imgsensor_src/camera_calibration_cam_cal.cpp 默认sensor流程
/vendor/mediatek/proprietary/custom/mt6765/hal/imgsensor_src/camera_calibration_cam_cal_ov13b10.cpp 特定sensor
DoCamCal2Again()其他的函数和DoCamCalSingleLsc()实现很相似
配置像素ID:如果要进行Isc校准,需要在camera_isp_isc_xxxmipirow .h中配置像素id与模块厂商确定烧成OTP的第一个像素,然后修改vendor/mediatek/proprietary /custom / mt6765/hal/ imgsensor / xxx_mipi_raw/ camera_isp_Isc_xxxmipiraw.h
SensorGoldenCalTable{ //SensorGoldenCalTable
pixId: 3, //0,1,2,3: B, Gb, Gr,R
SlimLscType: 0
Width:0
}
OTP Read Flow
Sensor OTP
Sensor OTP代码和Platform OTP代码类似,在custom_camera_msdk.cpp中GetCameraCalData()函数来区分走默认函数CAM_CALGetCalData(),就是sensor OTP。Sensor
1、这块可以修改rg bg的值,刷版本看预览是否偏色,来看OTP是否正常(偏色)应用
2、这一抓kernel log来看OTP数据,是否正常。这块可以联系模组厂fae看OTP数据是否正常。
adb reboot
adb root
adb shell dmesg > D:\log\kernel.txt
sensor OTP的函数 》sensor型号_read_data_kernel《,获取有差异,但是大同小异。这里讲一个不一样的,万一找不到,从datasheet中找出OTP的寄存器,然后在驱动代码中搜寄存器就找到了;platform OTP可以根据camera_custom_msdk.cpp中GetCameraCalData()函数来看走那个函数来分析。
高通OTP代码
kernel层
(1)eeprom初始化
./kernel/msm-4.14/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
函数主要是实现了两个功能:
- 通过platform_driver_register函数注册平台驱动(有match device和driver的动作)(msm_eeprom_platform_driver)
- 将msm_eeprom_i2c_driver挂载i2c总线上
(2)match驱动和设备
这之后,就会根据名称匹配驱动driver和设备device
./kernel/msm-4.14/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
./kernel/msm-4.14/arch/arm/boot/dts/qcom/sm8150-camera-sensor-qrd.dtsi(//举个例子)
在dtsi中是设备的定义
平台 + 驱动 + 设备
compatible = “qcom,eeprom”和 .driver = {.name = “qcom,eeprom”,匹配上了,
系统就去调用probe函数probe = msm_eeprom_i2c_probe
(3)match成功,调用probe
./kernel/msm-4.14/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
这个函数主要工作:
- msm_eeprom_get_dt_data(e_ctrl);读取dtsi配置的上电时序配置/
- msm_eeprom_parse_memory_map用于解析以下节点
- msm_camera_power_up上电
- read_eeprom_memory读取OTP数据
- msm_camera_power_down下电
说白了,前面无非就是去读取dtsi的配置,进行上电,然后读取OTP数据,下电,
这就是整个probe函数的流程!
(4)读取OTP数据:read_eeprom_memory
qcom,page0 =
= <有效值 地址 地址类型 数据 数据类型 延迟>
qcom,page7 = <1 0x3d81 2 0x01 1 10>;/*往0x3d81写入0x01:把OTP数据加载到buffer中 */
qcom,pageen7 = <0 0x0 0 0x0 0 0>;
qcom,poll7 = <0 0x0 0 0x0 0 0>;
qcom,mem7 = <256 0x7010 2 0 1 1>;/*从0x7010开始读取256个数据*/
Userspace层
在kernel层,数据最后被保存到memptr指向的地址里
vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/eeprom/eeprom.c
用户态通过ioctl下到内核,我们看下内核的接受者函数
./kernel/msm-4.14/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
Copy_to_user中将cal_data.mapdata的num_bytes个数据放到cfg.read_data.dbuffer