1. 项目缘由:龙芯k和“走马观碑组”的MPU到底指什么
1.1 先说清这是一次什么样的移植
这周我们组干了个说大不大、说小不小的活:把MPU6050六轴传感器的驱动,从我们之前折腾过的平台迁到龙芯k这块主控板上。组名“走马观碑组”听起来有点飘,实际上干的活儿特别具体——龙芯k板子上要用姿态数据做后续控制,板子自带的存储和外设不算丰富,得外挂一颗IMU来获取三轴加速度和三轴角速度,所以驱动移植就成了绕不开的一关。
很多人看到“龙芯k - 走马观碑组MPU驱动移植”这个标题,第一反应是:龙芯平台上还有Memory Protection Unit?是不是要做内存保护?这里必须先踩一脚刹车。项目里说的MPU,指的是InvenSense的MPU6050惯性传感器,不是ARM Cortex-M处理器里的那个MPU内存保护单元。这点如果不提前讲清楚,后面读代码读设备树时很容易整岔。顺便说一句,网上常有人搜“h750 mpu怎么设置”,那个多半是在问STM32H750里Memory Protection Unit怎么配置,和我们这颗传感器完全是两码事。
真正要做的事情,是把MPU6050的Linux驱动跑在龙芯k环境里,让用户态程序能通过I2C总线拿到加速度和角速度原始值。刚接到需求时我觉得这不算难,毕竟MPU6050是一颗烂大街的传感器,开源驱动一大把,Linux内核里也有官方维护的inv_mpu6050驱动。可真上手后发现,“驱动移植”这四个字的难点不在MPU6050本身,而在新平台的I2C总线上有没有被正确枚举、中断引脚能不能申请、内核配置有没有把相关子系统打开,以及驱动依赖的设备树节点对不对路。
1.2 为什么叫移植而不是叫开发
关于为什么要用“移植”这个词,我也提一下。MPU6050的寄存器手册是固定的,I2C通信时序也是公开的,从原理上讲,任何平台读写它都差不多。所以多数情况下不需要从零写一个传感器驱动,而是把已有代码搬到新板子上,再根据新平台的差异做适配。这个过程就是典型的“驱动移植”。
移植的工作量通常集中在三块:硬件连接、设备树描述、驱动代码与当前内核API的兼容性。我们这次主要参考了Linux内核自带的inv_mpu6050驱动,它服务于IIO子系统,同时也会替换成一份自定义的简易I2C字符设备驱动做对比验证。后续整篇记录都会围绕这三块展开,顺便把过程中踩过的坑和排查思路都写清楚,希望对同样在龙芯或其它嵌入式Linux平台上接MPU6050的朋友有点帮助。
1.3 这个板子能干什么、适合谁参考
龙芯k这块板子本质是一个嵌入式Linux平台,适合跑应用、做控制。我们的最终目标是在上面跑通一个IMU数据读取链路:MPU6050 采集原始数据,CPU 通过 I2C 读取,再换算成物理单位,供后续姿态解算或避障算法调用。在整个项目里,我们走马观碑组负责的“驱动移植”,是链路最底层的那一环。
这篇内容适合几类人看:手里刚好有龙芯或类似国产嵌入式Linux板子,想外接MPU6050的;在别的平台已经调通过传感器,却不知道怎么把驱动迁移到新内核版本上的;还有一种就是刚接触Linux驱动、想通过一个具体传感器把I2C子系统、设备树、中断机制串起来理解的人。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 移植前的关键准备:硬件接线、内核环境与MPU6050寄存器
2.1 先把硬件和I2C地址确认清楚
很多驱动调不通的问题,根源在硬件连接就没对。MPU6050标准接口一共四根线:VCC、GND、SCL、SDA。有些模块还带XDA、XCL、AD0和INT,但我们只用到基础四线,外加一个INT引脚用来上报数据就绪中断。
龙芯k板子上有两路I2C控制器,我用万用表直接量了板载排针,确定要用的那一路是I2C0,SCL和SDA上都已经有10k左右的上拉电阻。这一点很重要:如果传感器模块本身没有上拉,而板子的I2C总线又没接上拉,那SDA和SCL就一直是浮空状态,Linux的i2cdetect会报Bus error或者什么设备都扫描不到。
MPU6050的7位I2C地址默认是0x68。如果AD0引脚被拉高,地址会变成0x69。我们这块模块的AD0默认接地,所以设备地址就是0x68。在裸机环境下写代码时,经常需要把7位地址左移一位变成0xD0/0xD1再配合读写位使用,但Linux内核I2C子系统里统一使用7位地址,直接填0x68就行,不需要再左移。这也是我见过不少人从STM32裸机习惯迁过来后翻车的地方。
2.2 龙芯k平台的开发环境与内核准备
这次龙芯k板子跑的是Linux 5.10内核,开发机上装好了交叉编译工具链。我习惯把内核源码单独放到工作目录,编译内核模块时直接引用内核源码路径。如果只是加载一个外部模块,并不需要完整编译整个内核,但一定要有已经编译好的内核树,也就是源码和生成过Module.symvers的目录。否则模块编译时会报找不到内核头文件或版本不匹配的错误。
我们这次有两种驱动选择方案。第一种是直接用内核自带的IIO驱动:把CONFIG_IIO、CONFIG_INV_MPU6050_I2C
