资讯详情

资讯详情

高通Camera驱动调试实战:从日志到硬件信号定位问题

1. 高通Camera驱动调试的全貌先搞清楚你在调什么做高通平台Camera驱动调试的同学应该都有类似的体验项目一开最怕听到摄像头点不亮这五个字。但更怕的是拿到板子后不知道怎么下手第一反应就是改设备树、改dtsi、换sensor驱动改到天荒地老还不知道问题出在哪。我做了几年高通平台的BSP和Camera bring-up有个特别深的感触高通Camera驱动调试真正的门槛不在于你会不会改代码而在于脑海里有没有一张完整的软件分层和问题分类地图。没有这张图你就是在黑箱里猜有了这张图每个问题都能在几分钟内定位到具体模块剩下的就是按步骤验证。1.1 先梳理软件栈从kernel到HAL每一层都干点啥从底层往上高通Camera软件栈大概分成这么几块Kernel侧驱动主要是cam_sensor、cam_cciI2C控制器、cam_csiphyMIPI物理层、cam_isp、cam_icp等。sensor的上电、复位、时钟、I2C读写、MIPI CSI的初始化都在这一层完成。你常改的cam_sensor设备树节点、上电时序的power-down和reset序列就是在这里生效的。HAL层高通从Android 8.0之后全面切到了CAMXCamera eXtension架构对应的HAL实现叫camx。这一层负责整个Camera pipeline的搭建包括sensor的打开、stream on/off、ISP的tuning、3A算法的调度等。camx的日志开关、camxoverridesettings.txt这个文件是调试阶段接触最多的东西。chi-cdk层这是CAMX之上的可配置层用来做sensor的定制化适配。每个sensor的.cpp文件、CHromatix参数、camxsettings里面的feature配置都在这一层。通俗点说camx是框架chi-cdk是插件。应用/框架层cameraserver、provider、App的调用栈。很多看起来像驱动问题的卡顿、黑屏往上追几层会发现其实只是上层没发stream。在kalamaSM8550这类较新的平台上CAMX的版本和逻辑和老的SM8250时代已经有不少差异比如sensor probe流程、power domain的划分、以及对cam_sensor子系统的改动。但整体套路还是一致的核心能力仍然是会看日志、会读寄存器、会看时序、会抓现场。1.2 问题分类决定了调试手段我习惯先把Camera驱动的问题分成五大类每一类对应的调试手段完全不一样问题类型典型现象主要调试手段枚举失败no camera are attached、无法打开sensor设备树、I2C、寄存器、上电时序出图失败stream on失败、黑屏、数据错误MIPI信号、CSI配置、ISP日志稳定性问题掉帧、crash、卡死、重启内核日志、ramdump、QSR工具性能问题帧率不足、功耗高、带宽爆时间戳分析、带宽工具、perf采样效果问题偏色、过曝、对焦不准raw dump、3A日志、tuning调整很多新人拿到问题会直接开改但经验做法是先通过现象反推属于哪一类再用对应的手段去缩小范围最后才动手改代码。这样改起来心里有底验证起来也明确。比如枚举失败的问题你花一个小时去调ISP的tuning参数方向就完全反了。1.3 硬件链路不能只靠猜软件调试再溜也绕不开硬件。Camera这条链路的硬件部分相对固定sensor通过MIPI CSI接口接到SoC的CSIPHY控制信号走CCII2C电源部分通常由PMIC GPIO或者外部LDO控制再加上一根MCLK和若干根GPIOPWDN、RESET。这几个环节任何一个有问题最后表现出来的都是读不到sensor ID或者stream on超时。所以我给自己定了一条规矩软件日志定位到具体的硬件链路之后一定要用万用表、示波器或逻辑分析仪做二次确认。比如读到sensor ID失败我改代码前会先去量PWDN是不是正确拉高了、RESET有没有被误拉低、供电管脚上电瞬间有没有塌陷。这种习惯帮我少走了很多弯路因为有时候sensor没起来不是驱动写得不对而是硬件上某一根线虚焊或者供电被其他模块抢了。2. 日志与寄存器读写日复一日的主力调试手段说实话Camera驱动调试玩到最后真正天天用的就两样东西日志和寄存器。别被调试技术大全这种词吓到技术含量不在于会用啥高大上的工具而在于你知道什么场景该开什么日志、什么现象该读哪个寄存器。2.1 日志开关从logcat到kernel log逐个排查先说最常用的三个日志入口第一个是logcat。CAMX的日志默认通过logcat输出标签一般是CamX、ChiNode、cameraserver。用下面的命令抓adb logcat -c adb logcat -v threadtime | grep -E CamX|ChiNode|cameraserver camx.log但默认的log级别往往不够细需要用camxoverridesettings.txt把特定组的日志级别开到Verbose。这个文件放在vendor的/vendor/etc/下或者通过adb push进去。常见配置类似enableAllOverridesTRUE logLevel3 overrideLogOutputs0 perfLogsTRUE记得设置完要setprop persist.vendor.camera.experimental 1然后重启cameraserver或者直接重启机器否则不生效。日志级别从0到4数字越大越详细但3和4产生的日志量非常大抓的时候注意别把串口刷爆。第二个是kernel log。sensor驱动、CCI控制器、CSIPHY、ISP的驱动主要打印在dmesg里adb shell dmesg | grep -E cam_sensor|cam_cci|cam_csiphy|cam_isp像sensor probe成功、CCI读写超时、MIPI报错这类信息都会在这里。有一个坑我踩过好多次kernel log的环形缓冲区默认比较小Camera出问题的时候很多早期打印会被覆盖掉。建议在产品开发阶段就把logcat的sensor日志级别开大或者用pstore/ramoops把内核日志保留到重启之后。第三个是sensor驱动自己的日志。每个sensor适配的时候驱动里会留很多CAM_ERR、CAM_INFO之类的打印但这些默认可能不开。我一般会在bring-up阶段直接把pr_err级别的sensor相关打印全打开虽然有点刷屏但排查起来真的快。2.2 寄存器级调试直接和硬件对话日志只能告诉你出问题了要定位问题还是得靠寄存器。内核态读寄存器最常用的还是devmem或者专门的CCI工具。高通平台一般支持直接操作物理地址I2C的寄存器则要通过sensor驱动里的debug接口或者临时改代码加打印。比如确认sensor ID是否正常可以在cam_sensor驱动的probe流程里加一条i2c read的打印看读回来的值和datasheet对不对得上。用户态看寄存器CAMX提供了不少debug手段。比如通过adb shell dumpsys media.camera能看到当前Camera的总体状态再细一点可以看MIPI CSI的CSIPHY寄存器、ISP的cam_isp寄存器等。大部分平台上这些寄存器地址是固定的可以直接用devmem读但要先关掉相关power domain否则读出来全是0。这个坑我踩过当时读ISP寄存器全是0还以为是基地址写错了后来才发现是没先开CAM电源。Trace32劳特巴赫在高通Camera调试里也是利器。接上JTAG之后可以直接挂到SoC上看内存、改寄存器、打断点尤其在查crash或者死锁的时候比堆日志高效得多。不过Trace32成本高很多公司不一定配。如果手头没有用高通的QSR/QDMP工具链也一样能达到类似目的只是没有图形界面那么直观。2.3 实操案例I2C读不到sensor ID的快速定位我调过一个sensor现象是枚举阶段读ID失败。当时我没有急着改驱动而是按这个顺序排查先看设备树里sensor的节点是否匹配、GPIO和供电是否正确在sensor power on之后、read id之前用示波器量PWDN和RESET的波形是否符合sensor的手册要求手动通过CCI工具或者临时代码读I2C地址确认芯片本身是否存在如果I2C能读到但读ID失败那就是ID地址或者寄存器地址写错了如果I2C完全无ACK基本就是供电/复位/时钟的问题。最后发现是RESET信号被其他模块的GPIO复用导致复位时序不对。这类问题不改一行代码纯靠日志和寄存器就能定位清楚。很多时候我们觉得驱动难调其实是因为缺少这种逐层排除的思路。3. 从no camera are attached开始的典型定位链路凡是做过高通平台bring-up的同学对no camera are attached这句话都不陌生。这句话出现在logcat里时意味着CAMX在枚举阶段没有探测到任何可用的Camera设备。对就是那个著名的没有摄像头连接。3.1 这句话的完整产生过程按照CAMX的流程开机后camx会通过SensorManager去扫描系统里注册的所有sensor。每个sensor在设备树里对应一个cam_sensor节点CAMX会按顺序去.probe它们。probe的过程简单说就是给sensor上电、拉复位、等MCLK稳定、然后通过CCI/I2C去读sensor的出厂ID。如果ID和驱动里slaveInfo配置的一致就认为这个sensor存在如果读不到或者ID不对就判定这个sensor不存在。当所有sensor都没被成功判定存在时就会报no camera are attached。所以这句话的本意是我尝试了所有注册过的sensor没有一个能通过I2C读到ID而不是字面上的没插摄像头。从前面的流程也能看出来读不到ID是个结果真正的原因可能是电源没起来、时钟没给、GPIO被拉错、I2C不通、sensor本身挂了任何一个环节。定位的思路就是把前面这几个环节挨个验证一遍。3.2 一条我常用的排查链路我把这套排查链路固定下来了遇到no camera第一反应就按这个走第一步确认sensor驱动是否加载。在内核日志里找cam_sensor的probe信息确认对应sensor的compatible是否匹配。设备树节点名字和驱动里的of_match_table完全对应不上后面全白搭。第二步确认sensor是否上电。看设备树里sensor的供电配置gpio和regulator是否都在probe时成功请求。常见问题是一个GPIO被两个node共用或者某个regulator在别的驱动里已经被关掉。第三步抓上电时序。这个最直观拿示波器抓PWDN、RESET、MCLK三个信号。注意sensor的手册一般会给明确的时序要求比如PWDN拉高至少10ms后RESET才能拉高代码里用的是usleep_range还是mdelay差了数量级也会出问题。kalama平台上sensor的clock和power管理比老平台更严格有些sensor在MCLK没稳定的情况下直接读ID就是0xFF。第四步验证I2C通路。如果前三步都正常那就要确认CCI有没有通。最简单的方法是找一个已知能用的sensor对比或者用逻辑分析仪抓I2C波形。抓I2C时序要注意地址很多sensor支持7位和8位两种地址写法设备树和CAMX配置里搞错了就会出现写正常、读失败的现象。第五步确认sensor ID配置。如果I2C通了但读到的ID和驱动配置不一致就要检查xxx_sensor.cpp里的slaveInfo.slaveAddress和regAddr、regData. 有些sensor的ID寄存器不止一个比如OV系列有regAddr0x300A这种位置配置时少了一位就前功尽弃。3.3 实战案例kalama平台上sensor probe失败的尴尬问题在调一块kalamaSM8550平台的项目时遇到一个很有意思的情况所有sensor在开机后第一次枚举都是成功的但只要进行过一次camera close再重新打开就会报no camera are attached。日志里能看到sensor power off的流程正常走完但camera open的第二次probe阶段sensor ID读出来是0xFF。后来用示波器抓时序才发现第二次上电时PWDN和RESET的拉高顺序出现了毛刺原因是GPIO的驱动能力和上拉配置在第一次close之后被重置了。改dtsi里GPIO的input-enable和bias-pull-down配置之后问题解决。这个故事说明什么日志和信息够多的情况下这种非常规问题也能快速收敛。如果你只盯着CAMX的Error code看很可能永远卡在为什么第二次ID读失败上而脱离硬件信号单独调软件方向就是错的。3.4 示波器和逻辑分析仪是第二双眼睛软件工程师对示波器往往有天然的抗拒但Camera调试躲不开。我的建议是不需要精通能看懂三样就足够了GPIO的高低电平时序、MCLK的频率和稳定度、I2C的ACK信号。逻辑分析仪更简单接在CCI的SCL和SDA上把抓到的波形导出来用软件解析一下就能看到I2C总线上每个ACK和NACK的位置。有句话想多说一句很多疑难杂症最后都是硬件问题。软件日志看到MIPI信号CRC error频繁早一点上示波器看CSIPHY的差分信号质量可能半小时就定位到阻抗匹配的问题省得在代码层面反复纠结。4. 稳定性问题卡死、重启与硬件异常的系统排查稳定性问题是最让人头疼的因为它不像枚举失败那样有明显的起始点。常见现象包括Camera预览一段时间后画面卡住、系统watchdog重启、camera进程crash、或者整机直接死机。这类问题的特点是没有统一的报错信息必须靠日志和现场还原去推断。4.1 稳定性问题的几个常见形态第一种是听不到SOFStart of Frame。CAMX在stream on之后会持续等sensor通过MIPI发过来的帧同步信号如果SOF超时驱动会报Sensor stream on timeout。导致SOF丢失的原因很多MIPI信号不稳定、sensor的MIPI参数配错、时钟频率不够、甚至CSI的电压域配置不对。这种问题的排查我会先在dmesg里看CSIPHY的错误计数。第二种是ISP或者ICP处理超时。表现为cam_isp的handler的done中断没有按时回来。日志会显示ProcessRequest超时。这种问题往往不是sensor问题而是ISP的带宽不够、tuning参数导致处理时间超出帧周期、或者memory fragment导致buffer分配失败。第三种是camera进程crash。这种最好查logcat里直接有backtrace定位到具体函数之后基本就是空指针、数组越界、死锁。在CAMX里很多crash和feature的开关有关系比如开了一个不支持的HDR或者raw档位代码走到了未定义分支。4.2 从kernel panic到CAMX错误码日志里的破案线索遇到稳定性问题我一般会先抓三类日志logcat -b crash看cameraserver或者其他相关进程有没有native crashdmesg看kernel有没有panic、watchdog、page fault、以及其他BSP相关错误CAMX的perfLogs和错误级日志看具体的错误码是CamxResultEInvalidState还是CamxResultETimeout。这里要特别推荐高通的ramdump机制。如果系统在Camera场景下直接死机重启不要急着开机先在EMMC/UFS里抓ramdump。高通平台提供了ramdump工具链连接EDL模式之后可以把崩溃现场的内存全部倒出来查当时Kamd各个线程的调用栈。配合Trace32或者qsr工具能快速定位死锁、崩溃、异常中断的原因。我处理过一个典型的卡死问题Camera长时间预览之后CamX::Node的一个worker线程卡在等待sensor stream on的semaphore上而sensor驱动却永远没有回事件。最后通过ramdump看到线程栈停留在wait_for_completion而对应的硬件中断却没触发结论是sensor在长时间工作后MIPI信号质量下降导致间歇性断开。这类问题光看日志很难看到真相ramdump提供的现场信息是决定性的。4.3 硬件不稳定MIPI信号、供电纹波与raw dump验证软件查到一定程度如果现象是偶发随机就要考虑硬件稳定性了。MIPI信号质量不好会在CSIPHY的日志里看到大量的ECC error或CRC error。如果sensor和SoC之间的PCB走线太长或者阻抗不连续信号反射会造成这些错误计数器不断增加。这种问题软件只能缓解根治要靠硬件改版但调试阶段可以用降低MIPI速率、调整时钟相位来临时规避。供电纹波是另一个隐形杀手。我之前在一个项目里遇到过Camera在低亮度场景下偶尔黑屏查了快两天最后用示波器测sensor的AVDD发现低亮度时sensor功耗变化电源纹波飙到了80mV超过sensor手册要求的50mV上限导致内部LDO瞬间跌落。后来在供电线上加了一个10uF的电容问题当场消失。这种排查思路是先把现象和外部环境对上再去怀疑代码。raw dump是验证硬件链路是否稳定的最直接办法。通过CAMX的dump功能直接抓sensor输出的raw图如果raw图上出现固定的条纹、坏点、或者半屏偏色说明sensor的数据本身就不干净。如果raw图干净但经过ISP后图像异常那就是ISP或tuning的问题。这个判断可以帮你把问题从像素级直接切到模块级。5. 性能与图像质量帧率、带宽与3A调优中的调试视角很多人以为Camera调完能出图就万事大吉实际上产品化阶段更多的精力花在性能帧率、功耗、内存和图像质量色彩、对焦、曝光上。这两个方向也需要一套特定的调试手段。5.1 帧率问题先把数字算清楚帧率不够的排查最关键的是拿到准确的帧间隔时间。CAMX在perf log里会打印每一帧的SOF、SOF_to_sof、RequestDone时间戳。如果SOF_to_sof稳定在33.3ms但实际预览卡顿说明瓶颈不在sensor而在后面的ISP或者HAL处理。我一般会把几十帧的SOF_to_sof和RequestDone_to_RequestDone时间戳拉出来对比。如果后者明显大于前者说明pipeline的处理速度跟不上帧率这时要去看ISP的tuning里有没有配了昂贵的算法、或者3A的处理耗时。如果连SOF_to_sof都大于理论帧周期那就是sensor的上帧率没配对或者sensor的MIPI速率不足以支撑当前的分辨率和帧率。计算MIPI带宽是否足够有个简单的公式每帧数据量大约是分辨率 × 位深 / 8RAW10就是10bit算RAW12就按12bit算乘以帧率再加上5%~10%的空闲余量就是MIPI实际需要的速率。如果这个速率接近甚至超过运行的CSIPHY的lane配置上限瓶颈就不言而喻了。5.2 DDR带宽与ISP频率性能瓶颈的另两个大头Camera是个吃带宽的大户尤其在多摄、高分辨率、高帧率的场景下。高通平台的CAMX里可以用dumpCamx或者perfLogs输出每一帧DDR带宽的统计。如果在日志里看到带宽超过平台预算就要考虑降低ISP中间buffer的位宽、开启compression、或者降低某路video的分辨率。ISP频率的调整一般放在devconfig或者tops配置里。高通的ISP频率根据场景自动调但如果调度的策略太激进在某个分辨率组合下ISP频率上不去就会出现处理超时。排查办法是把ISP频率固定到最高测试如果问题消失基本就是频率调度策略的问题而不是硬件不够。这里分享一个小经验调性能问题时一定要把日志里的时间和数字量化不要凭感觉。比如感觉卡顿和帧间隔时间从33.3ms涨到60ms是两个完全不同的调试起点。量化之后问题从玄学变成了计算题。5.3 3A调试曝光、白平衡、对焦的日志视角3AAE/AWB/AF调试也是Camera驱动工作里很大的一块。很多效果问题看起来是tuning问题但它的根子在驱动配置。AE和AWB的日志主要通过Engine日志开关打开。比如AE的NRTNeural Real-time算法跑得不对会导致曝光收敛慢或者来回抖动AWB在复杂光源下偏色往往需要看AWB模块的置信度和候选光源数量。这些日志在CAMX里是有开关的可以通过camxoverridesettings里的enable3ALog等字段打开。AF调试比较痛苦的场景是对焦慢或者拉风箱。排查的逻辑是先看AF的VCM驱动的步进值和速度是否正确再看PDAF置信度数据是否正常。很多AF问题其实是sensor的PDAF配置错误比如pixel的孔径和位置间距填反了导致计算的相位差方向都反了整个AF算法玩不转。5.4 图像质量raw图和双摄对比法效果问题里拍照偏色、噪点多、锐化过度这类问题工具上主要靠raw图。高通平台提供了在dumpsys里触发raw dump的方式或者在chi-cdk的override配置文件里打开dumpRawTRUE跑一段时间之后在指定目录下就会生成raw文件。拿到raw之后用工具如DCRAW、Python的rawpy、或者厂商的RAW分析工具转成图像先判断数据源是否正常。如果raw本身偏色那就是AWB的统计源头问题如果raw正常但最终JPEG偏色那就是tuning的AWB模块或者ColorCorrection的问题。这个链条一定要分清不然容易被各种参数绕晕。双摄对比法也很有用同一个场景用一颗已知正常的sensor和一颗有问题的sensor各拍一张raw对比两者在相同光照下的响应曲线。两颗sensor的raw数据差异明显时多半是sensor寄存器的曝光、增益配置不一致。6. 调试环境与工具链的坑串口、下载模式与远程调试Camera驱动调试除了代码和信号还有一个前端问题调试环境本身搭不起来啥都白搭。很多同学在项目初期光捣鼓环境就耗掉两三天这些坑我先替你踩过。6.1 串口驱动与权限最常见的隐形绊脚石高通平台调试标配是USB转串口常见的芯片有CH340、CP2102、FTDIFT231X等。这些芯片在Windows下都有驱动但Linux下往往会遇到问题。比如CH340在部分内核版本里需要手动加载ch341模块CP210x系列的驱动比较全但有的发行版需要从厂商包安装FTDI的芯片在个别主板上会被识别成USB Serial而不是FT232R这时候要检查是不是芯片本身有问题。Linux下的串口权限是另一个坑。默认情况下普通用户没有权限读写/dev/ttyUSB0需要把自己加入dialout组或者临时用sudo chmod 666 /dev/ttyUSB0. 否则你用minicom或screen打开串口看到的全是乱码或者根本没反应。还有个小细节串口的波特率别设错了。高通的bootloader和kernel日志通常走115200但有些平台fastboot阶段是921600两者之间不统一会导致日志断断续续。我用过一台设备因为线缆的屏蔽不好长距离传输时串口数据会丢字节后来换了一条屏蔽线才稳定。硬件环境这种事看起来不起眼影响却极大。6.2 EDL 9008下载模式刷不死系统的高通专属通道高通平台的救砖和刷写基本都靠EDLEmergency Download模式也叫Qualcomm HS-USB QDLoader 9008。进入EDL的方式有很多关机状态下按住特定组合键、使用adb reboot edl、或者在bootloader里进入。进入后PC设备管理器里会出现Qualcomm HS-USB QDLoader 9008设备。EDL刷机的核心是分区表。高通平台一般用QFirehose或者QFIL刷写刷的时候会按照gpt_both0.bin这个分区表写。这个分区表相当重要搞错了就会把整个系统的分区布局打乱所以一定要用和你机器对应版本的boot和引导文件。persist、misc、vendor_boot这几个分区也要小心Camera驱动涉及的很多配置就在vendor_boot里。我经历过一次尴尬把一个vendor_boot刷出问题后机器起不来只能用EDL重刷整个镜像。刷完之后所有vendor分区全被覆盖之前调好的sensor配置也没了。从那以后我每次动vendor相关分区之前都会先把vendor_boot.img、dtbo.img、boot.img单独做一份备份。6.3 不依赖线缆的调试手段adb over network与日志落盘经常有同学问调试Camera的时候总是需要插USB线拿Log太麻烦有没有更舒服的办法有。Android设备可以开adb网络调试adb tcpip 5555 adb connect device_ip:5555这样之后你就可以通过Wi-Fi直接抓logcat、push/pull文件不用一直插着USB。尤其在测一些需要拿着设备到处跑的用例比如拍照、录像、追踪对焦时网络调试舒服太多了。还有一种做法是把日志直接落盘到设备内部存储之后在pc上离线分析。比如使用adb shell logcat -v threadtime -f /data/local/tmp/camx.log -r 10240 -n 5这样即使你不在设备旁边也能保证日志被持续记录下来。运行完把文件拉出来adb pull /data/local/tmp/camx.log回溯现场非常高效。嗯关于启动模式再补充一句如果你调的是Ubuntu主机adb偶尔会出现无法识别设备的情况多半是udev规则没配置好。把高通设备的VID:0x05C6、PID:0x9008EDL和0x900Efastboot都加进/etc/udev/rules.d/里重启udev服务基本上都能解决。我在实际调试中最深的体会是Camera驱动调试这个事七分靠读代码和日志三分靠硬件测量和工具辅助。每个问题都像破案日志是现场指纹寄存器是物证逻辑分析仪是监控录像。把这些手段组合起来疑难杂症也能一步步还原出真相。最后分享一个我自己一直在用的小习惯每调完一个sensor或一个平台就把上电时序、寄存器配置、关键GPIO的定义和调试过程中踩过的坑整理成一张表格。下次遇到类似问题直接翻表格就能快速回忆起当时的排查思路不用每次从零开始。这个习惯帮我省下的时间比我花在整理上的时间多得多。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →