android sensor architecture and principle analysis - reprint for learning records

This paper mainly describes the architecture and implementation principle of G-sensor related software and Hardware on Android 2.3 platform, which are introduced respectively according to the five levels of Applications, Framework, HAL, Driver and Hardware.

1. System architecture

1.1 Android architecture diagram



1.2 Sensor subsystem architecture diagram


 · Application Framework

       The Sensor application obtains Sensor data through the Sensor application framework, and the Sensor Manager of the application framework layer communicates with the C + + layer through JNI.

 · Sensor Libraries

       The Sensor middle layer is mainly composed of Sensor Manager, Sensor service and Sensor hardware abstraction layer.

 · Input Subsystem

       The general Linux input framework is designed for input devices such as keyboard, mouse and touch screen, and defines a set of standard event sets. The Sensor input subsystem adopts a general Linux input framework, which interacts with the user space through the / sys/class/input node.

 · Event Dev

       Evdev provides a common way to access / dev/input/eventX input device events.

 · AccelerometerDriver

       The driver communicates with MMA7660 module through SIRQ and I2C bus. SIRQ is used to generate sensor event interrupts.

 

2 applications

two point one   Five steps of application development

(1)     Obtain the sensor manager object;

mSensorManager =(SensorManager) getSystemService(SENSOR_SERVICE);

(2)     Acquiring sensor objects;

mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

(3)    Define event listeners;

mEventListener =new SensorEventListener() {

    
  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) {
  9. }
  10. };

(4)     Register event listeners;

protectedvoid onResume() {

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

(5)     Uninstall the event listener;

protectedvoid onPause() {

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

3 framework

3.1 working model



3.1.1 creation of sensormanager



nativeClassInit(): initializes Native class information;
sensors_module_init(): create a Native SensorManager instance and read the Sensor device list from SensorService;
sensors_module_get_next_sensor(): read the next sensor device from SensorService;

3.1.2 SensorThread data receiving and processing



sensors_create_queue(): create a message queue shared with SensorService;
sensors_data_poll(): read the message sent by SensorService from the message queue;

3.1.3 working principle of sensorservice



SensorDevice::poll(): call HAL interface to read data;
SensorEventConnection::sendEvents(): write a message to the message queue, and SensorThread will read the message later;

3.1.4   SensorDevice access to HAL



4 hardware abstraction layer (HAL)


In the linux operating system, the interaction between applications and hardware is realized through device drivers. In order to reduce the development difficulty of application developers, shield hardware differences, Android system defines a hardware abstraction layer to provide developers with an interface to obtain various device related information.

four point one   Sensors HAL key processes

4.1.1   Turn on the Sensor device


Sensorbase:: openinput(): open the sensor message file handle of the input subsystem;
IOCTL (evocgabs (...): get ABS_ X/ABS_ Y/ABS_ Acceleration of Z;

4.1.2   Round robin Sensor event


InputEventCircularReader::fill(): call read() to read events from the input subsystem and put them into the ring buffer;
InputEventCircularReader::readEvent(): reads events from the ring buffer;
InputEventCircularReader::next(): move the current pointer of the ring buffer;

five point two   Sensors HAL key data structure

5.2.1 sensors_module_t

    
  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. };

hw_get_module() will load the Hal module and return the Hal entry data structure (hw_module_t). HAL_MODULE_INFO_SYM defaults to "Hal" in hw_get_module is obtained with 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
  12. };

5.2.2 hw_module_methods_t
  static struct hw_module_methods_t sensors_module_methods = {
    
  1. .open = open_sensors
  2. };

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);
  9. };

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);
  9. };

5.2.5 sensor_t
Define the basic parameters of the sensor.
    
  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, { } },
  6. };
    
  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];
  12. };


6 driver

six point one   Mm7660 drive frame


The mma7660 communicates with the host through the I2C interface. Therefore, the mma7660 driver is implemented by using the I2C subsystem framework of Linux system, which is mainly composed of three parts:
 
(1) I2C core
I2C core provides the registration and cancellation methods of I2C bus driver and device driver, the upper code of I2C communication method (i.e. "algorithm") independent of specific adapter, and the upper code of detection device and detection device address. This part is platform independent.
This part is implemented in the I2C driver of the Linux kernel. The mma7660 driver uses the functional interface it provides to register the device driver.

(2) I2C bus driver
I2C bus driver is the implementation of adapter in I2C hardware architecture. I2C bus driver mainly includes I2C adapter data structure_ algorithm data structure of adapter and I2C adapter_ algorithm and function controlling I2C adapter to generate communication signal. Through the I2C bus driven code, we can control the I2C adapter to generate start bit, stop bit and read-write cycle in the master mode, and to be read-write and generate ACK in the slave mode. Different CPU platforms correspond to different I2C bus drivers.
This part is implemented in the I2C driver of the Linux kernel. The mma7660 driver directly obtains the adapter provided by it and calls the interface of the I2C core to register.

(3) I2C device driver
I2C device driver is the implementation of device end in I2C hardware architecture. The device is generally connected to the I2C adapter controlled by the CPU, and exchanges data with the CPU through the I2C adapter. I2C device driver mainly includes data structure i2c_driver and I2C_ The client and mma7660 drivers need to implement the member functions.
I2C in the drivers directory in the Linux kernel source code_ Dev.c file, which realizes the function of I2C adapter device file. The application program accesses the device through "i2c-%d" file name and using file operation interfaces open(), write(), read(), ioctl() and close(). The application layer can use these interfaces to access the storage space or registers of the I2C device attached to the adapter and control the working mode of the I2C device.

six point two   Mm7660 operation flow

6.2.1   initialization


6.2.2   Detection equipment



6.2.3   Remove device



6.2.4   Collect data



6.2.5   Sleep and wake

Suspend processing: close mma7660 module;
Resume processing: enable mma7660 module;
 
    
  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. }
  9. static int mma7660_resume(struct i2c_client *client)
  10. {
  11. int result;
  12. result = i2c_smbus_write_byte_data(client, MMA7660_MODE,
  13. MK_MMA7660_MODE( 0, 1, 0, 0, 0, 0, 1));
  14. assert(result== 0);
  15. return result;
  16. }
  17. static struct i2c_driver mma7660_driver = {
  18. .driver = {
  19. .name = MMA7660_DRV_NAME,
  20. .owner = THIS_MODULE,
  21. },
  22. . class = I2C_CLASS_HWMON,
  23. .suspend = mma7660_suspend,
  24. .resume = mma7660_resume,
  25. .probe = mma7660_probe,
  26. .detect = mma7660_detect,
  27. // .address_data = &addr_data,
  28. .remove = __devexit_p(mma7660_remove),
  29. .id_table = mma7660_id,
  30. };

six point three   Command line debugging

6.3.1   sysfs debug interface

(1) Define data structures related to 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. {
  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. static const struct attribute_group mma7660_group =
  16. {
  17. .attrs = mma7660_attrs,
  18. };


(2) Create sysfs file system in probe function;
 
    
  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;
  5. }


(3) Implement the read-write function related to sysfs attribute;
    
  1. ssize_t show_orientation(struct device *dev, struct device_attribute *attr, char *buf)
  2. {
  3. int result;
  4. u8 tilt, new_orientation;
  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. switch ((orientation>> 2)& 0x07) {
  11. case 1:
  12. result = sprintf(buf, "Left\n");
  13. break;
  14. case 2:
  15. result = sprintf(buf, "Right\n");
  16. break;
  17. case 5:
  18. result = sprintf(buf, "Downward\n");
  19. break;
  20. case 6:
  21. result = sprintf(buf, "Upward\n");
  22. break;
  23. default:
  24. switch(orientation & 0x03) {
  25. case 1:
  26. result = sprintf(buf, "Front\n");
  27. break;
  28. case 2:
  29. result = sprintf(buf, "Back\n");
  30. break;
  31. default:
  32. result = sprintf(buf, "Unknown\n");
  33. }
  34. }
  35. return result;
  36. }
    
  1. ssize_t show_xyz_force(struct device *dev, struct device_attribute *attr, char *buf)
  2. {
  3. int i;
  4. s8 xyz[ 3];
  5. for (i= 0; i< 3; i++)
  6. mma7660_read_xyz(i, &xyz[i]);
  7. return sprintf(buf, "(%d,%d,%d)\n", xyz[ 0], xyz[ 1], xyz[ 2]);
  8. }
  9. ssize_t show_axis_force(struct device *dev, struct device_attribute *attr, char *buf)
  10. {
  11. s8 force;
  12. int n = to_sensor_dev_attr(attr)->index;
  13. mma7660_read_xyz(n, &force);
  14. return sprintf(buf, "%d\n", force);
  15. }

  6.3.2   Gsensor debugging instance
/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

seven point one   Mm7660 module


seven point two   Key characteristics
  • 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   Functional module diagram


7.2.2   Hardware connection diagram


7.2.3   Motion detection principle

mma7660 is a capacitive 3-axis g-sensor. Its technical principle is to make a comb structure on the surface of wafer. When action occurs, the deformation is judged by detecting the capacitance difference, and the value of acceleration is deduced.
The simple physical model is shown as follows:

7.2.4   I2C read / write timing


7.2.5   Working state machine


7.2.6   Register definition


7.2.7   event detection


  • Direction and shake detection  

  • Tap or tilt detection
 



 

Keywords: Android

Added by amitvedak on Tue, 19 Oct 2021 10:16:40 +0300