本文主要描述了在android2.3平台G-sensor相關軟硬體的體系架構和實作原理,按照Applications、Framework、HAL、Driver和Hardware五大層次分别介紹。
1.系統架構 (Architecture)
1.1 Android體系架構圖
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iN4UzNfNzN0gDM0UzMzEzLcZjMvwFNwITMwIzLcNHZh9GbwV3LcRXZu5ibkN3YukXbvw1LcpDc0RHaiojIsJye.png)
1.2 Sensor子系統架構圖
· 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?
- @Override
- publicvoid onSensorChanged(SensorEvent event) {
- float[] values = event.values;
- mTextView.setText("Accelerometer:" + values[0] +", "
- + values[1] +", " + values[2]);
- }
- 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() {
- super.onResume();
- mSensorManager.registerListener(mEventListener, mSensor,
- SensorManager.SENSOR_DELAY_NORMAL);
super.onResume();
mSensorManager.registerListener(mEventListener, mSensor,
SensorManager.SENSOR_DELAY_NORMAL);
}
(5) 解除安裝事件監聽器;
protectedvoid onPause() {
- super.onPause();
- mSensorManager.unregisterListener(mEventListener);
super.onPause();
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 plaincopyprint?
- 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);
- };
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擷取。
- 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
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 = {
- .open = open_sensors
.open = open_sensors
};
5.2.3 sensors_poll_context_t
- 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);
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
- 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);
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
定義傳感器的基本參數。
- 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, { } },
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, { } },
};
- 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];
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驅動架構
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 探測裝置
6.2.3 移除裝置
6.2.4 采集資料
6.2.5 睡眠和喚醒
Suspend處理:關閉mma7660模組;
Resume處理:使能mma7660模組;
- 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)
- MK_MMA7660_MODE(0, 1, 0, 0, 0, 0, 1));
- 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,
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相關資料結構;
- 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,
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檔案系統;
- result = sysfs_create_group(&client->dev.kobj, &mma7660_group);
- if (result != 0) {
- ERR("sysfs_create_group err\n");
- 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屬性相關的讀寫函數;
- ssize_t show_orientation(struct device *dev, struct device_attribute *attr, char *buf)
- 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");
- case 5:
- result = sprintf(buf, "Downward\n");
- case 6:
- result = sprintf(buf, "Upward\n");
- default:
- switch(orientation & 0x03) {
- case 1:
- result = sprintf(buf, "Front\n");
- break;
- case 2:
- result = sprintf(buf, "Back\n");
- default:
- result = sprintf(buf, "Unknown\n");
- }
- }
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;
}
- 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);
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?
- /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)
/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模組
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 事件檢測
- 方向和搖動檢測