android架构和原理分析(G-sensor即Gravity-sensor--重力传感器)

来源:互联网 发布:国际移民组织 知乎 编辑:程序博客网 时间:2024/05/02 19:50
转自:http://blog.csdn.net/silingsong/article/details/7513157

本文主要描述了在android2.3平台G-sensor相关软硬件的体系架构和实现原理,按照Applications、Framework、HAL、Driver和Hardware五大层次分别介绍。

1.系统架构 (Architecture)

1.1 Android体系架构图

1.2 Sensor子系统架构图


·Application Framework

       Sensor应用程序通过Sensor应用框架来获取sensor数据,应用框架层的Sensor Manager通过JNIC++层进行通信。

·Sensor Libraries

       Sensor中间层主要由Sensor ManagerSensor serviceSensor硬件抽象层组成。

·Input Subsystem

       通用的Linux输入框架专为与键盘、鼠标和触摸屏等输入设备而设计,并定义了一套标准事件集合。Sensor输入子系统采用采用了通用的Linux输入框架,它通过/sys/class/input节点和用户空间进行交互。

·Event Dev

       Evdev提供了一种访问/dev/input/eventX输入设备事件的通用方法。

·AccelerometerDriver

       此驱动通过SIRQI2C总线与MMA7660模组进行通信。SIRQ用来产生传感器事件中断。

2 应用 (Applications)

2.1 应用开发五步曲

(1)   获取传感器管理器对象;

mSensorManager =(SensorManager) getSystemService(SENSOR_SERVICE);

(2)   获取传感器对象;

mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

(3)  定义事件监听器;

mEventListener =new SensorEventListener() {

[java] view plaincopy
  1. @Override 
  2. publicvoid onSensorChanged(SensorEvent event) { 
  3.   float[] values = event.values; 
  4.    mTextView.setText("Accelerometer:" + values[0] +", " 
  5.           + values[1] +", " + values[2]); 
  6.  
  7. @Override 
  8. publicvoidonAccuracyChanged(Sensor sensor,int accuracy) { 

(4)   注册事件监听器;

protectedvoid onResume() {

[java] view plaincopy
  1. super.onResume(); 
  2.  
  3. mSensorManager.registerListener(mEventListener, mSensor, 
  4.        SensorManager.SENSOR_DELAY_NORMAL); 

(5)   卸载事件监听器;

protectedvoid onPause() {

[java] view plaincopy
  1.   super.onPause(); 
  2.    
  3.    mSensorManager.unregisterListener(mEventListener); 

3 框架 (Framework)

3.1 工作模型

3.1.1 SensorManager的创建


nativeClassInit(): 初始化Native类信息;
sensors_module_init(): 创建Native SensorManager实例,从SensorService读取Sensor设备列表;
sensors_module_get_next_sensor(): 从SensorService读取下一个Sensor设备;

3.1.2 SensorThread数据接收处理


sensors_create_queue(): 创建和SensorService共享的消息队列;
sensors_data_poll(): 从消息队列中读取SensorService发过来的消息;

3.1.3 SensorService的工作原理


SensorDevice::poll(): 调用HAL接口读取数据;
SensorEventConnection::sendEvents(): 往消息队列中写入消息,SensorThread后续会读取该消息;

3.1.4 SensorDevice对HAL的访问


4 硬件抽象层 (HAL)

在linux操作系统中,应用同硬件之间的交互都是通过设备驱动来实现,Android系统为了降低应用开发人员开发难度,屏蔽硬件差异,定义出硬件抽象层,为开发人员提供获取各种设备相关的信息的接口。

4.1 Sensors HAL关键流程

4.1.1 打开Sensor设备
SensorBase ::openInput() : 打开input子系统的sensor消息文件句柄;
ioctl(EVIOCGABS(...)) : 获取ABS_X/ABS_Y/ABS_Z的加速度;

4.1.2 轮循Sensor事件
InputEventCircularReader::fill(): 调用read()从input子系统中读取事件放入环形缓冲区;
InputEventCircularReader::readEvent(): 从环形缓冲区中读取事件;
InputEventCircularReader::next(): 移动环形缓冲区当前指针;

5.2 Sensors HAL关键数据结构

5.2.1 sensors_module_t
[cpp] view plaincopy
  1. struct sensors_module_t { 
  2.    struct hw_module_t common; 
  3.  
  4.    /**
  5.      * Enumerate all available sensors. The list is returned in "list".
  6.      * @return number of sensors in the list
  7.      */ 
  8.    int (*get_sensors_list)(struct sensors_module_t* module, 
  9.            struct sensor_tconst** list); 
  10. }; 

hw_get_module()会加载HAL模块,并返回HAL入口数据结构(hw_module_t)。HAL_MODULE_INFO_SYM默认是“HAL”,在hw_get_module中用dlsym获取。
[cpp] view plaincopy
  1. conststruct sensors_module_t HAL_MODULE_INFO_SYM = { 
  2.     .common = { 
  3.         .tag = HARDWARE_MODULE_TAG, 
  4.         .version_major = 1, 
  5.         .version_minor = 0, 
  6.         .id = SENSORS_HARDWARE_MODULE_ID, 
  7.         .name ="MMA7660 Sensors Module"
  8.         .author ="The Android Open Source Project"
  9.         .methods = &sensors_module_methods, 
  10.     }, 
  11.     .get_sensors_list = sensors__get_sensors_list 
  12. }; 

5.2.2 hw_module_methods_t

static struct hw_module_methods_t sensors_module_methods = {
[cpp] view plaincopy
  1. .open = open_sensors 
5.2.3 sensors_poll_context_t
[cpp] view plaincopy
  1. struct sensors_poll_context_t { 
  2.    struct sensors_poll_device_t device;// must be first 
  3.     sensors_poll_context_t(); 
  4.     ~sensors_poll_context_t(); 
  5.    int activate(int handle, int enabled); 
  6.    int setDelay(int handle, int64_t ns); 
  7.    int pollEvents(sensors_event_t* data,int count); 
  8.    int handleToDriver(int handle); 
  9. }; 

5.2.4 sensors_poll_device_t

[cpp] view plaincopy
  1. struct sensors_poll_device_t { 
  2. struct hw_device_t common; 
  3.  
  4.    int (*activate)(struct sensors_poll_device_t *dev, 
  5.            int handle,int enabled); 
  6.  
  7.    int (*setDelay)(struct sensors_poll_device_t *dev, 
  8.            int handle, int64_t ns); 
  9.  
  10.    int (*poll)(struct sensors_poll_device_t *dev, 
  11.             sensors_event_t* data,int count); 
  12. }; 

5.2.5 sensor_t
定义传感器的基本参数。
[cpp] view plaincopy
  1. staticconststruct sensor_t sSensorList[] = { 
  2.         {"MMA7660 3-axis Accelerometer"
  3.                "Freescale Semiconductor"
  4.                 1, SENSORS_HANDLE_BASE+ID_A, 
  5.                 SENSOR_TYPE_ACCELEROMETER, 3.0f*9.81f, (3.0f*9.81f)/64.0f, 0.35f, 0, { } }, 
  6. }; 
[cpp] view plaincopy
  1. struct sensor_t { 
  2.    constchar*     name; 
  3.    constchar*     vendor;  
  4.    int             version; 
  5.    int             handle; 
  6.    int             type; 
  7.    float           maxRange; 
  8.    float           resolution; 
  9.    float           power; 
  10.     int32_t         minDelay; 
  11.    void*           reserved[8]; 
  12. }; 


6 驱动 (driver)

6.1 mma7660驱动框架
mma7660与主机通信是通过I2C接口,因此mma7660驱动程序采用Linux系统的I2C子系统框架来实现,主要由3部分组成:

(1) I2C核心
I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(即“algorithm”)上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。这部分是与平台无关的。
此部分在Linux内核的I2C驱动中实现,mma7660驱动使用其提供的功能接口来注册设备驱动。

(2) I2C总线驱动
I2C总线驱动是对I2C硬件体系结构中适配器端的实现。I2C总线驱动主要包含了I2C适配器数据结构i2c_adapter、I2C适配器的algorithm数据结构i2c_algorithm和控制I2C适配器产生通信信号的函数。经由I2C总线驱动的代码,我们可以控制I2C适配器以主控方式产生开始位、停止位、读写周期,以及以从设备方式被读写、产生ACK等。不同的CPU平台对应着不同的I2C总线驱动。
此部分在Linux内核的I2C驱动中实现,mma7660驱动直接获取其提供的adapter,并调用I2C核心的接口来注册。

(3) I2C设备驱动
I2C设备驱动是对I2C硬件体系结构中设备端的实现。设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。I2C设备驱动主要包含了数据结构i2c_driver和i2c_client,mma7660驱动需要实现其中的成员函数。
在Linux内核源代码中的drivers目录下的i2c_dev.c文件,实现了I2C适配器设备文件的功能,应用程序通过“i2c-%d”文件名并使用文件操作接口open()、write()、read()、ioctl()和close()等来访问这个设备。应用层可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器并控制I2C设备的工作方式。

6.2 mma7660操作流程

6.2.1 初始化


6.2.2 探测设备

6.2.3 移除设备

6.2.4 采集数据

6.2.5 睡眠和唤醒
Suspend处理:关闭mma7660模组;
Resume处理:使能mma7660模组;
[cpp] view plaincopy
  1. staticint mma7660_suspend(struct i2c_client *client, pm_message_t mesg) 
  2.    int result; 
  3. result = i2c_smbus_write_byte_data(client, MMA7660_MODE,  
  4.                                MK_MMA7660_MODE(0, 0, 0, 0, 0, 0, 0)); 
  5.     assert(result==0); 
  6.    return result; 
  7.  
  8. staticint mma7660_resume(struct i2c_client *client) 
  9.    int result; 
  10. result = i2c_smbus_write_byte_data(client, MMA7660_MODE,  
  11.                                 MK_MMA7660_MODE(0, 1, 0, 0, 0, 0, 1)); 
  12.     assert(result==0); 
  13.    return result; 
  14.  
  15. staticstruct i2c_driver mma7660_driver = { 
  16.     .driver = { 
  17.         .name = MMA7660_DRV_NAME, 
  18.         .owner = THIS_MODULE, 
  19.     }, 
  20.     .class = I2C_CLASS_HWMON, 
  21.     .suspend = mma7660_suspend, 
  22.     .resume = mma7660_resume, 
  23.     .probe = mma7660_probe, 
  24.     .detect = mma7660_detect, 
  25. //  .address_data = &addr_data, 
  26.     .remove = __devexit_p(mma7660_remove), 
  27.     .id_table = mma7660_id, 
  28. }; 
6.3 命令行调试

6.3.1 sysfs调试接口

(1) 定义sysfs attribute相关数据结构;
[cpp] view plaincopy
  1. static SENSOR_DEVICE_ATTR(all_axis_force, S_IRUGO, show_xyz_force, NULL, 0); 
  2. static SENSOR_DEVICE_ATTR(x_axis_force, S_IRUGO, show_axis_force, NULL, 0); 
  3. static SENSOR_DEVICE_ATTR(y_axis_force, S_IRUGO, show_axis_force, NULL, 1); 
  4. static SENSOR_DEVICE_ATTR(z_axis_force, S_IRUGO, show_axis_force, NULL, 2); 
  5. static SENSOR_DEVICE_ATTR(orientation, S_IRUGO, show_orientation, NULL, 0); 
  6.  
  7. staticstruct attribute* mma7660_attrs[] = 
  8.     &sensor_dev_attr_all_axis_force.dev_attr.attr, 
  9.     &sensor_dev_attr_x_axis_force.dev_attr.attr, 
  10.     &sensor_dev_attr_y_axis_force.dev_attr.attr, 
  11.     &sensor_dev_attr_z_axis_force.dev_attr.attr, 
  12.     &sensor_dev_attr_orientation.dev_attr.attr, 
  13.     NULL 
  14. }; 
  15.  
  16. staticconststruct attribute_group mma7660_group = 
  17.     .attrs = mma7660_attrs, 
  18. }; 


(2) 在probe函数中创建sysfs文件系统;
[cpp] view plaincopy
  1. result = sysfs_create_group(&client->dev.kobj, &mma7660_group); 
  2. if (result != 0) { 
  3.     ERR("sysfs_create_group err\n"); 
  4.    goto exit_sysfs_creat_failed; 


(3) 实现sysfs属性相关的读写函数;
[cpp] view plaincopy
  1. ssize_t show_orientation(struct device *dev, struct device_attribute *attr,char *buf) 
  2.    int result; 
  3. u8 tilt, new_orientation; 
  4.  
  5.     mma7660_read_tilt(&tilt); 
  6.     DBG("tilt [0x%x]\n", tilt); 
  7.     new_orientation = tilt & 0x1f; 
  8.    if (orientation!=new_orientation) 
  9.         orientation = new_orientation; 
  10.  
  11.    switch ((orientation>>2)&0x07) { 
  12.        case 1: 
  13.             result = sprintf(buf,"Left\n"); 
  14.            break
  15.        case 2: 
  16.             result = sprintf(buf,"Right\n"); 
  17.            break
  18.        case 5: 
  19.             result = sprintf(buf,"Downward\n"); 
  20.            break
  21.        case 6: 
  22.             result = sprintf(buf,"Upward\n"); 
  23.            break
  24.        default
  25.            switch(orientation & 0x03) { 
  26.                case 1: 
  27.                     result = sprintf(buf,"Front\n"); 
  28.                    break
  29.                case 2: 
  30.                     result = sprintf(buf,"Back\n"); 
  31.                    break
  32.                default
  33.                     result = sprintf(buf,"Unknown\n"); 
  34.         } 
  35.     } 
  36.    return result; 
[cpp] view plaincopy
  1. ssize_t show_xyz_force(struct device *dev, struct device_attribute *attr,char *buf) 
  2.    int i; 
  3.     s8 xyz[3]; 
  4.  
  5.    for (i=0; i<3; i++) 
  6.         mma7660_read_xyz(i, &xyz[i]); 
  7.  
  8.    return sprintf(buf,"(%d,%d,%d)\n", xyz[0], xyz[1], xyz[2]); 
  9.  
  10. ssize_t show_axis_force(struct device *dev, struct device_attribute *attr,char *buf) 
  11.     s8 force; 
  12.    int n = to_sensor_dev_attr(attr)->index; 
  13.  
  14. mma7660_read_xyz(n, &force); 
  15.  
  16.    return sprintf(buf,"%d\n", force); 

6.3.2 Gsensor调试实例
[plain] view plaincopy
  1. /sys/devices/platform/gl5201-i2c.1/i2c-1/1-004c # ls 
  2. uevent 
  3. name 
  4. modalias 
  5. subsystem 
  6. power 
  7. driver 
  8. all_axis_force 
  9. x_axis_force 
  10. y_axis_force 
  11. z_axis_force 
  12. orientation 
  13. input 
  14. /sys/devices/platform/gl5201-i2c.1/i2c-1/1-004c # cat all_axis_force  
  15. (-1,0,22) 

7 Hardware

7.1 mma7660模组

7.2 关键特性
  • Sampling Resolution: 6bit
  • Digital Output (I2C)
  • 3mm x 3mm x 0.9mm DFN Package
  • Low Power Current Consumption:
    Off Mode: 0.4 μA,
    Standby Mode: 2 μA,
    Active Mode: 47 μA at 1 ODR
  • Configurable Samples per Second from 1 to 120 samples
  • Low Voltage Operation:
    Analog Voltage: 2.4 V - 3.6 V
    Digital Voltage: 1.71 V - 3.6 V
  • Auto-Wake/Sleep Feature for Low Power Consumption
  • Tilt Orientation Detection for Portrait/Landscape Capability
  • Gesture Detection Including Shake Detection and Tap Detection
7.2.1 功能模块图
7.2.2 硬件连接图
7.2.3 运动检测原理
mma7660是一种电容式3轴g-sensor,其技术原理是在wafer的表面做出梳状结构,当产生动作时,由侦测电容差来判断变形量,反推出加速度的值。
简单物理模型如下图:
7.2.4 I2C读写时序
7.2.5 工作状态机
7.2.6 寄存器定义
7.2.7 事件检测
  • 方向和摇动检测
  • 轻拍或倾斜检测



原创粉丝点击