天天看點

gsensor架構和原理分析 .

本文主要描述了在android2.3平台G-sensor相關軟硬體的體系架構和實作原理,按照Applications、Framework、HAL、Driver和Hardware五大層次分别介紹。

1.系統架構 (Architecture)

1.1 Android體系架構圖

gsensor架構和原理分析 .

1.2 Sensor子系統架構圖

gsensor架構和原理分析 .

 · Application Framework

       Sensor應用程式通過Sensor應用架構來擷取sensor資料,應用架構層的Sensor Manager通過JNI與C++層進行通信。

 · Sensor Libraries

       Sensor中間層主要由Sensor Manager、Sensor service和Sensor硬體抽象層組成。

 · Input Subsystem

       通用的Linux輸入架構專為與鍵盤、滑鼠和觸摸屏等輸入裝置而設計,并定義了一套标準事件集合。Sensor輸入子系統采用采用了通用的Linux輸入架構,它通過/sys/class/input節點和使用者空間進行互動。

 · Event Dev

       Evdev提供了一種通路/dev/input/eventX輸入裝置事件的通用方法。

 · AccelerometerDriver

       此驅動通過SIRQ和I2C總線與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 plaincopyprint?

  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. publicvoidonAccuracyChanged(Sensor sensor,int accuracy) {  
          
           @Override
           publicvoid onSensorChanged(SensorEvent event) {
              float[] values = event.values;
              mTextView.setText("Accelerometer:" + values[0] +", "
                     + values[1] +", " + values[2]);
           }
 
           @Override
           publicvoidonAccuracyChanged(Sensor sensor,int accuracy) {
           }
       };      

(4)   注冊事件監聽器;

protectedvoid onResume() {

  1. super.onResume();  
  2. mSensorManager.registerListener(mEventListener, mSensor,  
  3.        SensorManager.SENSOR_DELAY_NORMAL);  
       super.onResume();
      
       mSensorManager.registerListener(mEventListener, mSensor,
              SensorManager.SENSOR_DELAY_NORMAL);
    }      

(5)   解除安裝事件監聽器;

protectedvoid onPause() {

  1.    super.onPause();  
  2.    mSensorManager.unregisterListener(mEventListener);  
       super.onPause();
      
       mSensorManager.unregisterListener(mEventListener);
    }      

3 架構 (Framework)

3.1 工作模型

gsensor架構和原理分析 .

3.1.1 SensorManager的建立

gsensor架構和原理分析 .

nativeClassInit(): 初始化Native類資訊;

sensors_module_init(): 建立Native SensorManager執行個體,從SensorService讀取Sensor裝置清單;

sensors_module_get_next_sensor(): 從SensorService讀取下一個Sensor裝置;

3.1.2 SensorThread資料接收處理

gsensor架構和原理分析 .

sensors_create_queue(): 建立和SensorService共享的消息隊列;

sensors_data_poll(): 從消息隊列中讀取SensorService發過來的消息;

3.1.3 SensorService的工作原理

gsensor架構和原理分析 .

SensorDevice::poll(): 調用HAL接口讀取資料;

SensorEventConnection::sendEvents(): 往消息隊列中寫入消息,SensorThread後續會讀取該消息;

3.1.4 SensorDevice對HAL的通路

gsensor架構和原理分析 .

4 硬體抽象層 (HAL)

gsensor架構和原理分析 .

在linux作業系統中,應用同硬體之間的互動都是通過裝置驅動來實作,Android系統為了降低應用開發人員開發難度,屏蔽硬體差異,定義出硬體抽象層,為開發人員提供擷取各種裝置相關的資訊的接口。

4.1 Sensors HAL關鍵流程

4.1.1 打開Sensor裝置

gsensor架構和原理分析 .

SensorBase ::openInput() : 打開input子系統的sensor消息檔案句柄;

ioctl(EVIOCGABS(...)) : 擷取ABS_X/ABS_Y/ABS_Z的加速度;

4.1.2 輪循Sensor事件

gsensor架構和原理分析 .

InputEventCircularReader::fill(): 調用read()從input子系統中讀取事件放入環形緩沖區;

InputEventCircularReader::readEvent(): 從環形緩沖區中讀取事件;

InputEventCircularReader::next(): 移動環形緩沖區目前指針;

5.2 Sensors HAL關鍵資料結構

5.2.1 sensors_module_t

[cpp] view plaincopyprint?

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

    /**
     * Enumerate all available sensors. The list is returned in "list".
     * @return number of sensors in the list
     */
    int (*get_sensors_list)(struct sensors_module_t* module,
            struct sensor_t const** list);
};      

hw_get_module()會加載HAL子產品,并傳回HAL入口資料結構(hw_module_t)。HAL_MODULE_INFO_SYM預設是“HAL”,在hw_get_module中用dlsym擷取。

  1. const struct 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  
const 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 = "MMA7660 Sensors Module",
        .author = "The Android Open Source Project",
        .methods = &sensors_module_methods,
    },
    .get_sensors_list = sensors__get_sensors_list
};      

5.2.2 hw_module_methods_t

 static struct hw_module_methods_t sensors_module_methods = {

  1. .open = open_sensors  
    .open = open_sensors
};      

5.2.3 sensors_poll_context_t

  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);  
struct sensors_poll_context_t {
    struct sensors_poll_device_t device; // must be first
    sensors_poll_context_t();
    ~sensors_poll_context_t();
    int activate(int handle, int enabled);
    int setDelay(int handle, int64_t ns);
    int pollEvents(sensors_event_t* data, int count);
    int handleToDriver(int handle);
};      

5.2.4 sensors_poll_device_t

  1. struct sensors_poll_device_t {  
  2. struct hw_device_t common;  
  3.     int (*activate)(struct sensors_poll_device_t *dev,  
  4.             int handle, int enabled);  
  5.     int (*setDelay)(struct sensors_poll_device_t *dev,  
  6.             int handle, int64_t ns);  
  7.     int (*poll)(struct sensors_poll_device_t *dev,  
  8.             sensors_event_t* data, int count);  
struct sensors_poll_device_t {
struct hw_device_t common;

    int (*activate)(struct sensors_poll_device_t *dev,
            int handle, int enabled);

    int (*setDelay)(struct sensors_poll_device_t *dev,
            int handle, int64_t ns);

    int (*poll)(struct sensors_poll_device_t *dev,
            sensors_event_t* data, int count);
};      

5.2.5 sensor_t

定義傳感器的基本參數。

  1. static const struct 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, { } },  
static const struct sensor_t sSensorList[] = {
        { "MMA7660 3-axis Accelerometer",
                "Freescale Semiconductor",
                1, SENSORS_HANDLE_BASE+ID_A,
                SENSOR_TYPE_ACCELEROMETER, 3.0f*9.81f, (3.0f*9.81f)/64.0f, 0.35f, 0, { } },
};      
  1. struct sensor_t {  
  2.     const char*     name;  
  3.     const char*     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];  
struct sensor_t {
    const char*     name;
    const char*     vendor; 
    int             version;
    int             handle;
    int             type;
    float           maxRange;
    float           resolution;
    float           power;
    int32_t         minDelay;
    void*           reserved[8];
};      

6 驅動 (driver)

6.1 mma7660驅動架構

gsensor架構和原理分析 .

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 初始化

gsensor架構和原理分析 .

6.2.2 探測裝置

gsensor架構和原理分析 .

6.2.3 移除裝置

gsensor架構和原理分析 .

6.2.4 采集資料

gsensor架構和原理分析 .

6.2.5 睡眠和喚醒

Suspend處理:關閉mma7660模組;

Resume處理:使能mma7660模組;

  1. static int mma7660_suspend(struct i2c_client *client, pm_message_t mesg)  
  2. {  
  3.     int result;  
  4. result = i2c_smbus_write_byte_data(client, MMA7660_MODE,   
  5.                                MK_MMA7660_MODE(0, 0, 0, 0, 0, 0, 0));  
  6.     assert(result==0);  
  7.     return result;  
  8. static int mma7660_resume(struct i2c_client *client)  
  9.                                 MK_MMA7660_MODE(0, 1, 0, 0, 0, 0, 1));  
  10. static struct i2c_driver mma7660_driver = {  
  11.     .driver = {  
  12.         .name = MMA7660_DRV_NAME,  
  13.         .owner = THIS_MODULE,  
  14.     .class = I2C_CLASS_HWMON,  
  15.     .suspend = mma7660_suspend,  
  16.     .resume = mma7660_resume,  
  17.     .probe = mma7660_probe,  
  18.     .detect = mma7660_detect,  
  19. //  .address_data = &addr_data,   
  20.     .remove = __devexit_p(mma7660_remove),  
  21.     .id_table = mma7660_id,  
static int mma7660_suspend(struct i2c_client *client, pm_message_t mesg)
{
    int result;
result = i2c_smbus_write_byte_data(client, MMA7660_MODE, 
                               MK_MMA7660_MODE(0, 0, 0, 0, 0, 0, 0));
    assert(result==0);
    return result;
}

static int mma7660_resume(struct i2c_client *client)
{
    int result;
result = i2c_smbus_write_byte_data(client, MMA7660_MODE, 
                                MK_MMA7660_MODE(0, 1, 0, 0, 0, 0, 1));
    assert(result==0);
    return result;
}

static struct i2c_driver mma7660_driver = {
    .driver = {
        .name = MMA7660_DRV_NAME,
        .owner = THIS_MODULE,
    },
    .class = I2C_CLASS_HWMON,
    .suspend = mma7660_suspend,
    .resume = mma7660_resume,
    .probe = mma7660_probe,
    .detect = mma7660_detect,
//	.address_data = &addr_data,
    .remove = __devexit_p(mma7660_remove),
    .id_table = mma7660_id,
};      

6.3 指令行調試

6.3.1 sysfs調試接口

(1) 定義sysfs attribute相關資料結構;

  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. static struct attribute* mma7660_attrs[] =  
  7.     &sensor_dev_attr_all_axis_force.dev_attr.attr,  
  8.     &sensor_dev_attr_x_axis_force.dev_attr.attr,  
  9.     &sensor_dev_attr_y_axis_force.dev_attr.attr,  
  10.     &sensor_dev_attr_z_axis_force.dev_attr.attr,  
  11.     &sensor_dev_attr_orientation.dev_attr.attr,  
  12.     NULL  
  13. static const struct attribute_group mma7660_group =  
  14.     .attrs = mma7660_attrs,  
static SENSOR_DEVICE_ATTR(all_axis_force, S_IRUGO, show_xyz_force, NULL, 0);
static SENSOR_DEVICE_ATTR(x_axis_force, S_IRUGO, show_axis_force, NULL, 0);
static SENSOR_DEVICE_ATTR(y_axis_force, S_IRUGO, show_axis_force, NULL, 1);
static SENSOR_DEVICE_ATTR(z_axis_force, S_IRUGO, show_axis_force, NULL, 2);
static SENSOR_DEVICE_ATTR(orientation, S_IRUGO, show_orientation, NULL, 0);

static struct attribute* mma7660_attrs[] =
{
    &sensor_dev_attr_all_axis_force.dev_attr.attr,
    &sensor_dev_attr_x_axis_force.dev_attr.attr,
    &sensor_dev_attr_y_axis_force.dev_attr.attr,
    &sensor_dev_attr_z_axis_force.dev_attr.attr,
    &sensor_dev_attr_orientation.dev_attr.attr,
    NULL
};

static const struct attribute_group mma7660_group =
{
    .attrs = mma7660_attrs,
};      

(2) 在probe函數中建立sysfs檔案系統;

  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;  
    result = sysfs_create_group(&client->dev.kobj, &mma7660_group);
    if (result != 0) {
        ERR("sysfs_create_group err\n");
        goto exit_sysfs_creat_failed;
    }      

(3) 實作sysfs屬性相關的讀寫函數;

  1. ssize_t show_orientation(struct device *dev, struct device_attribute *attr, char *buf)  
  2. u8 tilt, new_orientation;  
  3.     mma7660_read_tilt(&tilt);  
  4.     DBG("tilt [0x%x]\n", tilt);  
  5.     new_orientation = tilt & 0x1f;  
  6.     if (orientation!=new_orientation)  
  7.         orientation = new_orientation;  
  8.     switch ((orientation>>2)&0x07) {  
  9.         case 1:  
  10.             result = sprintf(buf, "Left\n");  
  11.             break;  
  12.         case 2:  
  13.             result = sprintf(buf, "Right\n");  
  14.         case 5:  
  15.             result = sprintf(buf, "Downward\n");  
  16.         case 6:  
  17.             result = sprintf(buf, "Upward\n");  
  18.         default:  
  19.             switch(orientation & 0x03) {  
  20.                 case 1:  
  21.                     result = sprintf(buf, "Front\n");  
  22.                     break;  
  23.                 case 2:  
  24.                     result = sprintf(buf, "Back\n");  
  25.                 default:  
  26.                     result = sprintf(buf, "Unknown\n");  
  27.         }  
  28.     }  
ssize_t	show_orientation(struct device *dev, struct device_attribute *attr, char *buf)
{
    int result;
u8 tilt, new_orientation;

    mma7660_read_tilt(&tilt);
    DBG("tilt [0x%x]\n", tilt);
    new_orientation = tilt & 0x1f;
    if (orientation!=new_orientation)
        orientation = new_orientation;

    switch ((orientation>>2)&0x07) {
        case 1:
        	result = sprintf(buf, "Left\n");
        	break;
        case 2:
        	result = sprintf(buf, "Right\n");
        	break;
        case 5:
        	result = sprintf(buf, "Downward\n");
        	break;
        case 6:
        	result = sprintf(buf, "Upward\n");
        	break;
        default:
        	switch(orientation & 0x03) {
            	case 1:
            		result = sprintf(buf, "Front\n");
            		break;
            	case 2:
            		result = sprintf(buf, "Back\n");
            		break;
            	default:
            		result = sprintf(buf, "Unknown\n");
        }
    }
    return result;
}      
  1. ssize_t show_xyz_force(struct device *dev, struct device_attribute *attr, char *buf)  
  2.     int i;  
  3.     s8 xyz[3];  
  4.     for (i=0; i<3; i++)  
  5.         mma7660_read_xyz(i, &xyz[i]);  
  6.     return sprintf(buf, "(%d,%d,%d)\n", xyz[0], xyz[1], xyz[2]);  
  7. ssize_t show_axis_force(struct device *dev, struct device_attribute *attr, char *buf)  
  8.     s8 force;  
  9.     int n = to_sensor_dev_attr(attr)->index;  
  10. mma7660_read_xyz(n, &force);  
  11.     return sprintf(buf, "%d\n", force);  
ssize_t show_xyz_force(struct device *dev, struct device_attribute *attr, char *buf)
{
    int i;
    s8 xyz[3];

    for (i=0; i<3; i++)
        mma7660_read_xyz(i, &xyz[i]);

    return sprintf(buf, "(%d,%d,%d)\n", xyz[0], xyz[1], xyz[2]);
}

ssize_t show_axis_force(struct device *dev, struct device_attribute *attr, char *buf)
{
    s8 force;
    int n = to_sensor_dev_attr(attr)->index;

mma7660_read_xyz(n, &force);

    return sprintf(buf, "%d\n", force);
}      

 6.3.2 Gsensor調試執行個體

[plain] view plaincopyprint?

  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)  
/sys/devices/platform/gl5201-i2c.1/i2c-1/1-004c # ls
uevent
name
modalias
subsystem
power
driver
all_axis_force
x_axis_force
y_axis_force
z_axis_force
orientation
input
/sys/devices/platform/gl5201-i2c.1/i2c-1/1-004c # cat all_axis_force 
(-1,0,22)      

7 Hardware

7.1 mma7660模組

gsensor架構和原理分析 .

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 功能子產品圖

gsensor架構和原理分析 .

7.2.2 硬體連接配接圖

gsensor架構和原理分析 .

7.2.3 運動檢測原理

mma7660是一種電容式3軸g-sensor,其技術原理是在wafer的表面做出梳狀結構,當産生動作時,由偵測電容差來判斷變形量,反推出加速度的值。

簡單實體模型如下圖:

gsensor架構和原理分析 .

7.2.4 I2C讀寫時序

gsensor架構和原理分析 .

7.2.5 工作狀态機

gsensor架構和原理分析 .

7.2.6 寄存器定義

gsensor架構和原理分析 .

7.2.7 事件檢測

gsensor架構和原理分析 .
  • 方向和搖動檢測 
gsensor架構和原理分析 .