做高通Camera驱动调试这几年,我最大的感受是:这活儿看着杂,其实套路很固定。
不管你是刚接手Sensor bringup的新人,还是被预览黑屏、对焦乱跑、帧率掉到十几帧折磨的老手,高通平台Camera调试的核心就三件事——先把log抓对,再按套路定位,最后用工具和寄存器数据验证。今天我把这些年用过的调试方法、踩过的坑、还有那些文档里不会写的路子一次性理清楚,希望能给你省点时间。
1. 高通Camera驱动调试,到底在调什么?
1.1 先把Camera驱动这层皮扒开
很多新同事拿到高通平台第一反应是懵:Camera相关的代码目录多得吓人,vendor/qcom/proprietary/camx、chi-cdk、kernel/msm-5.x/drivers/media/platform/camx,还有techpack/camera,根本不知道从哪儿下手。
我一般喜欢打个比方:高通Camera驱动是一个三层楼的结构。最底层是Kernel驱动,负责和硬件打交道,I2C读写Sensor寄存器、MIPI收数据、电源和时钟控制、GPIO上下电,全在这层;中间层是CamX(Camera eXtension),这是高通私有的用户态框架核心,负责管Pipeline、Node、Request、Buffer,相当于调度中枢;最顶层是chi-cdk(Camera Hardware Interface CDK),这是给厂商做定制扩展的地方,sensor的配置文件、tuning、feature的override,都写在这层。
调试问题之前,你心里得明白问题可能出在哪层。比如开机黑屏,如果Kernel log里Sensor ID都读不到,那大概率是底层I2C或电源时序问题;如果Kernel log正常,sensor能出数,但上层预览黑,那就要去CamX和chi-cdk里查Pipeline和buffer flow。最怕的就是不管三七二十一,直接在logcat里瞎翻,那是纯靠运气。
我建议所有做高通Camera调试的人,先花半天时间把camx/src/core、chi-cdk/oem/qcom/topology、kernel/drivers/media/platform/camx这几个目录的结构过一遍,不要求全看懂,但至少知道每个子目录是干嘛的。否则后面看长log时会非常痛苦——你根本不知道CamX打印的那条WARNING是致命错误还是无关痛痒的提示。
1.2 调试的本质:一条log看穿三端
以前调试Sensor bringup的时候,我习惯同时开三个终端窗口:一个抓logcat,一个抓dmesg(也就是Kernel log),一个挂在串口调试助手上抓底层硬件报错。
为什么要三路同时抓?因为Camera链路的日志分属不同的输出通道。CamX和chi-cdk的日志走logcat,Tag一般是CamX、CHIUSECASE、CHICPV之类的;Kernel侧的驱动日志走dmesg,文件节点是/dev/log/kernel;而硬件相关的紧急报错、总线错误、fatal信息,有些会打到主串口上,特别是刷机阶段或者Kernel早起的初始化打印,logcat根本来不及开。
给新人的建议是:抓log要按问题来选通道,而不是全抓。做sensor bringup,重点抓dmesg和串口;做3A、tuning、图像效果问题,重点抓logcat里CamX和CHI的log;做稳定性测试(长时间预览、反复进退出Camera),三个通道全抓。而且logcat抓的时候最好加-v threadtime,不然多线程日志根本对不上时序。
另外一个很实用的技巧,在logcat里加-b all通道。高通Camera的不少缓冲区相关报错(比如buffer underrun、request timeout)会打到events和crash通道里,只抓main和system是看不到的。我调试过一个很隐蔽的预览卡顿问题,最后就是在logcat -b events -v threadtime里看到连续几条CHI_USECASE: request timeout,才定位到是overflow request超时被drop了。
2. 调试套路:从log到dump的完整打法
2.1 日志分级:哪些log是你真正需要的
每次有同事拿着几MB的logcat来找我说“帮我看看Camera有什么问题”,我都头大。没开Camera日志级别、没做任何过滤的大log,基本等于噪音,我通常是先问一句:你抓的是debug级别还是info级别?
高通CamX的日志级别是可以动态调整的,常见做法是用property控制,比如adb shell setprop persist.vendor.camera.debug.loglevel 2,数值越大日志越详细。更灵活的方法是只给某个模块开debug,比如想查sensor上报的数据对不对,就用adb shell setprop persist.vendor.camera.sensor.log 2;想查ISP pipeline就开persist.vendor.camera.isp.log;想查3A算法就找对应af/awb/ae的log开关。
真正的干货是:不要看全部log,要看“第一次报错前的那几行”以及“周期性重复报错的那几行”。高通Camera的错误上报有一个习惯,同一个error不会只打印一次,会伴随一些errno和handle。比如CamX: [ERROR][Core] CamxResult CHI... = 0x...,后面的数值非常重要,怎么查?在camx源码里搜CamxResult枚举定义(一般在camx/src/core/camxdefs.h或camxresult.h),就能对应到具体的错误码。
我的经验是,logcat里出现ERROR级别的日志不代表一定致命,很多Error后面会跟一个recovery动作,比如sensor error recovery直接re-init sensor。真正致命的是FATAL或者ASSERT,以及连续重复的timeout。新手判断问题严重性时,先看有没有FATAL,再看有没有反复出现的timeout,最后才看普通ERROR,这个顺序能帮你快速过滤掉干扰项。
2.2 抓log的姿势要正确
这里分享一个我固定使用的抓log流程,也是调试最常用的三板斧。
第一步,开日志并清空旧日志。执行adb logcat -c清空,然后用带时间戳的方式抓取:adb logcat -v threadtime > camx_log.txt 2>&1。如果是kernel log,用adb shell dmesg -w > kernel_log.txt。需要注意,dmesg在某些版本需要root权限,否则看不到Camera相关的打印。
第二步,如果是sensor bringup或者在跑功耗、休眠唤醒相关case,优先用串口调试助手抓。很多底层logcat抓不到。串口设置一般是115200-8-N-1,接好UART后把kernel log重定向到串口(在cmdline里加console=ttyMSM0,115200这类参数),这样从kernel起来的瞬间到sensor上电的每一步都能看到。我自己常年在工作台上放一个USB转串口模块,几乎每天都要用。
第三步,做问题复现,并在复现前后分别打点。比如你要测冷启动camera打开耗时,就在log里搜索CHIUSECASE的open和first frame相关tag,对比时间差;如果问题在持续预览几分钟后才出现,就在复现前做一次adb shell killall cameraserver,确保每次测的都是冷启动,避免上一条case污染数据。
另外,如果你身边没有USB线,可以用adb tcpip 5555开启adb无线调试,然后adb connect <IP>:5555。但这个在Camera调试里有个坑——无线adb传大log容易丢包,抓log时建议干脆落盘到设备端:adb shell "logcat -v threadtime -f /data/vendor/log/camera.txt",然后再adb pull出来。这个习惯能救你很多次,特别是碰到机器复现几分钟后自动重启的case。
2.3 崩溃和hang死时的核心dump解析
Camera问题里最让人头疼的两类:一个是cameraserver直接crash,一个是整个系统不崩溃但Camera死等(hang)。这两类都需要看dump,但方式不同。
先说crash。当cameraserver崩溃时,系统会生成tombstone,路径在/data/tombstones/,对应的log会在logcat里打出Fatal signal和backtrace。我拿到tombstone后会先做两件事:第一,用addr2line把so的偏移地址转成源码行号,命令类似addr2line -f -C -e vendor/lib64/hw/camera.qcom.so 0x12345;第二,检查崩溃时的调用栈是camx内部(通常是buffer或者request管理),还是chi-cdk的vendor扩展代码(一般是你自己写的feature)。如果是后者,检查你自定义代码的空指针和越界就对了。
再说hang。CamX在长时间没有完成request时会触发watchdog超时,打印SWFR(software frame request)相关的dump。常见场景是sensor不出数据,或者IFE处理卡住。这种时候优先看log里对应的Pipeline状态是Pending还是Active,然后看是哪个node没返回buffer。我记得调试一个8x50平台的问题,预览hang住后看log,发现是JPEGnode没拿到EBD(empty buffer done),最后查出来是JPEG硬件时钟频率太低,大量图像压缩超时。这种问题光看栈没用,一定要靠流程日志。
还有一类高通的专用ramdump分析工具,一般用在Kernel panic场景。我建议新人先别碰ramdump,先把logcat和tombstone看懂,已经能解决80%的Camera问题。
3. 图像问题的专业排查路径
3.1 黑屏、花屏、偏色:先定性再归因
图像问题基本逃不开这几类:黑屏、花屏/条纹、偏色/过曝/欠曝、清晰度差。我的习惯是拿到问题后先做“定性”——判断是链路问题、同步问题还是算法问题,再去细查。
黑屏问题的排查顺序,我建议严格按“sensor出数→ISP处理→显示”这条链路查。第一步确认sensor是否出数,看sensor寄存器里的frame counter或者直接dump raw data;第二步确认MIPI有没有数据到IFE,看CamX log里的CSIClient相关打印;第三步确认IFE/ISP是否完成处理,看是否有IFE的output buffer产出。卡在哪一步就从哪一步往后查。
花屏或条纹,优先怀疑MIPI数据同步和时钟问题。几种典型情况:条纹固定位置出现,可能是MIPI的lane mapping不对;画面滚动横纹,可能是sensor的曝光和帧同步信号(VSYNC)频率和平台配置不匹配;画面有周期性噪点,可能要关注MIPI时钟频率是否在平台支持范围外。MIPI时钟算错了是高频坑,我在RK平台调OV5695时也遇到过类似问题——mipi_freq配错半个数量级,预览直接全是雪花点。
偏色问题就复杂了,硬件、sensor、ISP算法都可能背锅。最简单的排除法是先用高通的chipidea或qcarcam工具直接出raw图,然后在PC上看raw图的白点是否正常。如果raw图色偏严重,那基本排除CamX上层的问题,往sensor/镜头/ISP去查;如果raw图正常但最终输出偏色,那问题大概率在3A和tuning配置上,重点查AWB的色温判断和gain范围。
3.2 对焦、曝光、3A收敛异常的tuning思路
3A问题里最经典的就是“对焦拉风箱”和“曝光来回跳”。这两个问题的本质都是算法在收敛过程中震荡,而非硬件坏了。
AF拉风箱时,我第一步会先关掉自动对焦,手动写一个AF position,看这个位置出图是否清晰。如果手动清晰、自动拉风箱,问题大概率是AF的search range和步长没配好。去chromatix里查AF相关配置,看search_frame的步长是否过大,以及lens position有没有做calibration——很多项目烧录的EEPROM里AF初始位置不对,会导致对焦在错误区间反复搜索。
AE曝光来回跳,这种问题经常出现导致预览忽明忽暗。先看曝光收敛曲线,高通有工具可以画AE convergence,如果没有工具,就在log里过滤AE相关tag,看exposure time和gain是否在两个值之间反复跳。常见原因是AE target(目标亮度)定太高,或者sensor的动态范围不够,导致算法在相邻两帧的曝光组合间来回振荡。这种问题调AE target比例或者放宽AE的convergence threshold都能缓解,但最根本的是看sensor的曝光步进是否平滑。
另外我特别想提醒一点:3A问题不要只盯着算法调,先确认sensor寄存器写入是否成功。我调试过一个某品牌sensor项目,AE一直收敛不了,查来查去发现是sensor对exposure寄存器写入有固定的trigger要求,CamX默认的写入时序不满足,导致每次写exposure都被sensor忽略了。这种问题在sensor datasheet里写得明明白白,但新手往往忽略而浪费时间调convergence参数。
3.3 预览卡顿和帧率异常的定位
预览卡顿在驱动侧通常有两个来源:buffer不足导致丢帧,sensor输出帧率本身不达标。
我排查帧率问题时,习惯先加一个最简单的帧计数验证。在CamX的node里打印frame_id的连续情况,看frame_id是否有跳号。如果频繁跳号,说明有帧被drop了,再去看drop是发生在sensor输出侧还是CamX的内部queue。如果frame_id连续但界面卡,那就查显示链路和buffer queue,跟Camera驱动的关联反而小了。
还有一个高通平台特有的概念叫SOF(Start of Frame)中断。如果SOF中断频率低于预期,从log里能看到类似sensor SOF timeout的报错。这种问题一般是sensor的vblank配置不当,或者MIPI时钟不够导致每帧传输时间过长。我在8550平台kalama项目上就遇到过这类问题,新驱动IC接入后帧率一直只有22fps,最后查下来是sensor的vts(vertical total size)没按60fps要求配,导致每帧周期比预期长了差不多30%。
遇到帧率不达标,先看sensor datasheet里的帧周期公式,对照寄存器里的HTS、VTS和MIPI速率算一遍,搞清楚理论帧率是多少,再去log里抓实际SOF频率。大部分帧率问题在数数阶段就能暴露出来。
4. 硬件联调:串口、电源、时序和信号完整性
4.1 串口调试助手与内核打印的关系
很多人觉得串口调试助手是单片机时代的东西,做Linux/Android调试用不上。这话大错特错。在高通Camera调试里,串口往往是最后一道救命稻草,特别是Kernel在启动早期或者已经panic的时候,logcat和adb全不可用,只有串口还能看到内核打印。
软件侧配合串口抓log的思路是:把内核printk通过console=参数输出到串口,这样从bootloader阶段开始,每一步init、每个驱动的probe、每个I2C传输失败,都会打到串口上。Camera驱动的probe顺序、电源通知、clk开启的这些信息,在dmesg里有时因为缓冲被覆盖而丢失,但在串口上是可以实时看到的。
实际操作建议,搞串口调试时别用裸串口工具直接看,建议用带时间戳和自动保存的调试助手,把原始数据同时存到文件里。因为串口打印速度很快,你盯着屏幕很容易错过关键行,回看文件对照时间戳才能还原现场。我现在那个串口工具就一直挂着自动保存,出问题直接翻文件。
4.2 上下电时序与GPIO/regulator确认
sensor无法出图或者出图异常,很大一部分原因出在上下电时序上,尤其是带独立AVDD/DOVDD/DVDD供电的sensor。
很多sensor的datasheet会给出上电时序图,比如AVDD先稳定,然后MCLK、然后是RESET释放,顺序反了sensor可能无法正常初始化。在高通平台,这些时序都是通过CamX的power setting配置的,每个sensor的power_conf里都有严格的sequence和delay。调试时如果sensor ID读不到,我第一步就是对照datasheet和power_conf,一项项比对每个电压是否在enable后等了足够的delay。
寄存器核对的方法:在sensor初始化日志里,搜power和gpio相关的打印,确认每个regulator的电压是否和计划一致,比如pm8994_l17输出1.8V、pm8994_lvs1切换IO口方向等。如果发现电压没起来,那就是电源配置或者硬件供电问题;如果电压起来但时序不对,那就要动power_conf里的delay参数。
4.3 MIPI信号和时钟问题的基本检查
图像花屏、条纹、颜色错乱,经常是MIPI物理层问题。作为驱动工程师,你不一定需要自己上手示波器,但至少要知道怎么用寄存器去判断链路好不好。
高通CamX里有MIPI的错误计数寄存器,在sensor和IFE的CSIC(Camera Serial Interface Controller)配置里,能看到类似EccErrorCount、CrcErrorCount、FrameSyncError之类的统计。如果CRC错误在持续增长,说明MIPI数据在传输过程中有误码,通常先检查lane的映射、时钟频率、以及供电纹波。如果CSI接收到的帧同步不完整,那就是同步信号问题,优先查sensor输出的frame_start/frame_end信号格式。
实战中我还遇到过一个奇葩问题:有时花屏,有时正常,最后发现是FPC排线过长,MIPI信号衰减导致在高温下误码率升高。这种硬件问题,软件只能靠错误计数日志来复现和确认,真正解决需要改硬件设计。如果CRC错误是偶发的,建议用长时间连续抓数、统计错误趋势的方法,比肉眼盯预览可靠得多。
5. 常用工具与平台特有调试手段
5.1 高通Camera调试工具箱盘点
先列一个我日常工作台必备的工具清单,基本覆盖99%的高通Camera调试场景:
| 工具/命令 | 主要用途 | 备注 |
|---|---|---|
adb logcat | 用户态日志、CamX/CHI日志 | 加-b all抓全通道 |
adb shell dmesg/ 串口 | Kernel日志、底层驱动报错 | 开console=输出到串口 |
adb shell cat /sys/kernel/debug/camera/* | sensor寄存器、clk状态 | 需root |
| CamX扩展命令 | 动态开关debug log | 搜persist.vendor.camera.*相关 |
| QPST / QFIL | 刷机、抓dump | 刷机小心,救砖用 |
| QACT | tuning参数调试 | 配合chromatix使用 |
adb shell getprop persist.vendor.camera. | 查看各种运行时状态 | 记得先setprop开debug |
adb shell "echo 0 > /sys/kernel/debug/msm_cam/xxx" | 强制复位某些模块 | 仅调试用 |
关于QPST和QFIL,这两个工具严格说是刷机工具,但在调试中有另一个重要作用:备份和恢复EOM(EEPROM/OTP)数据。很多sensor的af/awb校准数据存在EEPROM里,调试中若反复读写搞坏了,用QPST随时可以刷回来。我之前就在客户现场把一颗sensor的EEPROM写乱过,当时直接备份重刷救回来的。分区表和EDL(紧急下载模式)在火烤变砖时也是救命稻草,这里提醒一句:EDL模式下刷错分区表会直接把机器刷死,一定要备份原始分区表再动手。
5.2 EDL刷机和分区表对调试的作用
调试中确实会遇到把系统搞崩的情况,比如加载了一个错误的sensor驱动导致kernel panic,或者改tuning时写坏了某个分区。这时候EDL刷机就是最后的兜底。高通平台刷机主要是QFIL,刷之前务必选对分区表,并且备份persist和fota这类关键分区。
我还发现一个规律:很多Camera问题在SN(system)和vendor分区版本不一致时会被误判。比如改了CamX相关代码,但只刷了vendor没刷system,或者反过来,就会出现各种稀奇古怪的现象。遇到不明原因的问题,第一步先确认软件版本和分区版本是否匹配,这是纯经验,但真的能省很多冤枉时间。
5.3 与MTK平台的调试思路差异
有MTK平台经验的朋友转过来做高通,往往在前两个月都会有一段“水土不服”。我自己也是从MTK转过来的,所以特别能理解这种差异。
MTK平台的调试,很多是围绕imgsensor结构体和kd_imgsensor文件来的,sensor bringup通常只要把参数配进sensor list里,platform framework会把大部分逻辑处理好,调试也比较直接。但高通平台把大量行为拆到了CamX和chi-cdk两个层,sensor不仅要有驱动,还必须有配套的chromatix(算法调优参数)和testdata,否则即使sensor out了图,效果也很烂。这就是为什么高通的调试曲线比MTK陡——前期启动难,后期上限高。
MTK里通常用ispsys直接改某个寄存器去验证图像效果;高通里面则习惯通过chi-cdkoverride或者tuning修改来实现。所以做高通,一定要学会在rubik(高通官方tuning工具)、QACT和chromatix文件之间来回切换,这是一道绕不过去的坎。
6. 常见问题速查与案例复盘
6.1 高通Camera问题速查表
总结了一份我在项目中最常用的问题排查速查表,基本覆盖日常80%的调试场景:
| 现象 | 优先检查项 | 常见根因 |
|---|---|---|
| 开机后sensor ID读不到 | Kernel log里I2C是否报错;power_conf的上电顺序 | 电源时序错、I2C地址错、sensor没上电 |
| 预览全黑但log正常 | 检查CSIClient的MIPI接收是否有数据;raw dump看是否全0 | MIPI lane mapping、CSI接口配置错误 |
| 预览花屏/条纹 | 检查CRC/ECC错误计数;MIPI clock频率 | 走线干扰、时钟超频、lane map错 |
| 预览偏色 | raw图确认AWB是否正常;tuning里AWB gain范围 | AWB校准数据异常、镜头遮挡、tuning参数异常 |
| 对焦拉风箱 | 手动AF position验证;检查AF校准数据 | EEPROM丢失、AF search范围配置不当 |
| 曝光忽明忽暗 | 抓AE收敛曲线;检查exposure写入是否成功 | AE target/Tolerance配置、sensor曝光寄存器时序 |
| 预览掉帧/卡顿 | frame_id连续性;SOF中断频率 | VTS/HTS设置、buffer不足、request timeout |
| Camera打开慢 | 从CHIUSECASE log里找time cost | 3A预热、sensor初始化、buffer分配 |
| 拍照黑/绿图 | 检查ISP pipeline和JPEG编码 | 拍照pipeline配置错误、bayer格式不对 |
| 休眠唤醒后全黑 | 检查sensor suspend/resume流程 | 电源未完全关闭、寄存器状态未恢复 |
表格只是辅助记忆,真正定位问题还是离不开log和寄存器数据,千万不能对着表格猜答案。
6.2 三个典型案例复盘
挑三个我印象最深的case分享出来,都是能体现调试思路的。
案例一:sensor ID读不到,但硬件看起来没问题。
现象是一个OIS sensor上电后I2C read全返回失败。检查了power_conf的电源顺序、I2C地址、GPIO,都正常。最后用示波器量sensor的MCLK,发现MCLK的幅度只有0.8V左右,而sensor需要至少1.5V的高电平。后来查CamX的时钟配置,发现MCLK被配成了某个不正常的CLK源电压。根因是CamX对sensor的MCLK配置不当,导致时钟电平不够,sensor不能正常起来。这个case给我的教训是:sensor读不到ID,不能只看时序和电压,时钟电平一样重要。
案例二:预览正常,拍照后图片全绿色。
从log看拍照流程没有报错,ISP pipeline也都执行了,但输出的JPEG图全绿。后来对比预览和拍照两个pipeline的bayer pattern配置,发现拍照pipeline错误地配置了RGGB的bayer顺序,和sensor实际输出的bayer顺序不一致,导致ISP解出的颜色全乱。这个问题的关键点在于预览和拍照可能走的是不同pipeline node,它们的配置是独立维护的,改了一处不能默认另一处也一样。检查时务必分别确认。
案例三:长时间预览10分钟后突然黑屏。
这个问题抓了三天。log里没有任何crash信息,就是预览突然没画面了。后来在串口上发现一条被淹没的sensor error recovery日志,说明sensor曾经发生过error,CamX的recovery机制尝试resume,但resume失败了,所以黑屏。查下去才发现,sensor在长时间工作后在一颗寄存器的写入上偶发超时,问题根源是I2C总线上挂了多个设备,存在总线冲突。最后通过给sensor加独立的I2C总线解决了。这个case充分说明串口和错误日志的重要性,光靠logcat真的看不见这些底层的error recovery信息。
6.3 独家经验与避坑技巧
最后分享几条自己积累起来的实战经验,希望能帮后来者少踩坑。
第一,调试前先固化环境。无论是log级别、sensor配置还是tuning文件,每次调试之前先拍照存档,否则改了参数忘了改回来,很容易分不清问题到底是代码引入的还是环境引入的。
第二,别迷信高通默认配置。高通的sensor配置文件,是从参考项目copy过来的,不一定适配你的sensor。我见过很多项目在最终量产前才发现,sensor的vts、mipi_freq、power_conf里还留着参考sensor的参数。每一个参数都要对照datasheet核对,不要“看着像”就通过。
第三,log抓得再全,不如问题复现得稳定。如果问题不是必现,先花时间把复现路径稳定下来。稳定的复现路径比任何工具都有价值。
第四,克制直接改代码的冲动。碰到问题,先分析是配置问题还是代码问题。高通平台90%的Camera问题都是配置类问题,不是代码逻辑问题。优先查chromatix、power_conf、sensor寄存器配置,而不是一上来就改CamX源码。改源码一时爽,后期维护火葬场。
第五,多看sensor datasheet的寄存器说明。调试调试,本质上是把代码里的配置跟硬件行为对上号。没有任何工具能替代你对硬件的理解。datasheet里的每个寄存器都可能成为你排查问题的突破口,别跳过这步。
做高通Camera驱动调试,真正的核心竞争力是把Log读到脑子里形成“现状图”的能力——你看得越细,定位越快。希望这篇文章能帮你建立一套自己的调试框架。如果你在调试中遇到什么特别棘手的case,也欢迎来交流。