The gravity sensor works according to the principle of piezoelectric effect.
The so-called piezoelectric effect is "for the non-existence of the symmetry center of the polar crystals added to the crystal of the external force in addition to the crystal deformation, but also to change the polarization of the crystal State, in the crystal interior of the establishment of electric field, this due to the mechanical force of the phenomenon of polarization of the medium is called the positive effects."
The gravity sensor uses the property of its internal crystal deformation due to acceleration. Since this deformation generates a voltage, the acceleration can be converted to a voltage output as long as the relationship between the generated voltage and the applied acceleration is calculated. Of course, there are many other ways to make accelerometer, such as capacitive effect, hot bubble effect, light effect, but its most basic principle is due to the acceleration of a certain medium deformation, by measuring its deformation and related circuit to convert to voltage output.
bma250e
10-bit, digital, tri-axis accelerometer, motion trigger, interrupt control
Main Features: Small package, digital interface, programmable function, on-board FIFO, on-board interrupt control, low power consumption.
I²c interface, 2 interrupt pin, voltage range 1.2to3.6v
Acceleration Range: 2g/4g/8g/16g
Power trigger interrupt Signal generation: New data, detects any motion, single output and dual output, azimuth recognition, flat detection, no motion detection. Low power consumption, short wake-up time, advanced system power management
VDD is the main power supply for internal blocks
The Vddio is divided into a power supply pin to support the interface and internal blocks
Power mode:
There are six power modes, in addition to the normal mode to support the operation of this device, there are other five energy-saving modes: Deep sleep mode, sleep mode, standard mode, low power mode one and low power mode two.
Normal mode when power is turned on. In DEEP-SUSPND mode, the device is close to the lowest power consumption. Only the interface remains active. No data request is being responded to, configuration register is lost.
Offsetcompensation: Slow compensation, fast compensation, fast compensation, online calibration
Non-volatile Memory: Three types of registers: Hardwired,volatile,non-volatile
Bma250_driver.c
BMA250_DRIVER.C Code Analysis:
1, static int bma250_smbus_read_byte(struct i2c_client *client,
unsigned char reg_addr, unsigned char *data)
static int bma250_smbus_write_byte(struct i2c_client *client,
unsigned char reg_addr, unsigned char *data)
Two functions are called separately
I2c_smbus_read_byte_data (client, reg_addr);
I2c_smbus_write_byte_data (client, reg_addr, *data);
Both functions call I2c_smbus_xfer, and the function prototype is:
S32 i2c_smbus_xfer(struct i2c_adapter *adapter, U16 addr, unsigned short flags,
Char read_write, U8 command, int protocol,
Union I2c_smbus_data *data)
Two calls is the parameter char read_write This parameter has changed, read the parameter is i2c_smbus_read, write the parameter is:I2c_smbus_write, the other parameters are unchanged. The parameter int protocol represents the protocol used.
Through Export_symbol (i2c_smbus_read_byte_data) in i2c-core.c; Export this function and use it in other files.
2. Static device_attr(mode, s_irugo| S_IWUSR, Bma250_mode_show, Bma250_mode_store);
Static device_attr(value, S_irugo, Bma250_value_show, NULL);
......;
Static device_attr(update, s_irugo| S_IWUSR, NULL, Bma250_update_store);
Static device_attr(selftest, s_irugo| S_IWUSR, Bma250_selftest_show, Bma250_selftest_store);
Complete the DEVICE_ATTR function macro fill, you need to create an interface below
static struct attribute *bma250_attributes[]= {
&dev_attr_range.attr,
......
&dev_attr_offset_filt_z.attr,
&dev_attr_orientation.attr,
Null
};
when the interface name you want to implement is orientation , you need to implement the struct static struct attribute *bma250_attributes[]
the name of the member variable must be &dev_attr_orientation. attrandthen encapsulated
static struct Attribute_group Bma250_attribute_group = {
. attrs = Bma250_attributes
};
re-use Sysfs_create_group (&data->input->dev.kobj,&bma250_attribute_group) to create an interface. through the above steps, you can see the interface in the ADB shell terminal. When we echo the data into the interface, we actually complete a write operation on the upper layer, which corresponds to kernel, and calls the "store" in the driver. Similarly, "show" is called when we have a cat interface. Here, simply built the android layer to the kernel bridge, the actual implementation of the hardware operation, or in the "show" and "store" completed. These interfaces are also debug interfaces.
Program execution Process:
Board Information:
struct bma250acc{
S16 x,
Y
Z
} ;
struct bma250_data {/*kernel\lc1810\include\linux\bmc.h*/
struct I2c_client *bma250_client;//bma250 Equipment
atomic_t delay; Delay
atomic_t enable; To enable
unsigned char mode; Working mode
struct Input_dev *input; Input device
struct bma250acc value; The escalated coordinate value
struct Mutex Enable_mutex; Mutex Amount
struct Mutex Mode_mutex;
struct delayed_work work; //
struct Work_struct irq_work;
#ifdef Config_has_earlysuspend
struct Early_suspend early_suspend;
#endif
atomic_t Selftest_result;
int orientation;
};
/*kernel\lc1810\arch\arm\mach-comip\board-lc1810.c*/
#if defined (config_sensors_bma250)
static struct bma250_data bmc_bma250_data = {
. Orientation = 0,
};
#endif
Fill I2c_board_info:
static struct i2c_board_infocomip_i2c1_board_info[] = {
#if defined (config_sensors_bma250)
{
I2c_board_info ("bma250", 0x18),
. Platform_data = &bmc_bma250_data,
},
#endif
}
1, Module_init (bma250_init);
Module_exit (Bma250_exit);
static int __init bma250_init (void)
{
Return I2c_add_driver (&bma250_driver); //Load driver Bma250_driver
}
Where the driver is:
static struct I2c_driver Bma250_driver = {
. Driver = {
. Owner = This_module,
. Name = Sensor_name,
},
. id_table = bma250_id,//id_table is the ID table of the I²C device supported by the driver
. Probe = Bma250_probe,/* Bus->match after successful call */
. remove = Bma250_remove,
};
2, Bma250_probe (struct i2c_client *client,const struct i2c_device_id *id) function execution:
1), using i2c_check_functionality (Client->adapter, I2C_FUNC_I2C) Check the I²C device adapter is working properly.
2), assign space to Bma250_data and clear zero.
3), use I2c_smbus_read_word_data (client, Bma250_chip_id_reg), detect whether the bma250 ID number matches, continue, or fail.
4), let the client's data point to the newly allocated space, initialize data.
5), mutually exclusive access: use
Bma250_set_bandwidth (client, bma250_bw_set);
Bma250_set_range (client, bma250_range_set); Set bandwidth and range.
Use init_delayed_work(&data->work, bma250_work_func), dynamically initialize a queue of work, and queue handler functions Bma250_work_ Func () is bound together. Work after a period of delay.
While in the static void bma250_work_func(struct work_struct *work)
{
struct Bma250_data *bma250 = container_of (struct delayed_work *) work,
struct bma250_data, work);
static struct BMA250ACC acc;
unsigned long delay = msecs_to_jiffies (atomic_read (&bma250->delay));
bma250_read_accel_xyz (Bma250->bma250_client, &ACC);
Input_report_abs (Bma250->input, Abs_x, acc.x);
Input_report_abs (Bma250->input, abs_y, ACC.Y);
Input_report_abs (Bma250->input, Abs_z, acc.z);
Input_sync (Bma250->input);
bma250->value = ACC;
PRINTK ("_______[%s]: acc.x=%d,y=%d,z=%d\n", __func__,acc.x,acc.y,acc.z);
schedule_delayed_work (&bma250->work, delay);
}
The first is a delay of Msecs_to_jiffies (Atomic_read (&bma250->delay)) and then
bma250_read_accel_xyz (Bma250->bma250_client, &ACC) reads the value of the sensor's XYZ, and then the three points are reported through the input_report_abs () function. After a period of delay after the schedule_delayed_work () is delayed , a specific task is scheduled to execute, and the task to be executed will be suspended into the workqueue provided by the Linux system.
The Init_delayed_work () and schedule_delayed_work () functions are paired.
6), initialize the bma250_input through the Bma250_input_init (data) function. The space is first allocated through Input_allocate_device () when initializing. In the set quote range, then register the device and let Bma250_input point to it.
7), create the Sysfs interface through the Sysfs_create_group () function.
8), initialize the bma250 power management to suspend and open.
static void Bma250_early_suspend (struct early_suspend *h)
{
struct Bma250_data *data =container_of (H, struct bma250_data, early_suspend);
Mutex_lock (&data->enable_mutex);
if (Atomic_read (&data->enable) = = 1) {
Bma250_set_mode (data->bma250_client, bma250_mode_suspend);
Cancel_delayed_work_sync (&data->work);
}
Mutex_unlock (&data->enable_mutex);
}
Mutually exclusive settings bma250 The working mode is suspend, and then executes the Cancel_delayed_work_sync () function, which, for a deferred execution, cancels it when the work is not executed.
Working: static void bma250_late_resume(struct early_suspend *h)
{
struct Bma250_data *data =
Container_of (h, struct bma250_data, early_suspend);
Mutex_lock (&data->enable_mutex);
if (Atomic_read (&data->enable) = = 1) {
Bma250_set_mode (data->bma250_client, bma250_mode_normal);
schedule_delayed_work (&data->work,
Msecs_to_jiffies (Atomic_read (&data->delay)));
}
Mutex_unlock (&data->enable_mutex);
}resume first mutually exclusive work mode is set to normal operation mode, and then call the Schedule_delayed_work () function delay after a period of time to call work in the Working queue processing.
Worker threads (events), or worker threads, or more specifically, these should be the default worker threads. A worker thread-related concept is a work queue, or a job queue.events such a thread, which is actually like a kernel thread, There is something to deal with, no matter on sleep, is also a cycle of death, and Schedule_delayed_work () the role is to wake up this thread, to be sure, is to first put their own this struct work_struct insert Workqueue_ struct in this queue, and then awaken events in slumber. Then events will be processed, and if there is a delay, then it will be scheduled to execute after delay, if there is no delay, or set a delay of 0, then hurriedly start execution.
9), after initialization through the function Bma250_set_mode (client, bma250_mode_suspend); Set the sensor to the SUSPEND state. Bma250_input_delete (data) If an error occurs, and the device is released.
At this point, bma250_probe execution is complete, sensor initialization is complete.
Sensor BMA250 source Code Execution analysis