本帖最后由 飞神 于 2019-4-9 14:12 编辑
传感器介绍
MPU60X0是invenSence公司的一款全球首例9轴运动处理传感器。它内部集成了3轴MEMS陀螺仪和3轴MEMS加速度计,同时可以通过I2C接口(注意这个接口是XDA、XCL,而开发板与MPU6050通信的接口是SDA、SCL)连接一个第三方的数据传感器,比如说磁力计,扩展成9轴数据输出。MPU6050内置1024字节的fifo缓冲区,可编程的加速度范围和陀螺仪范围,可编程的中断,使用400khz快速模式的i2c通信。对于MPU6050这款传感器的介绍,更详细的可参考手册和度娘,这款传感器很经典,网上的资料特别多。
MPU6050这款传感器应用场合非常多,如果你仔细观察,你会发现我们身边也有许多它的影子。如下
无人机
平衡车 运动手环
vr眼镜
每天刷的步数(也是依赖手机的陀螺仪传感器)
驱动mpu6050的方式
看完上边花里胡哨的图片后,想必您对这款传感器不陌生了,现在我开始说如何在ROC-RK3308-CC开发板上轻松简单的实现设备的驱动,MPU6050作为一款经典而且性能非常强大的传感器,在RK3308的SDK中可以用多种方式去驱动,我在这简单总结一下,如下
1.纯粹自己写 这种方式就是自己通过i2c的接口函数去配置传感器的寄存器,然后在某一个条件去获取传感器的数据,进而将数据上报到用户层,在该论坛里就有贴子实现过,感兴趣的可自行搜索。 2.使用Rockchip的传感器框架来写 Rockchip的传感器框架在linux/kernel/drivers/input/sensors目录下,具体参考相应的文档去实现该驱动。 3.使用invenSence自身的驱动代码(无需自己写驱动) 本帖就是使用这种方式去实现,看下文。
如何使用invensense自身的驱动
ROC-RK3308的SDK中已经集成了invenSense厂商的驱动代码,因此我们无需再去写驱动代码,只需要完成设备树的适配就可以驱动相应的设备,invenSense的驱动框架源码目录如下
- linux/kernel/drivers/staging/iio/imu/inv_mpu
复制代码 其实这个invenSense的驱动框架是与安卓的Hal层配合使用的,那么既然Hal层能获取数据,那么我们Linux的用户层也一样能拿到数据。
下面我们一步一步来实现适配。
1.设备树的适配
既然驱动代码都已经有了,那么我们就可以按照官方的驱动代码去填写我们的设备树,设备树进行如下配置:
- &i2c1 {
- clock-frequency = <400000>;
- status = "okay";
- mpu6050: mpu@68 {
- compatible = "invensense,mpu6050";
- reg = <0x68>;
- mpu-int_config = <0>;
- mpu-level_shifter = <0>;
- mpu-orientation = <1 0 0 0 1 0 0 0 1>;
- orientation-x= <1>;
- orientation-y= <0>;
- orientation-z= <0>;
- irq-gpio = <&gpio0 RK_PB7 IRQ_TYPE_LEVEL_LOW>;
- mpu-debug = <1>;
- status = "okay";
- };
- };
复制代码 参数含义(很重要!!)
compatible必须是"invensense,mpu6050"
reg = <0x68>;这个是i2c从设备地址,这个地址取值mpu6050的ADO脚,它接地就是0x68,它拉高就是0x69
irq-gpio = <&gpio0 RK_PB7 IRQ_TYPE_LEVEL_LOW>;这个就是mpu6050的int脚接的中断口,必须要接中断才能获取设备数据。
mpu-int_config = <0>;是中断使能配置寄存器的值(如果扩展成9轴,那么这个参数还会作用于中断引脚配置寄存器),填0即可,因为内部驱动代码会帮你开相应中断。
这里额外要注意,比如如果要填0x10的话,那么这样填写mpu-int_config = <0x10000000>或者mpu-int_config = /bits/ 8 <0x10>; 。
mpu-orientation=<1 0 0 0 1 0 0 0 1>;是设备的3*3的方向矩阵
orientation-x= <1>;//代表取反
orientation-y= <0>;
orientation-z= <0>;
根据你实际的layout进行配置方向矩阵,这部分的信息可通过sysfs文件系统的接口获取,进而实现你的设备layout
到这里也许你会问,我就想获取一些数据而已,怎么搞那么多的参数,我不配置那么多行不行?
答案是不行的,要么就自己去改源码咯。因为在probe函数里遍历设备树的驱动代码如果没有匹配到这些选项就会立即报错退出。
2.make menuconfig的选配
打开驱动目录下的Kconfig
- linux/kernel/drivers/staging/iio/imu/inv_mpu/Kconfig
复制代码 从文件中可以看出,要想用invenSense的驱动框架,必须将相应的依赖项选配上。
- config INV_MPU_IIO
- tristate "Invensense MPU devices"
- depends on I2C && SYSFS && IIO && IIO_KFIFO_BUF && IIO_TRIGGER && !INV_MPU
- default n
- help
- This driver supports the Invensense MPU devices.
- This includes MPU6050/MPU3050/MPU9150/ITG3500/MPU6500/MPU9250.
- This driver can be built as a module. The module will be called
- inv-mpu-iio.
复制代码 将编译好的新内核烧录进开发板中,将会出现三个文件
- /dev/iio:device0
- /sys/bus/iio/devices/iio:device0
- /sys/bus/iio/devices/trigger0
复制代码
3.配置sysfs和获取传感器数据
如果上述操作成功,那么在/sys/bus/iio/devices/iio\:device0/目录下将会生成这些文件
这些文件就是启动参数的配置文件,这些文件的含义具体是什么属性,我就不逐一介绍了,更详细的参考附件的文档,在用户层我们进行以下配置就可以获取加速度和角速度的数据,代码如下- //配置sysfs文件系统的启动参数
- system("echo 1 > /sys/bus/iio/devices/iio:device0/accl_enable ");
- system("echo 1 > /sys/bus/iio/devices/iio:device0/gyro_enable ");
- system("echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_x_en ");
- system("echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_y_en ");
- system("echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_z_en");
- system("echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_anglvel_x_en ");
- system("echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_anglvel_y_en");
- system("echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_anglvel_z_en");
- system("echo 0 > /sys/bus/iio/devices/iio:device0/scan_elements/in_timestamp_en");
- system("echo 12 > /sys/bus/iio/devices/iio:device0/buffer/length");
- system("echo 1 > /sys/bus/iio/devices/iio:device0/buffer/enable");
复制代码
启动参数配置好,我们就可以read读取传感器的数据了
- ret=poll(&fp,1,-1);
- if(ret==-1)
- {
- printf("poll failed\n");
- exit(-1);
- }
- ret=read(fp.fd,buff,512);
复制代码
根据获取的数据buff进行解析成相应的加速度和角速度
以x轴加速度为例,其他轴的详细的源码参考附件。
- //accel x
- x=buff[1]*256+buff[0];
- if(x>32767)
- {
- ax=(65535-x)/16384.0;
- ax=-ax;
- }else
- {
- ax=x/16384.0;
- }
- printf("ax:%.2lfg\n",ax);
复制代码 4.demo测试
经过上面的步骤后,我们就可以在用户层获取源源不断的设备数据了。数据效果如下:
|