Quantcast
Channel: Sam的技术Blog
Viewing all articles
Browse latest Browse all 158

Invensense mlSDK分析

$
0
0

作者:Sam(甄峰)  sam_code@hotmail.com

 

0. 背景 

最近在Nvdia Tegra K1平台上使用Invensense MPU9250 Sensor。MPU9250使用I2C连接到K1平台。在Driver支持后,/dev/input/中新建3个node,  /dev/input/eventX. 通过ioctl(EVIOCGNAME)得到其名,分别为:MPU6500, INV_DMP, akm89xx. 这与I2C设备驱动中创建的device对应起来。且其中有数据。

这说明I2C设备驱动这块任务完成,已经把Raw Data传送到/dev/input/eventX中去了。

 

然后在Android APP层通过SensorManager获取Sensor实体,并尝试得到数据:

可以发现,它拥有以下Sensor:

1. MPL Rotation Vector(旋转矢量传感器)

2. MPL Linear Accel. (加速度,不包括重力)

3. MPL Gravity. (仅包括重力)

4. MPL Gyro. (角速度)

5. MPL Accel. (加速度)

6. MPL magnetic field

7. MPL Orientation.(方向)

 

MPU9250=MPU6500+AK8963,所以加速度,角速度信息是直接从MPU6500得到的,方向信息则从AK8963得到,其它几个SensorManager层面的Sensor,则都是通过软件计算模拟出来的。具体实现则在sensors.xxxx.so部分实现. 通常是sensors.default.so, 在一些平台,则由自己定制的库实现,如K1平台使用sensors.tegra.so.

 

 

1. mlSDK的发现(抽丝拨茧):

A:在MPU9250通过I2C连接K1,Driver insmod成功后,尝试使用Android SensorManager得到Sensor,获取Sensor数据,Gyro,Acc , Magnetic, Linear_Acc, Orientation, Gravity均一切正常,说明Framework中已经针对MPU9250数据做过处理。

 

B:之后想使用NativeC程序直接从/dev/input/eventX中读取数据(input_event),于是打开设备名为MPU9250的node(/dev/input/event4). 读取input event. 问题立刻来了。

 

首先看数据格式:

 

#define EV_SYN 0x00

#define EV_REL 0x02

 

struct input_event {
 struct timeval time;
 __u16 type;
 __u16 code;
 __s32 value;
};

 

获取的数据很有规律(driver中填充的):

Data[0]: type=2,code=3

Data[1]: type=2,code=4

Data[2]: type=2,code=5

 

Data[3]: type=2,code=0

Data[4]: type=2,code=1

Data[5]: type=2,code=2

 

Data[6]: type=2,code=9

Data[7]: type=2,code=8

 

Data[0]: type=0,code=0

 

这就是一组数据。从Driver中可以看到:

Data[0]: type=2,code=3

Data[1]: type=2,code=4

Data[2]: type=2,code=5

他们分别是ACC的X,Y,Z的Raw Data。

 

 

Data[3]: type=2,code=0

Data[4]: type=2,code=1

Data[5]: type=2,code=2

 他们分别是GYRO的X,Y,Z的Raw Data。

 

Data[6]: type=2,code=9

Data[7]: type=2,code=8

timestamp的高32和低32bit.

 

 Data[0]: type=0,code=0

SYNC,作为一组数据的结束标记。

 

直到这里,还一切正常。但ACC, GYRO的值,却异常奇怪,很难想到公式把他们转换的正常的加速度和角速度单位。Sam自然想到,sensors.tegra.so也是读取以上node数据,但SensorManager却拿到正确数据,那肯定在这一层做了转换。

 

C:查数据转换踪迹:

在device/nvidia/ardbeg/sensors/目录下,可以看到sensors.cpp 和Android.mk

从Android.mk内容判断,

LOCAL_SRC_FILES := sensors.cpp

LOCAL_MODULE := sensors.tegra

sensors.cpp最终将生成sensors.tegra.so.

但请注意,其实它还包含了一系列库。

libsensors.base

libinvensense_hal

libsensor.mpl

libsensors.nvs_input

libsensors.iio.lights

libsensors.max44005

libsensors.bmpx80

那这些库的源码在哪呢?

大都在device/nvidia/drivers/sensors目录下。

这几个库中,最关键的就是libsensors.mpl,它由MPLSensor.cpp, MPLSupport.cpp CompassSensor.cpp生成,但同时,它又依赖于两个库:

libmllite.so,   libmplmpu.so

这两个库,就是数据转换的关键。

 

D: mlsdk踪迹:

先分析libmllite.so, 它的源码在device/nvidia/drivers/sensors/mlsdk/目录下,相信此目录下源码和头文件均为Invesense提供。主要源码在device/nvidia/drivers/sensors/mlsdk/mllite目录。

将由它提供接口,把Raw Data转换为标准单位的数据。

 

其次是libmplmpus.so,

这个库并没有提供源码,只提供了库文件。

vendor/nvidia/tegra/prebuilt/ardbeg/target/product/ardbeg/lib/

(这意味着移植是个大问题)

 

2. NativeC 程序使用mlSDK:

 既然清楚了sensors.tegra.so如何使用mlsdk把Raw data转化成标准单位数据。那理论上我们NativeC程序也可以做到这一点。

2.1: 生成自己的libmllite.so库:

想直接链接libmllite.so时,总会出问题,怀疑是编译选项的差异造成的,干脆自己编译一份库好了。

于是copy mlsdk整个目录,并按自己的习惯写了Android.mk+Application.mk.  编译,正常通过。

2.2: 修改代码,使用mlsdk,

于是可以得到正常单位数据了。(只尝试了ACC, GYRO)

 

 

3.  sensors.xxxx.so的功能和结构

在查看mlSDK使用情况时,也也通过sensors.tegra.so复习了一下sensors.xxxx.so的作用和写法。(之前在模拟ACC设备时,TT曾告诉我这个模板和方法)

总的来说:这个模快提供一个方法,让Framework能够得到底层Sensor(包括硬件Sensor,软件Sensor)的信息,并得到Sensor数据。

 

所以它需要做三件事:

A. 维护一个Sensor list. 把所有Sensor信息列入其中

 

B. 提供一个接口,供上层能够拿到Sensor信息,并控制Sensor(打开,关闭,得到数据)

 

C. 提供Sensor数据。

 

Sensor List如下:

static struct sensor_t sSensorList[10] = {
      MPLROTATIONVECTOR_DEF,
      MPLLINEARACCEL_DEF,
      MPLGRAVITY_DEF,
      MPLGYRO_DEF,
      MPLACCEL_DEF,
      MPLMAGNETICFIELD_DEF,
      MPLORIENTATION_DEF,
};

具体定义如下:

#define MPLROTATIONVECTOR_DEF {                         \
    "MPL rotation vector",                              \
    "Invensense",                                       \
    1, ID_RV,                                           \
    SENSOR_TYPE_ROTATION_VECTOR, 10240.0f, 1.0f,        \
    0.5f, 20000, 0, 0, { } }

 

含义如下:

struct sensor_t {

    // Name of this sensor.
    // All sensors of the same "type" must have a different "name".

    const char*     name;

    //vendor of the hardware part //
    const char*     vendor;

    // version of the hardware part + driver. The value of this field
    // must increase when the driver is updated in a way that changes the
    // output of this sensor. This is important for fused sensors when the
    // fusion algorithm is updated.

    int             version;

    // handle that identifies this sensors. This handle is used to reference
    //this sensor throughout the HAL API.
/
    int             handle;

    //this sensor's type. //
    int             type;

    // maximum range of this sensor's value in SI units /
    float           maxRange;

    / smallest difference between two values reported by this sensor /
    float           resolution;

    // rough estimate of this sensor's power consumption in mA /
    float           power;

    // this value depends on the trigger mode:
    
    //   continuous: minimum sample period allowed in microseconds
    //   on-change : 0
    //   one-shot  :-1
     //   special   : 0, unless otherwise noted
    
    int32_t         minDelay;

    // number of events reserved for this sensor in the batch mode FIFO.
     //If there is a dedicated FIFO for this sensor, then this is the
    // size of this FIFO. If the FIFO is shared with other sensors,
    // this is the size reserved for that sensor and it can be zero.
    
    uint32_t        fifoReservedEventCount;

    // maximum number of events of this sensor that could be batched.
     // This is especially relevant when the FIFO is shared between
     //several sensors; this value is then set to the size of that FIFO.
    
    uint32_t        fifoMaxEventCount;

    // reserved fields, must be zero
    void*           reserved[6];
};

 

接口如下:

struct sensors_module_t HAL_MODULE_INFO_SYM = {
        common: {
                tag: HARDWARE_MODULE_TAG,
                version_major: 1,
                version_minor: 0,
                id: SENSORS_HARDWARE_MODULE_ID,
                name: "Ardbeg sensors module",
                author: "nvidia",
                methods: &sensors_module_methods,
                dso: NULL,
                reserved: {0}
        },
        get_sensors_list: sensors__get_sensors_list,
};

 

static int sensors__get_sensors_list(struct sensors_module_t* module, struct sensor_t const** list)

把维护的Sensor通过参数二提供给调用方。

 

 

提供操作Sensor的接口;

 static struct hw_module_methods_t sensors_module_methods = {
        open: open_sensors
};

 

 

 

最重要的当然是如何提供数据:

dev->device.poll            = poll__poll;

 

pollEvents(sensors_event_t* data, int count)

在这个函数内提供数据:

其中参数1,即为存放数据的结构体。(sensors_event_t结构,在附2)

参数2应该是Sensor个数。

 

sensors.xxxx.so的开发者应该依次填充sensors_event_t结构体数组中的内容。以供上层使用。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

注1:MPU9150,MPU9250介绍:

MPU9150和MPU9250均为9轴芯片。

MPU9150着眼于精度和性能,内部采用MPU6050(3轴加速度,3轴陀螺仪)+AK8975(磁)。 只支持I2C

MPU9250着眼于低功耗,内部采用MPU6500(3轴加速度,3轴陀螺仪)+AK8963。支持I2C和SPI。

 

 

注2:sensors_event_t

typedef struct sensors_event_t {
   
    int32_t version;

   
    int32_t sensor;

   
    int32_t type;

   
    int32_t reserved0;

   
    int64_t timestamp;

    union {
        union {
            float           data[16];

           
            sensors_vec_t   acceleration;

           
            sensors_vec_t   magnetic;

           
            sensors_vec_t   orientation;

           
            sensors_vec_t   gyro;

           
            float           temperature;

           
            float           distance;

           
            float           light;

           
            float           pressure;

           
            float           relative_humidity;

           
            uncalibrated_event_t uncalibrated_gyro;

           
            uncalibrated_event_t uncalibrated_magnetic;

           
            meta_data_event_t meta_data;
        };

        union {
            uint64_t        data[8];

           
            uint64_t        step_counter;
        } u64;
    };
    uint32_t reserved1[4];
} sensors_event_t;


 

Viewing all articles
Browse latest Browse all 158

Trending Articles