做MTK平台sensor调试也有些年头了踩过的坑比吃过的盐还多。最典型的一种场景是板子刚回来我看sensor的驱动代码写得清清楚楚I2C地址也对寄存器配置也照参考码来了但上层就是拿不到数据或者好不容易拿到数据了方向反了90度陀螺仪零漂大得吓人。这种问题在项目推送阶段出现往往会把原本一周的软件进度拖成两周。其实MTK sensor开发的门槛不在“会调I2C”或“会读寄存器”而在于你脑子里有没有一套完整的链路观念从硬件引脚、内核驱动、设备树/DWS到HAL层数据映射、校准算法再到Android的SensorService全都要串得起来。这篇文章就当作一个MTK sensor技能知识总结把我平时排查问题、移植新sensor、跨平台对比时用的那套思路和实操步骤写出来适合刚入门做驱动/HAL的兄弟也适合正在做项目移植、被方向校准和功耗问题折磨的朋友。1. MTK sensor开发到底在做什么1.1 sensor不是只有“加速度计”这一种很多新人一听到“MTK sensor”第一时间想到的就是手机里的加速度计、陀螺仪、光感、距离感应。这个理解没错但不完整。从项目实际接触到的类型来看至少可以分这么几类运动类加速度计Accelerometer、陀螺仪Gyroscope、磁力计Magnetometer这三者常组合成九轴惯性测量单元比如ICM-20602、LSM6DS3、AK09918这类芯片。环境类环境光传感器ALS比如TI的OPT3001、ams的TMD2772还有接近传感器Proximity、色温传感器、气压计Barometer、温湿度传感器。特殊功能类用于计步的sensor hub算法依赖的加速计、用于翻盖/霍尔感应的霍尔传感器还有一些平台新增的SAR比吸收率传感器主要用于通话时检测人体靠近。影像类摄像头模组里的CMOS image sensor比如OV5670、IMX358、S5K3P8这些也会被大家称为“sensor”但它们走的是MIPI/ISP通路跟运动类sensor的I2C输入子系统完全不同。上面这些在MTK平台上都可能出现在同一个软件仓库里但每一类调试方法天差地别。如果只盯着“我把驱动跑通了”这一个目标很容易漏掉功耗、方向、校准这些真正要命的事。1.2 MTK平台完整的sensor软件链路在MTK平台上一个正常数据上报的链路大概是这个样子的先是物理sensor芯片挂在I2C或SPI总线上通过中断GPIO告诉主控“我有新数据了”。内核驱动负责初始化芯片、配置寄存器、申请中断并通过input子系统或者MTK的sensor框架上报事件。再往上走MTK的sensor HAL层负责跟内核节点通信把底层上报的数据换算成Android SensorManager需要的坐标方向和单位。然后是SensorService它把感知数据分发给应用层。MTK很多平台其实是带协处理器的比如SCPSensor Control Processor——一个专门负责低功耗传感器数据采集和融合的小核心。当你配置了低功耗计步或者 always-on 功能后主CPU可以进休眠加速计和SCP之间保持连接由SCP做数据搬运和算法处理。所以MTK sensor开发不只是写一个驱动那么简单还要理解数据是走“直接到AP”还是路径经过SCP。这个区别直接影响功耗和数据延迟也是后期调低功耗最容易踩坑的地方。1.3 为什么我认为新人应该从驱动层入手我带过一些新人第一周就让他们去改HAL层结果改来改去发现数据没变化原因是底层根本没进数据。所以我一直建议新接触MTK sensor开发的人无论最终是做驱动还是做算法都先把驱动层的probe流程摸一遍I2C probe怎么走、chip id怎么读、中断怎么申请、上报的event怎么被打出来。把这条chain摸透了再往上层走就特别顺。另外一个原因MTK平台的驱动层与高通的Linux input驱动相比多了很多平台相关的资源管理逻辑例如DWS里的GPIO复用、电源域PMIC的LDO控制、设备休眠唤醒。这些内容如果不实际操作你是永远体会不到“一块板子亮不了机”和“sensor不工作”之间有多大的关联。2. 方案选型与平台差异MTK和高通到底有什么不同2.1 Sensor Hub与低功耗设计的思路差异同样做一个加速度计MTK和高通在框架上最大的差异体现在“谁去管理数据通路”。高通中高端平台一般有ADSP或者SLPISensors Low Power Island传感器通过I2C/SPI挂在DSP子系统上DSP里面跑sensor算法AP只用Socket去收数据。MTK那边则是SCP理念一样但配置和调测方式完全不同。我在实际项目里最直观的感受是MTK的GPIO和I2C通道由DWSDevice Work Sheet管理你要先用Excel或者工具生成DWS再编进preloader或者lk里高通则是用设备树dtsi里的pinctrl去配置习惯完全不一样。MTK的HAL层分为“传感器驱动”和“算法库”两块很多算法计步、姿态不是写死在HAL里的而是通过传感器数据进SCP后由算法库算出来高通更倾向用ADSP内部的sensor processing framework。如果用表格对比大概是这样对比点MTK高通资源管理配置DWS device treedevice tree/ACPI低功耗协处理器SCPSensor Control ProcessorADSP/SLPI传感器驱动接入方式可通过input子系统或MTK自定义框架多数挂在DSP侧也有input方式数据时间戳获取HAL里从event time读取需注意时基DSP带专属时间戳时基相对统一功耗调试入口/sys/power/wakeup_sources需要关注SCP/sys/kernel/debug/msm_subsys等这个表不是说谁好谁坏而是在说如果你习惯了高通的调试方式跳到MTK项目时别拿高通的思路去硬套。最典型的坑是“我在高通里直接改dtsi就把GPIO配了为什么MTK里我改了dtsi却没用”因为你还需要同步生成/编译DWS并且在DWS里正确配置上拉电阻和复用模式。2.2 DWS设置与GPIO资源分配到底怎么配接到一个新MTK项目的sensor调试任务时第一件事不是去看代码而是先打开原理图找到sensor用的I2C总线、中断GPIO、供电LDO在PMIC上的通道。然后你再去改DWS。DWS里需要配置的内容一般包括sensor挂在哪条I2C bus上I2C channel number。中断脚对应的GPIO有没有做上拉输入模式还是输出模式。供电脚是PMIC LDO还是GPIO控制的开关是否常开还是可以软件控制。某些平台还需要配置传感器复位脚的GPIO避免复位方向反了导致sensor一直处于复位状态。操作上常见是把DWS生成到一个dws文件里再通过mtk的配置工具转换到kernel的dts/dtsi中。编译时DWS会跟着boot image一起刷进机器。我踩过的坑是我在DWS里把一个本来用于TP中断的GPIO复用给了光感结果触摸屏和光感不能同时工作开机一会儿就漂。后面查DWS才发现是同一组gpio两个模块都申请了。所以在配置DWS的policePINMUX时务必交叉检查同一个GPIO在其它模块里的占用情况。2.3 ISP sensor选型与AEC这类“隐藏烧脑点”除了运动和环境sensor影像sensor在MTK项目里也经常听到。常用ISP sensor的选型如果你是做整机的会关心分辨率、像元大小、HDR能力、帧率和支持的MIPI lane数。举个例子做前摄美颜效果的通常会挑支持RAW输出的高像素sensor方便算法调做后摄主摄的一般要求大像元和高动态范围像OV50系列或者三星的S5K系列。AECAuto Exposure Control在camera sensor里和运动sensor不是一个概念它是3A流程里负责自动曝光控制的部分。MTK平台和高通平台上AEC的差异主要体现在统计数据和调优接口上MTK的ISP驱动提供AE统计算法通过Polling统计值去调整曝光和增益高通则有一套CAMSS(相机子系统)的标准化流程很多参数在Chromatix里配置。对普通sensor工程师来说知道这个区别能帮你在跨平台项目时少走弯路——不要以为MTK的AE参数表可以原封不动搬到高通。不过别被ISP sensor的复杂度吓到。日常做MTK sensor移植时先把“能不能出图、曝光是否正确、AE是否收敛”这三件事理清楚比陷入算法细节更重要。3. 一个sensor从零到能上报数据要经过哪几步3.1 拿到硬件资料先做三件事别一上来就写代码。拿到一个新板子和新sensor之后我建议先做三件事第一核对I2C地址和芯片版本。很多sensor芯片的I2C地址由引脚电平决定不同模组厂给出的地址可能不一样。最好的办法是看硬件原理图或询问硬件工程师再结合datasheet确认SA0引脚的状态。第二确认中断引脚。这个非常关键。有些sensor支持“无中断轮询”模式但绝大多数场景下中断引脚需要连接主控的GPIO并且触发电平要和sensor datasheet一致一般是高电平有效也有低电平有效的。如果中断配置反了上层拿不到数据驱动却以为一切正常。第三确认供电范围。不同sensor的VDD和IOVDD电压不同有些需要3.3V有些需要1.8V。如果PMIC LDO配错了I2C能扫到设备但寄存器读出来全返回0xFF这种问题最容易让你怀疑人生。3.2 内核驱动移植实操示例MTK平台sensor驱动目录一般是一大堆vendor相关的目录我不打算统一路径因为不同平台差别很大。这里只列通用的关键步骤。假设我们要调一个加速度计驱动的基本结构是这样的static const struct i2c_device_id accel_id[] { { example_accel, 0 }, { } }; MODULE_DEVICE_TABLE(i2c, accel_id); static const struct of_device_id accel_of_match[] { { .compatible mediatek,example_accel }, { } }; MODULE_DEVICE_TABLE(of, accel_of_match); static struct i2c_driver accel_driver { .probe accel_probe, .remove accel_remove, .id_table accel_id, .driver { .name example_accel, .of_match_table accel_of_match, }, }; module_i2c_driver(accel_driver);probe里面要做的关键事情读取chip id判断I2C链路是否正常ret i2c_smbus_read_byte_data(client, ACCEL_REG_CHIP_ID); if (ret ! ACCEL_EXPECT_ID) { dev_err(client-dev, chip id error: 0x%02x\n, ret); return -ENODEV; }这一步就是排查“设备到底在不在”的试金石。如果chip id读不对后面一切都不用谈。初始化寄存器。根据不同sensor配置量程、采样率、滤波器、中断映射等。建议先把sensor配置成最基础的连续测量模式让中断每采一个点触发一次确认通路后再去做FIFO和batch优化。申请中断并注册input deviceinput_dev devm_input_allocate_device(client-dev); input_set_drvdata(input_dev, accel); input_dev-name example_accel; input_set_capability(input_dev, EV_ABS, ABS_X); input_set_capability(input_dev, EV_ABS, ABS_Y); input_set_capability(input_dev, EV_ABS, ABS_Z); input_set_abs_params(input_dev, ABS_X, -32768, 32767, 0, 0); ... request_threaded_irq(client-irq, NULL, accel_irq_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT, example_accel, accel);注意中断触发模式一定要和硬件实际电平匹配这里写的是上升沿触发。如果板子实际是低电平有效你要用IRQF_TRIGGER_FALLING或者IRQF_TRIGGER_LOW否则中断永远不会来。3.3 HAL层注册与方向校准驱动上报数据后HAL层还需要知道“我的sensor物理方向和Android的坐标系怎么对应”。比如PCB上把加速度计的Y轴方向装反了如果你不处理光感方向还好但计步和方向传感器都会出乱子。MTK平台的HAL配置一般包含一个device_info表里面需要设置type、axis映射、scale、power、max range等参数。方向映射通常用一个3x3矩阵或者一组符号变换项相当于把物理坐标旋转到标准坐标系。实操做法是安装一个sensor测试APK能够实时显示三轴的加速度值和姿态。将设备平放屏幕朝上观察加速度计输出的Z轴是否接近9.8 m/s²X和Y是否接近0。将设备旋转90度依次检查X、Y、Z的正负方向是否和物理旋转一致。如果不一致修改axis映射例如需要把X轴反向就把X那一列的符号改成-1或者交换X和Y轴。这里最实用的经验是改一次映射就重新测一次方向不要一次改三四个轴。我之前懒想一次把矩阵改到位结果改错了还得靠重新编译HAL才能回到初始状态浪费了一个下午。校准Calibration通常分两种offline calibration和online calibration。Offline calibration在产线阶段完成数据存到NVRAM或者persist分区online calibration有些算法库会做自动校准比如陀螺零偏可以在设备静止时自动补偿。如果你发现陀螺仪静止时数据一直在跳先做一次手动校准看能否拉回来。如果拉不回来再考虑是不是硬件电路电源纹波太大。3.4 使用adb和SensorTest验证数据驱动和HAL都搞定后验证方法很关键。建议先用命令行确认内核input设备有没有上报adb shell getevent -lt执行后旋转设备能看到类似/dev/input/eventX: EV_ABS ABS_X 00000012这类输出。如果这一个能看到说明内核到input子系统是通的。然后再用app验证HAL层。MTK平台通常有自带的SensorTest工具或者直接用安卓的dumpsys sensorservice命令查看sensor列表和状态adb shell dumpsys sensorservice里面会列出当前注册的sensor包括name、vendor、version、maxRange、resolution等。如果你的sensor没出现在列表里说明HAL层解析失败这时要回头查HAL的配置文件里sensor name是否和内核设备对应。如果数据方向已经校准了但app里看到的数据噪声偏大先不要怀疑算法。用示波器量一下VDD的纹波再回到驱动侧把采样率和滤波器配置调一下。很多时候是滤波器没开导致高频抖动全部进了HAL。4. 常见问题与排查技巧实录4.1 sensor没中断、读不到chip id这是最最常见的故障。排查思路按顺序来先确认I2C总线号是否正确。同一个平台上有多条I2C总线sensor不一定挂在I2C-0也可能挂在I2C-3。用i2cdetect -y bus扫一下地址看能不能扫到。扫不到就直接查硬件连接和电源。确认供电。用cat /sys/kernel/debug/regulator/regulator_summary看相关LDO是否开启或者直接在电流表上看电流。确认中断GPIO有没有被复用。插上调试线后输入cat /proc/interrupts | grep name看中断号是否注册。如果没有检查DWS里的GPIO配置注意是不是把中断脚配成了输出模式。如果chip id能读到但中断不触发可以用测试脚本直接将sensor的INT脚拉高/拉低模拟中断触发看驱动能不能进handler。这样可以区分“软件中断没使能”还是“硬件根本没拉信号”。再补充一个容易忽略的点很多sensor支持多种中断映射方式比如加速度计的数据就绪DRDY中断需要先把相应的中断映射寄存器配置好否则你即使申请了GPIO中断芯片本身也不会拉高这条线。务必仔细看Datasheet里关于INT_EN和INT_MAP寄存器的说明。4.2 数据方向错乱和漂移方向错乱的原因很简单axis映射错误。调试方法前面讲过了这里补充一个细节方向校准不是只调HAL映射还要关注内核上报的input_report_abs的原始坐标是不是经过了某个中间换算。有些MTK参考驱动里会有data_transform之类的成员它会把原始坐标再转一次。如果你既在驱动里转了又在HAL里转了结果就是轴方向来回乱跳。漂移问题在陀螺仪和磁力计上最明显。陀螺仪零漂一般来自温度变化如果你只做一次静态补偿工作一段时间后还是会漂。解决思路是在正常使用温度下做多点校准或者用算法库的自动零偏校准。如果是磁力计漂移很大程度是PCB上电机、扬声器、电流走线产生的硬磁干扰。硬件layout上尽量让磁力计远离这些噪声源校准条件上要避免在桌角、手边有金属物体时校准。4.3 功耗异常与系统无法休眠sensor功耗问题是项目“验收前总是被点名”的重灾区。常见原因有sensor中断过于频繁导致AP持续唤醒。可以用cat /sys/power/wakeup_sources看看有没有accel相关的事件在反复计数如果计数增长得飞快基本就是中断风暴。sensor没有进入低功耗模式。很多sensor支持fifo/batch但驱动里如果为了贪方便一直让sensor连续采样功耗自然下不去。建议检查驱动里是否实现了batch操作以及HAL层是否配置了合适的batch rate。SCP和AP之间的数据通路不匹配。在MTK低功耗方案里如果SCP始终把数据送往AP即使AP休眠了也会被拉起来。要确认sensor是否真的挂在SCP侧并且唤醒手势之类的功能不会频繁触发整个系统唤醒。排查功耗问题时除了看wakeup_sources还需要用Power Monitor看整机电流曲线。sensor工作电流通常只有几百微安到几毫安但频繁中断唤醒AP的代价是几十毫安甚至几百毫安的电流抬升。所以很多时候不是sensor本身耗电而是它把AP唤醒得太勤。4.4 工具链与几个有趣的调试场景MTK平台调试sensor常用的命令和工具我整理了一个速查表操作命令/工具说明查看I2C设备是否存在i2cdetect -y bus确认sensor的I2C地址是否被扫描到查看内核日志adb shell dmesg | grep -i accel按驱动名过滤日志查看中断注册cat /proc/interrupts | grep name确认中断有没有真正注册并能计数查看sensor服务adb shell dumpsys sensorservice查看注册的sensor列表和状态查看input设备事件adb shell getevent -lt确认底层event上报校准/写入NVRAMMTKFactoryMode/特定APK产线校准通道进入烧录模式短接测试点SP Flash Tool或者adb reboot bootloader需要刷机时使用日常调试慎用另外提一个在机器人项目里经常遇到的扩展场景有些外接sensor并不直接挂在I2C/SPI上而是通过以太网口例如利用EthernetKRL Interface作为通信桥梁启动和控制机器人侧的sensor。这种情况在MTK平台上确实存在尤其是做边缘计算盒子/机器人主板的项目。调这类sensor时核心不在内核驱动而在于网络协议解析、时间戳对齐和网络抖动处理。你要先在用户态从socket里读到sensor的数据再通过HAL转换层注入到SensorManager看起来像是个虚拟sensor。这个我做下来的体会是协议栈越简单越好尽量让传感器本身做时间戳打点避免数据在网络buffer里堆了一段时间后再交给系统否则上层拿到数据会有明显延迟和抖动。4.5 常见问题速查表下面这个表格适合贴在工位上遇到问题先按表排查现象可能原因排查手段解决方案上层没有sensor列表HAL配置文件没生成/未识别设备dumpsys sensorservice检查HAL config中的name/vendor是否匹配I2C扫描不到设备供电、I2C地址错误、引脚复用i2cdetect、示波器量I2C波形修正DWS/电源配置chip id读错寄存器地址不对、版本兼容读datasheet确认chip id reg修正驱动寄存器定义有数据但方向反了axis映射错误SensorTest旋转比对修改HAL axis映射静止数据跳变滤波器没开、电源纹波大示波器查电源波形打开片上滤波器改善供电功耗高无法休眠sensor中断风暴/SCP通路不对wakeup_sources Power Monitor启用fifo/batch减少唤醒事件校准数据丢失NVRAM分区读写失败检查校准数据写入返回值校准时机和分区挂载顺序调整最后再分享一个小技巧如果你在MTK平台上被sensor“幽灵问题”折磨到毫无头绪我建议你把所有不相关的东西先全部剥掉关掉SCP关掉HAL直接通过一个最小驱动的测试App去读/sys节点或者原始input事件。只要底层一条链路通上层问题就是时间和耐心问题。反过来如果底层就不通你在HAL和算法里再怎么折腾都是白费。我做sensor这几年最大的体会是sensor问题十个里有八个不是代码问题而是硬件资源配置问题和时序问题。多花一点时间在原理图核对和DWS引脚复核上比你多写一百行驱动代码都值。这个习惯是我最想推荐给新人的一条经验。
阅读完成 · 觉得有帮助?