尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

MTK Camera双摄调试实战:PDN极性与sensor探测机制深度解析

MTK Camera双摄调试实战:PDN极性与sensor探测机制深度解析 简介本资源是一份面向MTK平台Android手机Camera驱动开发与调试工程师的实战技术指南聚焦imx与ov系列主流sensor如IMX111、OV9724、OV8825等在89平台上的集成与问题定位。文档系统梳理了camera上电流程、sensor初始化机制、ID识别原理及典型点不亮故障的分层排查思路特别详解了power down极性适配、kdSensorList数组配置、CIS模块供电控制等易错环节并结合mobilelog kernel_log.boot日志分析方法提供可落地的调试路径。资源为单个231KB的Word文档.docx内容结构清晰含关键代码路径说明与真实调试案例便于快速查阅与工程复用。目前已有1627人学习下载适合具备Linux内核基础、正参与MTK Camera Bring-up或量产问题攻关的中高级嵌入式开发者。1. MTK Camera调试指南不是看文档就能点亮的黑匣子而是靠 kernel_log.boot 和 power down 极性翻车现场复盘出来的实战手册你手头有一块 MT6589 或 MT89 平台的板子烧好了mt89_v10_vanzo_test固件Projectconfig.mk里明明写了CUSTOM_KERNEL_IMGSENSORimx111_mipi_raw ov9724_mipi_raw但开机后前摄能预览、后摄黑屏或者更玄学的是——单开前摄 OK、单开后摄 OK一齐打开就后摄 ID 能读到、图像死活不出。这时候你翻遍 MTK 官方文档、查遍 Google 和论坛发现全是“配置 sensorlist.h”“修改 kd_sensorlist.c”这类教科书式步骤却没人告诉你真正卡住你的是camera_pdn_reverse这个全局变量在getsensorid()里被悄悄改写的一行代码以及kdCISModulePowerOn()中对 power down 引脚极性反向的临时补丁。这不是驱动移植这是硬件时序与软件初始化逻辑的耦合博弈。本文不讲理论堆砌只拆解你在mobilelog/kernel_log.boot里真实看到的[0][1][1][imx111mipiraw][32]日志含义、kdSetDriver()参数pDrvIndex的高低 16 位怎么映射物理摄像头、为什么ov9724和imx111在同一块 PCB 上会因 PDN 极性冲突导致 ID 双重命中——所有内容均来自我亲手调试imx111 ov9724双摄项目时抓取的 kernel log、反编译的 init 流程、以及在kd_camera_hw.c里加了 17 个printk后定位到的那 3 行关键赋值。适合正在啃 MTK 89/6589 平台 camera 驱动、手上正拿着imx系列imx111/imx135/imx188和ov系列ov9724/ov8825/ov12830sensor datasheet 的一线嵌入式工程师也适合刚从 RK/Allwinner 切过来、以为“上电→读 ID→open”是标准流水线、结果在 MTK 这里被pDrvIndex[0]的 bit layout 教做人的人。2. Camera 上电流程深度拆解从 Projectconfig.mk 到 kernel_log.boot看清 MTK 是如何“盲扫”sensor 的MTK 的 camera 初始化不是按“前摄/后摄”逻辑启动的而是一场无差别、分两轮的 sensor 存在性探测。理解这个机制是读懂kernel_log.boot里[0][1][1]这类日志的前提也是后续排查 ID 误读、双摄冲突的根基。2.1 Projectconfig.mk 是起点但不是终点CONFIG 如何触发 sensor list 构建Projectconfig.mk中的CUSTOM_KERNEL_IMGSENSOR和CUSTOM_HAL_IMGSENSOR并非直接生成驱动而是作为宏定义参与编译条件判断。以imx111_mipi_raw为例其实际生效路径如下# mediatek/custom/vanzo89_wet_jb2/ProjectConfig.mk CUSTOM_KERNEL_IMGSENSOR : imx111_mipi_raw ov9724_mipi_raw该变量会被mediatek/custom/common/kernel/imgsensor/Android.mk引用并通过$(foreach sensor,$(CUSTOM_KERNEL_IMGSENSOR),$(call add-sensor,$(sensor)))生成对应 sensor 目录的编译规则。最终每个 sensor 的.c文件如imx111mipiraw_Sensor.c会被编译进 kernel image并在kd_sensorlist.c的静态数组中注册其初始化函数指针。提示CUSTOM_KERNEL_IMGSENSOR仅控制 kernel 层 sensor 驱动是否编译进内核CUSTOM_HAL_IMGSENSOR控制 HAL 层是否加载对应.so。二者必须严格一致否则会出现 kernel 能读 ID、HAL 找不到 driver 的经典黑屏。2.2 kdSensorList[]sensor 的“户籍档案”增删 sensor 必改的三处硬编码kdSensorList[]是整个上电流程的索引中枢它定义在mediatek/custom/common/kernel/imgsensor/src/kd_sensorlist.h是一个SENSOR_INIT_FUNCT*类型的数组。每新增一个 sensor必须在此处添加一行// mediatek/custom/common/kernel/imgsensor/src/kd_sensorlist.h extern int IMX111_MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT pFunc); extern int OV9724_MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT pFunc); // 注意顺序必须与 Projectconfig.mk 中的顺序一致 SENSOR_INIT_FUNCT kdSensorList[MAX_NUM_OF_SENSORS] { {IMX111_MIPI_RAW_SensorInit, imx111mipiraw}, {OV9724_MIPI_RAW_SensorInit, ov9724mipiraw}, // ... 其他 sensor };这个数组的长度MAX_NUM_OF_SENSORS由kd_sensorlist.c中的#define MAX_NUM_OF_SENSORS 8决定。若超出kdGetSensorInitFuncList()返回的pSensorList指针将越界导致 kernel panic。血泪经验曾因忘记同步修改MAX_NUM_OF_SENSORS导致第 9 个 sensor 的getsensorid()函数地址被覆盖为 0ioctl调用直接跳转到 NULL 地址。2.3 kdSetDriver()双摄探测的“发动机”pDrvIndex 参数的位域解析kdSetDriver()是启动 sensor 探测的核心函数其参数pDrvIndex是一个UINT32[2]数组。关键在于第一个元素pDrvIndex[0]的位域含义Bit 位置含义取值示例说明Bit 0–15前/后摄标识0x0001 后摄0x0002 前摄注意此值并非物理端口编号而是 MTK 内部约定的逻辑角色Bit 16–31Sensor 索引0x0001 第 1 个 sensor即kdSensorList[0]0x0002 第 2 个 sensor索引从 1 开始与数组下标错 1因此pDrvIndex[0] 0x00010001表示以“后摄”身份探测kdSensorList[0]即 imx111pDrvIndex[0] 0x00020002表示以“前摄”身份探测kdSensorList[1]即 ov9724。这个设计导致了一个关键行为MTK 不关心你硬件上把哪个 sensor 接在哪条 MIPI 通道它只是机械地、按kdSensorList顺序先用0x0001xxxx轮询所有 sensor再用0x0002xxxx轮询所有 sensor。能否成功完全取决于 sensor 的 power down 引脚是否在对应角色下被正确拉高/拉低。2.4 CAMERA_HW_Ioctl()上电与读 ID 的原子操作两个 ioctl case 的分工真相CAMERA_HW_Ioctl()是 kernel 层 camera 设备节点的入口其核心逻辑围绕两个 ioctl 命令展开static long CAMERA_HW_Ioctl( struct file * a_pstFile, unsigned int a_u4Command, unsigned long a_u4Param) { switch (a_u4Command) { case KDIMGSENSORIOC_T_CHECK_IS_ALIVE: // 【上电命令】 i4RetValue adopt_CAMERA_HW_CheckIsAlive(); break; case KDIMGSENSORIOC_X_FEATURECONCTROL: // 【功能控制命令】 i4RetValue adopt_CAMERA_HW_FeatureControl(pBuff); break; // ... 其他 case } return i4RetValue; }KDIMGSENSORIOC_T_CHECK_IS_ALIVE调用adopt_CAMERA_HW_CheckIsAlive()该函数内部执行kdCISModulePowerOn()—— 即真正的上电序列VDD/VANA/VDIG/VIO/PDN/RESET。只有这一步成功sensor 才可能响应后续 I2C 通信。KDIMGSENSORIOC_X_FEATURECONCTROL调用adopt_CAMERA_HW_FeatureControl()其参数pBuff是一个struct ACDK_SENSOR_GET_SENSOR_INFO_STRUCT结构体其中FeatureId SENSOR_FEATURE_GET_SENSOR_ID。此时才调用具体 sensor 的GetSensorID()函数如IMX111_MIPI_RAW_GetSensorID()通过 I2C 读取寄存器0x0000或0x0002获取 ID。关键点CheckIsAlive和GetSensorID是两个独立的 ioctl 调用中间没有隐含的 delay。如果CheckIsAlive上电后 sensor 未稳定如 PLL 未 lockGetSensorID就会读到 0x0000 或错误值。这就是为什么有些 sensor 需要在kdCISModulePowerOn()末尾手动加msleep(10)。3. Power Down 极性imx111 与 ov9724 的“握手协议”冲突才是双摄黑屏的元凶imx111和ov9724的 datasheet 明确写着PDN 引脚为active-low低电平有效。但 MTK 默认的kdCISModulePowerOn()实现对所有 sensor 统一执行gpio_set_value(PDN_PIN, 1)来释放 PDN即拉高。这就造成了一个致命矛盾MTK 认为“释放 PDN sensor 工作”而 sensor 实际要求“拉低 PDN sensor 工作”。当imx111和ov9724共享同一组 power control GPIO常见于低成本方案且 PDN 引脚物理上并联时问题就爆发了。3.1 camera_pdn_reverse一个全局变量引发的“极性矫正”连锁反应camera_pdn_reverse定义在mediatek/custom/vanzo89_wet_jb2/kernel/camera/camera/kd_camera_hw.c// kd_camera_hw.c static kal_uint32 camera_pdn_reverse 0; // 初始为 0表示默认极性高有效它的作用是在GetSensorID()函数中首次成功读取 ID 后将该 sensor 的 PDN 极性标记为“需反转”。以imx111mipiraw_Sensor.c为例// imx111mipiraw_Sensor.c UINT32 IMX111_MIPI_RAW_GetSensorID(UINT32 *sensorID) { // ... I2C 读 ID 代码 ... if (temp_val IMX111_SENSOR_ID) { *sensorID IMX111_SENSOR_ID; // 【关键】首次读到 ID标记 PDN 需反转 camera_pdn_reverse 1; // 注意此处是全局变量 return ERROR_NONE; } return ERROR_SENSOR_CONNECT_FAIL; }这个赋值动作会在后续所有kdCISModulePowerOn()调用中生效。kdCISModulePowerOn()内部有如下逻辑// kd_camera_hw.c if (camera_pdn_reverse) { gpio_set_value(PDN_PIN, 0); // 拉低 PDN激活 sensor } else { gpio_set_value(PDN_PIN, 1); // 拉高 PDN释放 sensor错误 }玄学来了camera_pdn_reverse是全局变量不是 per-sensor 的这意味着一旦imx111的GetSensorID()成功并置 1后续ov9724的上电也会走gpio_set_value(PDN_PIN, 0)路径。如果ov9724的 PDN 电路设计与imx111不同例如用了反相器就会导致ov9724在imx111之后被错误地拉低 PDN 而失效。3.2 双摄 ID 双重命中的日志证据kernel_log.boot 里的[0][1][1]和[0][2][1]打开mobilelog/kernel_log.boot搜索imx111你会看到类似这样的连续日志[0][1][1][imx111mipiraw][32] [0][2][1][imx111mipiraw][32]解读[0]pDrvIndex[0]的索引当前只用第一个[1]pDrvIndex[0]的低 16 位 1 →后摄模式[1]pDrvIndex[0]的高 16 位 1 →探测 kdSensorList[0][2]pDrvIndex[0]的低 16 位 2 →前摄模式[1]pDrvIndex[0]的高 16 位 1 →仍探测 kdSensorList[0]现象imx111在后摄模式本应成功和前摄模式本应失败下都被读到了 ID。原因imx111的GetSensorID()在后摄轮次首次执行成功读 ID 并将camera_pdn_reverse1进入前摄轮次时kdCISModulePowerOn()因camera_pdn_reverse1而拉低 PDN恰好imx111的 PDN 是 active-low所以它又被激活了——尽管它物理上接在后摄 MIPI 通道。3.3 ov9724 的“被动受害”为什么前摄能亮、后摄不亮在mt89_v10_vanzo_test项目中ov9724被接在前摄通道imx111接在后摄通道。但因为camera_pdn_reverse全局生效导致后摄轮次imx111上电PDN 拉低→ 读 ID 成功 →camera_pdn_reverse1前摄轮次imx111再次上电PDN 拉低→ 读 ID 成功误报→ov9724的上电序列也被camera_pdn_reverse1影响PDN 被拉低 → 但ov9724的硬件电路可能要求 PDN 拉高才能工作于是ov9724实际未激活 →GetSensorID()失败 → HAL 层认为前摄不存在 → 用户看到“前摄黑屏”根本矛盾camera_pdn_reverse的设计初衷是解决单 sensor 的极性问题但它被实现为全局变量无法区分不同 sensor 的硬件差异。这是 MTK 89 平台的一个已知缺陷官方 patch 是将其改为 per-sensor 的 flag但老项目只能自己修。4. 避坑MTK Camera 调试中最常踩的 5 个深坑现象、原因、解决全还原调试 MTK camera 不是拼凑代码而是在 kernel log 的字里行间、GPIO 的电平跳变、I2C 的 ACK/NACK 信号里找线索。以下是我在imx111ov9724双摄项目中用逻辑分析仪和串口 log 交叉验证出的 5 个高频、致命、文档里绝不会写的坑。4.1 现象kernel_log.boot里imx111的[0][1][1]日志出现但adb shell dumpsys media.camera显示 “No camera devices found”原因kdSensorList[]中imx111的初始化函数名与.c文件中定义的不一致。例如kd_sensorlist.h写的是IMX111_MIPI_RAW_SensorInit但imx111mipiraw_Sensor.c里定义的是IMX111_MIPI_RAW_sensorinit小写 s。编译时不会报错函数声明和定义分离但链接时kdSensorList[0].pFunct指向一个未定义的符号运行时kdSetDriver()调用该函数指针直接跳转到 0 地址或随机地址kernel panic 被 silent faillog 里只显示[0][1][1]就没了。解决在imx111mipiraw_Sensor.c开头加#pragma message(IMX111 init func registered)确认编译日志中有此输出用nm vmlinux | grep imx111查看符号表确认IMX111_MIPI_RAW_SensorInit是否存在且为Ttext类型。4.2 现象ov9724的 ID 能读到[0][2][2]日志出现但预览画面是纯绿或纯紫噪点原因ov9724的 MIPI clock laneCLK或 data laneD0-D3的 PCB 走线长度严重 mismatch导致 MIPI 接收端ISP采样时序错误。ov9724对时序比imx111更敏感ID 是低速 I2C 读取不受影响但高速 MIPI video stream 无法同步。解决用示波器抓 CLK 和 D0 的眼图确认 setup/hold time检查Projectconfig.mk中CUSTOM_KERNEL_IMGSENSOR的顺序——ov9724必须排在imx111之后因为kdSensorList顺序影响kdSetDriver()的调用顺序而某些平台的 ISP 初始化依赖 sensor list 的排列。4.3 现象单摄工作正常双摄同时打开时imx111预览正常ov9724预览卡在第一帧不动原因ov9724的GetSensorID()函数中msleep(10)时间不足。ov9724从上电到 PLL lock 需要 15ms但kdCISModulePowerOn()末尾只msleep(10)导致GetSensorID()读到的 ID 是旧值缓存HAL 层误判 sensor 存在但后续 streaming 时 sensor 实际未 ready。解决在ov9724mipiraw_Sensor.c的OV9724_MIPI_RAW_GetSensorID()函数开头i2c_read之前强制加msleep(20)或在kdCISModulePowerOn()中针对ov9724的 case将msleep改为20。4.4 现象kernel_log.boot里ov9724的[0][2][2]日志从未出现但 I2C bus 上能用i2cdetect -y 0扫到0x30地址原因ov9724的 I2C address 在kd_sensorlist.h中定义为0x30但在ov9724mipiraw_Sensor.c的OV9724_MIPI_RAW_GetSensorID()中i2c_client-addr被硬编码为0x607-bit address 错写成 8-bit。i2cdetect显示0x30是正确的 7-bit 地址但驱动用0x60去读自然超时。解决统一使用 7-bit address。i2c_client-addr 0x30;i2c_smbus_read_byte_data(client, 0x00)中的client地址即为0x30。4.5 现象imx111在kdCISModulePowerOn()中上电后用万用表测到 VANA2.8V但GetSensorID()返回ERROR_SENSOR_CONNECT_FAIL原因imx111的 RESET 引脚在kdCISModulePowerOn()中被gpio_set_value(RESET_PIN, 0)拉低后未按 datasheet 要求保持足够时间≥1ms再拉高。MTK 默认实现是gpio_set_value(RESET_PIN, 0); msleep(1); gpio_set_value(RESET_PIN, 1);但msleep(1)在 kernel 中精度不足实际可能只有 0.3ms。解决将msleep(1)替换为udelay(1000)精确微秒级 delay确保 RESET 低电平 ≥1000us或在kdCISModulePowerOn()中gpio_set_value(RESET_PIN, 0)后插入for(i0;i1000;i) barrier();空循环。5. 添加新 sensor 的完整 checklist从 kernel 到 HAL6 个文件、12 个关键点、1 个验证脚本往 MTK 89 平台添加一颗新 sensor如imx135_mipi_raw不是复制粘贴就能完事。我整理了一份经过imx111/ov9724/ov8825三颗 sensor 验证的 checklist覆盖 kernel 和 HAL 两层每个点都对应一个可能的翻车现场。5.1 Kernel 层4 个文件8 个必改项文件路径关键点检查项为什么重要mediatek/custom/common/kernel/imgsensor/src/kd_sensorlist.hkdSensorList[]数组1. 新增{IMX135_MIPI_RAW_SensorInit, imx135mipiraw}2.MAX_NUM_OF_SENSORS1数组越界会导致 kernel panic且 log 无提示mediatek/custom/common/kernel/imgsensor/inc/kd_imgsensor.hsensor ID 宏定义3.#define SENSOR_IMX135_MIPI_RAW 0x13504.#define IMX135_SENSOR_ID 0x1350HAL 层通过此 ID 匹配 sensorID 错则 HAL 加载失败mediatek/custom/common/kernel/imgsensor/src/kd_sensorlist.ckdGetSensorInitFuncList()5. 确认pSensorList指针指向kdSensorList起始地址若pSensorList被误赋值为NULL整个探测流程跳过mediatek/custom/vanzo89_wet_jb2/kernel/camera/camera/kd_camera_hw.ckdCISModulePowerOn()6. 为imx135添加专属 power sequenceVDD/VANA/VDIG/VIO/PDN/RESET 电压、时序7.camera_pdn_reverse逻辑适配若imx135PDN 为 active-high则camera_pdn_reverse0通用 power sequence 不适配imx135的 1.2V core voltage会导致 sensor 损坏5.2 HAL 层2 个文件4 个必改项文件路径关键点检查项为什么重要mediatek/custom/mt6589/hal/imgsensor/src/sensorlist.cppHAL sensor list8.ADD_SENSOR_ENTRY(IMX135_MIPI_RAW, imx135mipiraw)9.ADD_SENSOR_ENTRY(OV9724_MIPI_RAW, ov9724mipiraw)保持原有HAL 通过此 list 加载.so缺一项则对应 sensor 无法 openmediatek/custom/common/hal/imgsensor/inc/kd_camera_feature.hfeature ID 映射10.#define SENSOR_FEATURE_GET_SENSOR_ID_IMX135_MIPI_RAW SENSOR_FEATURE_GET_SENSOR_ID11.#define SENSOR_FEATURE_SET_FRAME_RATE_IMX135_MIPI_RAW SENSOR_FEATURE_SET_FRAME_RATEHAL 调用FEATURE_CONTROL时用此宏匹配 kernel 层的case宏名错则功能无效5.3 一键验证脚本check_sensor.sh3 行命令锁定问题层级写一个简单的 shell 脚本放在 adb root 后的/data/local/tmp/下可快速区分问题是出在 kernel、HAL 还是 app 层#!/system/bin/sh # check_sensor.sh echo Step 1: Check kernel sensor detection dmesg | grep -i imx135\|ov9724 | tail -10 echo Step 2: Check HAL sensor enumeration dumpsys media.camera | grep -A 5 CameraService echo Step 3: Check I2C device presence i2cdetect -y 0 | grep 30\|60\|70如果 Step 1 无输出 → kernel 层kdSensorList或Projectconfig.mk配置错误如果 Step 1 有[0][1][1][imx135mipiraw]Step 2 无imx135→ HAL 层sensorlist.cpp未添加或.so未编译如果 Step 1/2 都有Step 3 能扫到地址但预览黑 → 问题在 sensor driver 的open()/start_streaming()函数需抓logcat -s CameraService。6. 进阶技巧用mobilelog/kernel_log.boot定位 sensor 初始化时序一个表格搞定所有关键日志字段mobilelog/kernel_log.boot是 MTK camera 调试的“后悔药”。它记录了从 kernel start 到init进程启动前的所有 camera 相关 printk无需串口、无需重启只要adb shell抓取即可。但日志是海量的必须知道抓哪几行、看哪几个字段。我将imx111/ov9724/ov8825的典型日志归纳为一张表覆盖 95% 的初始化问题。日志片段字段含义正常值示例异常表现排查方向[0][1][1][imx111mipiraw][32]pDrvIndex[0]后摄模式探测kdSensorList[0][0][1][1][imx111mipiraw][32][0][1][1][unknown][32]或缺失kd_sensorlist.h中 sensor name 拼写错误Projectconfig.mk未包含该 sensor[0][2][2][ov9724mipiraw][32]pDrvIndex[0]前摄模式探测kdSensorList[1][0][2][2][ov9724mipiraw][32][0][2][2][ov9724mipiraw][32]重复出现两次camera_pdn_reverse被意外置 1导致前摄轮次误激活后摄 sensorkdCISModulePowerOn: VANA2.80V, VDIG1.20VkdCISModulePowerOn()输出的实测电压VANA2.80VVANA0.00V或VANA1.80Vpower sequence 中VANA的 regulator name 错误如vccana写成vcc_ana或硬件供电未焊好IMX111_MIPI_RAW_GetSensorID: read ID0x1110sensor driver 的GetSensorID()成功返回read ID0x1110read ID0x0000或read ID0xffffI2C address 错sensor 未上电PDN/RESET 问题I2C bus speed 过高ov9724需 ≤100kHzkdSetDriver: drvIdx0x00010001, ret0kdSetDriver()返回值ret0成功ret-1或ret-22kdSensorList[0].pFunct为 NULLGetSensorID()返回非ERROR_NONE实操技巧在kd_camera_hw.c的kdCISModulePowerOn()开头和结尾各加一行printk(KERN_INFO kdCISModulePowerOn: start/finish for %s\n, sensor_name);在GetSensorID()开头加printk(KERN_INFO %s_GetSensorID: start\n, __func__);。这样当你看到kernel_log.boot中kdCISModulePowerOn: start for imx111mipiraw之后没有kdCISModulePowerOn: finish for imx111mipiraw就知道卡在上电序列的某一步——立刻去查gpio_set_value()的 pin number 是否与 DTS 中定义一致。从那以后我每次 add new sensor都强制走一遍这个 checklist先grepkernel_log.boot确认[0][1][1]出现再i2cdetect确认地址最后dumpsys media.camera看 HAL 枚举。少一次漏检就少一次凌晨三点抓 log 的崩溃。希望帮到你。本文还有配套的精品资源点击获取
返回列表