Monday, 1 December 2014

Gyroscope vs Accelerometer

Introduction

This guide is intended to everyone interested in in using Accelerometers and Gyroscopes as well as combination IMU devices (Inertial Measurement Unit) in their electronics projects
We'll cover:
  • What does an accelerometer measure?
  • What does a gyroscope (aka gyro) measure?
  • How to convert analog-to-digital (ADC) readings that you get from these sensor to physical units (those would be g for accelerometer, deg/s for gyroscope)
  • How to combine accelerometer and gyroscope readings in order to obtain accurate information about the inclination of your device relative to the ground plane
Throughout the article I will try to keep the math to the minimum. If you know what Sine/Cosine/Tangent are then you should be able to understand and use these ideas in your project no matter what platform you're using: Arduino, Propeller, Basic Stamp, Atmel chips, Microchip PIC, etc.

There are people out there who believe that you need complex math in order to make use of an IMU unit (complex FIR or IIR filters such as Kalman filters, Parks-McClellan filters, etc). You can research all those and achieve wonderful but complex results. My way of explaining things require just basic math. I am a great believer in simplicity. I think a system that is simple is easier to control and monitor, besides many embedded devices do not have the power and resources to implement complex algorithms requiring matrix calculations.
I'll use as an example a new IMU unit, the Acc_Gyro Accelerometer + Gyro IMU. We'll use parameters of this device in our examples below. This unit is a good device to start with because it consists of 2 devices:
- LIS331AL (data sheet) - a triaxial 2G accelerometer
- LPR550AL (data sheet) - a dual-axis pitch and roll, 500 deg/sec gyroscope
Together they represent a 5-Degrees of Freedom Inertial Measurement Unit. Now that's a fancy name! Nevertheless, behind the fancy name is a very useful combination device that we'll cover and explain in detail in this guide.

 
Remove these adsRemove these ads by Signing Up

Step 1: The Accelerometer

To understand this unit we'll start with the accelerometer. When thinking about accelerometers it is often useful to image a box in shape of a cube with a ball inside it. You may imagine something else like a cookie or a donut , but I'll imagine a ball:accelerometer model If we take this box in a place with no gravitation fields or for that matter with no other fields that might affect the ball's position - the ball will simply float in the middle of the box. You can imagine the box is in outer-space far-far away from any cosmic bodies, or if such a place is hard to find imagine at least a space craft orbiting around the planet where everything is in weightless state . From the picture above you can see that we assign to each axis a pair of walls (we removed the wall Y+ so we can look inside the box). Imagine that each wall is pressure sensitive. If we move suddenly the box to the left (we accelerate it with acceleration 1g = 9.8m/s^2), the ball will hit the wall X-. We then measure the pressure force that the ball applies to the wall and output a value of -1g on the X axis.
accelerometer model
Please note that the accelerometer will actually detect a force that is directed in the opposite direction from the acceleration vector. This force is often called Inertial Force or Fictitious Force . One thing you should learn from this is that an accelerometer measures acceleration indirectly through a force that is applied to one of it's walls (according to our model, it might be a spring or something else in real life accelerometers). This force can be caused by the acceleration , but as we'll see in the next example it is not always caused by acceleration.
If we take our model and put it on Earth the ball will fall on the Z- wall and will apply a force of 1g on the bottom wall, as shown in the picture below:
accelerometer model
In this case the box isn't moving but we still get a reading of -1g on the Z axis. The pressure that the ball has applied on the wall was caused by a gravitation force. In theory it could be a different type of force - for example, if you imagine that our ball is metallic, placing a magnet next to the box could move the ball so it hits another wall. This was said just to prove that in essence accelerometer measures force not acceleration. It just happens that acceleration causes an inertial force that is captured by the force detection mechanism of the accelerometer.
While this model is not exactly how a MEMS sensor is constructed it is often useful in solving accelerometer related problems. There are actually similar sensors that have metallic balls inside, they are called tilt switches, however they are more primitive and usually they can only tell if the device is inclined within some range or not, not the extent of inclination.
So far we have analyzed the accelerometer output on a single axis and this is all you'll get with a single axis accelerometers. The real value of triaxial accelerometers comes from the fact that they can detect inertial forces on all three axes. Let's go back to our box model, and let's rotate the box 45 degrees to the right. The ball will touch 2 walls now: Z- and X- as shown in the picture below:
accelerometer model
The values of 0.71 are not arbitrary, they are actually an approximation for SQRT(1/2). This will become more clear as we introduce our next model for the accelerometer.
In the previous model we have fixed the gravitation force and rotated our imaginary box. In last 2 examples we have analyzed the output in 2 different box positions, while the force vector remained constant. While this was useful in understanding how the accelerometer interacts with outside forces, it is more practical to perform calculations if we fix the coordinate system to the axes of the accelerometer and imagine that the force vector rotates around us.
accelerometer model
Please have a look at the model above, I preserved the colors of the axes so you can make a mental transition from the previous model to the new one. Just imagine that each axis in the new model is perpendicular to the respective faces of the box in the previous model. The vector R is the force vector that the accelerometer is measuring (it could be either the gravitation force or the inertial force from the examples above or a combination of both). Rx, Ry, Rz are projection of the R vector on the X,Y,Z axes. Please notice the following relation:
R^2 = Rx^2 + Ry^2 + Rz^2     (Eq. 1)
which is basically the equivalent of the Pythagorean theorem in 3D.
Remember that a little bit earlier I told you that the values of SQRT(1/2) ~ 0.71 are not random. If you plug them in the formula above, after recalling that our gravitation force was 1 g we can verify that:
1^2 = (-SQRT(1/2) )^2 + 0 ^2 + (-SQRT(1/2))^2
simply by substituting R=1, Rx = -SQRT(1/2), Ry = 0 , Rz = -SQRT(1/2) in Eq.1
After a long preamble of theory we're getting closer to real life accelerometers. The values Rx, Ry, Rz are actually linearly related to the values that your real-life accelerometer will output and that you can use for performing various calculations.
Before we get there let's talk a little about the way accelerometers will deliver this information to us. Most accelerometers will fall in two categories: digital and analog. Digital accelerometers will give you information using a serial protocol like I2C , SPI or USART, while analog accelerometers will output a voltage level within a predefined range that you have to convert to a digital value using an ADC (analog to digital converter) module. I will not go into much detail about how ADC works, partly because it is such an extensive topic and partly because it is different from one platform to another. Some microcontroller will have a built-in ADC modules some of them will need external components in order to perform the ADC conversions. No matter what type of ADC module you use you'll end up with a value in a certain range. For example a 10-bit ADC module will output a value in the range of 0..1023, note that 1023 = 2^10 -1. A 12-bit ADC module will output a value in the range of 0..4095, note that 4095 = 2^12-1.
Let's move on by considering a simple example, suppose our 10bit ADC module gave us the following values for the three accelerometer channels (axes):
AdcRx = 586
AdcRy = 630
AdcRz = 561
Each ADC module will have a reference voltage, let's assume in our example it is 3.3V. To convert a 10bit adc value to voltage we use the following formula:
VoltsRx = AdcRx * Vref / 1023
A quick note here: that for 8bit ADC the last divider would be 255 = 2 ^ 8 -1 , and for 12bit ADC last divider would be 4095 = 2^12 -1.
Applying this formula to all 3 channels we get:
VoltsRx = 586 * 3.3V / 1023 =~ 1.89V (we round all results to 2 decimal points)
VoltsRy = 630 * 3.3V / 1023 =~ 2.03V
VoltsRz = 561 * 3.3V / 1023 =~ 1.81V
Each accelerometer has a zero-g voltage level, you can find it in specs, this is the voltage that corresponds to 0g. To get a signed voltage value we need to calculate the shift from this level. Let's say our 0g voltage level is VzeroG = 1.65V. We calculate the voltage shifts from zero-g voltage as follows::
DeltaVoltsRx = 1.89V - 1.65V = 0.24V
DeltaVoltsRy = 2.03V - 1.65V = 0.38V
DeltaVoltsRz = 1.81V - 1.65V = 0.16V
We now have our accelerometer readings in Volts , it's still not in g (9.8 m/s^2), to do the final conversion we apply the accelerometer sensitivity, usually expressed in mV/g. Lets say our Sensitivity = 478.5mV/g = 0.4785V/g. Sensitivity values can be found in accelerometer specifications. To get the final force values expressed in g we use the following formula:
Rx = DeltaVoltsRx / Sensitivity
Rx = 0.24V / 0.4785V/g =~ 0.5g
Ry = 0.38V / 0.4785V/g =~ 0.79g
Rz = 0.16V / 0.4785V/g =~ 0.33g
We could of course combine all steps in one formula, but I went through all the steps to make it clear how you go from ADC readings to a force vector component expressed in g.
Rx = (AdcRx * Vref / 1023 - VzeroG) / Sensitivity (Eq.2)
Ry = (AdcRy * Vref / 1023 - VzeroG) / Sensitivity
Rz = (AdcRz * Vref / 1023 - VzeroG) / Sensitivity
We now have all 3 components that define our inertial force vector, if the device is not subject to other forces other than gravitation, we can assume this is the direction of our gravitation force vector. If you want to calculate inclination of device relative to the ground you can calculate the angle between this vector and Z axis. If you are also interested in per-axis direction of inclination you can split this result into 2 components: inclination on the X and Y axis that can be calculated as the angle between gravitation vector and X / Y axes. Calculating these angles is more simple than you might think, now that we have calculated the values for Rx,Ry and Rz. Let's go back to our last accelerometer model and do some additional notations:

The angles that we are interested in are the angles between X,Y,Z axes and the force vector R. We'll define these angles as Axr, Ayr, Azr. You can notice from the right-angle triangle formed by R and Rx that:
cos(Axr) = Rx / R , and similarly :
cos(Ayr) = Ry / R
cos(Azr) = Rz / R
We can deduct from Eq.1 that R = SQRT( Rx^2 + Ry^2 + Rz^2).
We can find now our angles by using arccos() function (the inverse cos() function ):
Axr = arccos(Rx/R)
Ayr = arccos(Ry/R)
Azr = arccos(Rz/R)
We've gone a long way to explain the accelerometer model, just to come up to these formulas. Depending on your applications you might want to use any intermediate formulas that we have derived. We'll also introduce the gyroscope model soon, and we'll see how accelerometer and gyroscope data can be combined to provide even more accurate inclination estimations.
But before we do that let's do some more useful notations:
cosX = cos(Axr) = Rx / R
cosY = cos(Ayr) = Ry / R
cosZ = cos(Azr) = Rz / R
This triplet is often called Direction Cosine , and it basically represents the unit vector (vector with length 1) that has same direction as our R vector. You can easily verify that:
SQRT(cosX^2 + cosY^2 + cosZ^2) = 1
This is a nice property since it absolve us from monitoring the modulus(length) of R vector. Often times if we're just interested in direction of our inertial vector, it makes sense to normalize it's modulus in order to simplify other calculations.

Step 2: Gyroscope

We're not going to introduce any equivalent box model for the gyroscope like we did for accelerometer, instead we're going to jump straight to the second accelerometer model and we'll show what does the gyroscope measure according to this model.
Each gyroscope channel measures the rotation around one of the axes. For instance a 2-axes gyroscope will measure the rotation around (or some may say "about") the X and Y axes. To express this rotation in numbers let's do some notations. First let's define:
Rxz - is the projection of the inertial force vector R on the XZ plane
Ryz - is the projection of the inertial force vector R on the YZ plane
From the right-angle triangle formed by Rxz and Rz, using Pythagorean theorem we get:
Rxz^2 = Rx^2 + Rz^2 , and similarly:
Ryz^2 = Ry^2 + Rz^2
also note that:
R^2 = Rxz^2 + Ry^2 , this can be derived from Eq.1 and above equations, or it can be derived from right-angle triangle formed by R and Ryz
R^2 = Ryz^2 + Rx^2
We're not going to use these formulas in this article but it is useful to note the relation between all the values in our model.
Instead we're going to define the angle between the Z axis and Rxz, Ryz vectors as follows:
Axz - is the angle between the Rxz (projection of R on XZ plane) and Z axis
Ayz - is the angle between the Ryz (projection of R on YZ plane) and Z axis
Now we're getting closer to what the gyroscope measures. Gyroscope measures the rate of changes of the angles defined above. In other words it will output a value that is linearly related to the rate of change of these angles. To explain this let's assume that we have measured the rotation angle around axis Y (that would be Axz angle) at time t0, and we define it as Axz0, next we measured this angle at a later time t1 and it was Axz1. The rate of change will be calculated as follows:
RateAxz = (Axz1 - Axz0) / (t1 - t0).
If we express Axz in degrees, and time in seconds , then this value will be expressed in deg/s . This is what a gyroscope measures.
In practice a gyroscope(unless it is a special digital gyroscope) will rarely give you a value expressed in deg/s. Same as for accelerometer you'll get an ADC value that you'll need to convert to deg/s using a formula similar to Eq. 2 that we have defined for accelerometer. Let's introduce the ADC to deg/s conversion formula for gyroscope (we assume we're using a 10bit ADC module , for 8bit ADC replace 1023 with 255, for 12bit ADC replace 1023 with 4095).
RateAxz = (AdcGyroXZ * Vref / 1023 - VzeroRate) / Sensitivity Eq.3
RateAyz = (AdcGyroYZ * Vref / 1023 - VzeroRate) / Sensitivity
AdcGyroXZ, AdcGyroYZ - are obtained from our adc module and they represent the channels that measure the rotation of projection of R vector in XZ respectively in YZ planes, which is the equivalent to saying rotation was done around Y and X axes respectively.

Vref - is the ADC reference voltage we'll use 3.3V in the example below

VzeroRate - is the zero-rate voltage, in other words the voltage that the gyroscope outputs when it is not subject to any rotation, for the Acc_Gyro board it is for example 1.23V (you can find this values in the specs)

Sensitivity - is the sensitivity of your gyroscope it is expressed in mV / (deg / s) often written as mV/deg/s , it basically tells you how many mV will the gyroscope output increase , if you increase the rotation speed by one deg/s. The sensitivity of Acc_Gyro board is for example 2mV/deg/s or 0.002V/deg/s
Let's take an example, suppose our ADC module returned following values:
AdcGyroXZ = 571
AdcGyroXZ = 323
Using the above formula, and using the specs parameters of Acc_Gyro board we'll get:
RateAxz = (571 * 3.3V / 1023 - 1.23V) / ( 0.002V/deg/s) =~ 306 deg/s
RateAyz = (323 * 3.3V / 1023 - 1.23V) / ( 0.002V/deg/s) =~ -94 deg/s
In other words the device rotates around the Y axis (or we can say it rotates in XZ plane) with a speed of 306 deg/s and around the X axis (or we can say it rotates in YZ plane) with a speed of -94 deg/s. Please note that the negative sign means that the device rotates in the opposite direction from the conventional positive direction. By convention one direction of rotation is positive. A good gyroscope specification sheet will show you which direction is positive, otherwise you'll have to find it by experimenting with the device and noting which direction of rotation results in increasing voltage on the output pin. This is best done using an oscilloscope since as soon as you stop the rotation the voltage will drop back to the zero-rate level. If you're using a multimeter you'd have to maintain a constant rotation rate for at least few seconds and note the voltage during this rotation, then compare it with the zero-rate voltage. If it is greater than the zero-rate voltage it means that direction of rotation is positive.

Step 3: Combining the Accelerometer and Gyro

Putting it all together - Combining accelerometer and gyroscope data.

If you're reading this article you probably acquired or are planning to acquire a IMU device, or probably you're planning to build one from separate accelerometer and gyroscope devices.
The first step in using a combination IMU device that combines an accelerometer and a gyroscope is to align their coordinate systems. The easiest way to do it is to choose the coordinate system of accelerometer as your reference coordinate system. Most accelerometer data sheets will display the direction of X,Y,Z axes relative to the image of the physical chip or device. For example here are the directions of X,Y,Z axes as shown in specifications for the Acc_Gyro board:
acc_gyro axes
Next steps are:
  • Identify the gyroscope outputs that correspond to RateAxz , RateAyz values discussed above.Determine if these outputs need to be inverted due to physical position of gyroscope relative to the accelerometer
Do not assume that if a gyroscope has an output marked X or Y, it will correspond to any axis in the accelerometer coordinate system, even if this output is part of an IMU unit. The best way is to test it. Assuming you have fixed the position of gyroscope relative to the accelerometer. It is assumed that the gyro and accelerometer borders are parallel to each other, i.e. you're placing the gyro at an angle multiple of 90deg relative to the accelerometer chip. If you acquired an IMU board chances are that they are already aligned this way. We're not going to discuss in this article models where gyroscope is placed at an irregular angle relative to accelerometer (let's say 45 or 30 degrees), although this might be useful in some applications.
Here is a sample sequence to determine which output of gyroscope corresponds to RateAxz value discussed above.
- start from placing the device in horizontal position. Both X and Y outputs of accelerometer would output the zero-g voltage (for example for Acc_Gyro board this is 1.65V)

- next start rotating the device around the Y axis, another way to say it is that you rotate the device in XZ plane, so that X and Z accelerometer outputs change and Y output remains constant.

- while rotating the device at a constant speed note which gyroscope output changes, the other gyroscope outputs should remain constant

- the gyroscope output that changed during the rotation around Y axis (rotation in XZ plane) will provide the input value for AdcGyroXZ, from which we calculate RateAxz

- the final step is to ensure the rotation direction corresponds to our model, in some cases you may have to invert the RateAxz value due to physical position of gyroscope relative to the accelerometer

- perform again the above test, rotating the device around the Y axis, this time monitor the X output of accelerometer (AdcRx in our model). If AdcRx grows (the first 90 degrees of rotation from horizontal position), then AdcGyroXZ should also grow. Otherwise you need to invert RateAxz , you can achieve this by introducing a sign factor in Eq.3, as follows:
RateAxz = InvertAxz * (AdcGyroXZ * Vref / 1023 - VzeroRate) / Sensitivity , where InvertAxz is 1 or -1
same test cane be done for RateAyz , by rotating the device around the X axis, and you can identify which gyroscope output corresponds to RateAyz, and if it needs to be inverted. Once you have the value for InvertAyz, you should use the following formula to calculate RateAyz:
RateAyz = InvertAyz * (AdcGyroYZ * Vref / 1023 - VzeroRate) / Sensitivity
If you would do these tests on Acc_Gyro board you would get following results:
- the output pin for RateAxz is GX4 and InvertAxz = -1.
- the output pin for RateAyz is GY4 and InvertAyz = -1
From this point on we'll consider that you have setup your IMU in such a way that you can calculate correct values for Axr, Ayr, Azr (as defined Part 1. Accelerometer) and RateAxz, RateAyz (as defined in Part 2. Gyroscope). Next we'll analyze the relations between these values that turn out useful in obtaining more accurate estimation of the inclination of the device relative to the ground plane.
You might be asking yourself by this point, if accelerometer model already gave us inclination angles of Axr,Ayr,Azr why would we want to bother with the gyroscope data ? The answer is simple: accelerometer data can't always be trusted 100%. There are several reason, remember that accelerometer measures inertial force, such a force can be caused by gravitation (and ideally only by gravitation), but it might also be caused by acceleration (movement) of the device. As a result even if accelerometer is in a relatively stable state, it is still very sensitive to vibration and mechanical noise in general. This is the main reason why most IMU systems use a gyroscope to smooth out any accelerometer errors. But how is this done ? And is the gyroscope free from noise ?
The gyroscope is not free from noise however because it measures rotation it is less sensitive to linear mechanical movements, the type of noise that accelerometer suffers from, however gyroscopes have other types of problems like for example drift (not coming back to zero-rate value when rotation stops). Nevertheless by averaging data that comes from accelerometer and gyroscope we can obtain a relatively better estimate of current device inclination than we would obtain by using the accelerometer data alone.
In the next steps I will introduce an algorithm that was inspired by some ideas used in Kalman filter, however it is by far more simple and easier to implement on embedded devices. Before that let's see first what we want our algorithm to calculate. Well , it is the direction of gravitation force vector R = [Rx,Ry,Rz] from which we can derive other values like Axr,Ayr,Azr or cosX,cosY,cosZ that will give us an idea about the inclination of our device relative to the ground plane, we discuss the relation between these values in Part 1. One might say - don't we already have these values Rx, Ry , Rz from Eq.2 in Part 1 ? Well yes, but remember that these values are derived from accelerometer data only, so if you would be to use them directly in your application you might get more noise than your application can tolerate. To avoid further confusion let's re-define the accelerometer measurements as follows:
Racc - is the inertial force vector as measured by accelerometer, that consists of following components (projections on X,Y,Z axes):
RxAcc = (AdcRx * Vref / 1023 - VzeroG) / Sensitivity
RyAcc = (AdcRy * Vref / 1023 - VzeroG) / Sensitivity
RzAcc = (AdcRz * Vref / 1023 - VzeroG) / Sensitivity
So far we have a set of measured values that we can obtain purely from accelerometer ADC values. We'll call this set of data a "vector" and we'll use the following notation.
Racc = [RxAcc,RyAcc,RzAcc]
Because these components of Racc can be obtained from accelerometer data , we can consider it an input to our algorithm.
Please note that because Racc measures the gravitation force you'll be correct if you assume that the length of this vector defined as follows is equal or close to 1g.
|Racc| = SQRT(RxAcc^2 +RyAcc^2 + RzAcc^2),
However to be sure it makes sense to update this vector as follows:
Racc(normalized) = [RxAcc/|Racc| , RyAcc/|Racc| , RzAcc/|Racc|].
This will ensure the length of your normalized Racc vector is always 1.
Next we'll introduce a new vector and we'll call it
Rest = [RxEst,RyEst,RzEst]
This will be the output of our algorithm , these are corrected values based on gyroscope data and based on past estimated data.
Here is what our algorithm will do:
- accelerometer tells us: "You are now at position Racc"
- we say "Thank you, but let me check",
- then correct this information with gyroscope data as well as with past Rest data and we output a new estimated vector Rest.
- we consider Rest to be our "best bet" as to the current position of the device.
Let's see how we can make it work.
We'll start our sequence by trusting our accelerometer and assigning:
Rest(0) = Racc(0)
By the way remember Rest and Racc are vectors , so the above equation is just a simple way to write 3 sets of equations, and avoid repetition:
RxEst(0) = RxAcc(0)
RyEst(0) = RyAcc(0)
RzEst(0) = RzAcc(0)
Next we'll do regular measurements at equal time intervals of T seconds, and we'll obtain new measurements that we'll define as Racc(1), Racc(2) , Racc(3) and so on. We'll also issue new estimates at each time intervals Rest(1), Rest(2), Rest(3) and so on.
Suppose we're at step n. We have two known sets of values that we'd like to use:
Rest(n-1) - our previous estimate, with Rest(0) = Racc(0)
Racc(n) - our current accelerometer measurement
Before we can calculate Rest(n) , let's introduce a new measured value, that we can obtain from our gyroscope and a previous estimate.
We'll call it Rgyro , and it is also a vector consisting of 3 components:
Rgyro = [RxGyro,RyGyro,RzGyro]
We'll calculate this vector one component at a time. We'll start with RxGyro.
gyro model
Let's start by observing the following relation in our gyroscope model, from the right-angle triangle formed by Rz and Rxz we can derive that:
tan(Axz) = Rx/Rz => Axz = atan2(Rx,Rz)
Atan2 might be a function you never used before, it is similar to atan, except it returns values in range of (-PI,PI) as opposed to (-PI/2,PI/2) as returned by atan, and it takes 2 arguments instead of one. It allows us to convert the two values of Rx,Rz to angles in the full range of 360 degrees (-PI to PI). You can read more about atan2 here.
So knowing RxEst(n-1) , and RzEst(n-1) we can find:
Axz(n-1) = atan2( RxEst(n-1) , RzEst(n-1) ).
Remember that gyroscope measures the rate of change of the Axz angle. So we can estimate the new angle Axz(n) as follows:
Axz(n) = Axz(n-1) + RateAxz(n) * T
Remember that RateAxz can be obtained from our gyroscope ADC readings. A more precise formula can use an average rotation rate calculated as follows:
RateAxzAvg = ( RateAxz(n) + RateAxz(n-1) ) / 2
Axz(n) = Axz(n-1) + RateAxzAvg * T
The same way we can find:
Ayz(n) = Ayz(n-1) + RateAyz(n) * T
Ok so now we have Axz(n) and Ayz(n). Where do we go from here to deduct RxGyro/RyGyro ? From Eq. 1 we can write the length of vector Rgyro as follows:
|Rgyro| = SQRT(RxGyro^2 + RyGyro^2 + RzGyro^2)
Also because we normalized our Racc vector, we may assume that it's length is 1 and it hasn't changed after the rotation, so it is relatively safe to write:
|Rgyro| = 1
Let's adopt a temporary shorter notation for the calculations below:
x =RxGyro , y=RyGyro, z=RzGyro
Using the relations above we can write:
x = x / 1 = x / SQRT(x^2+y^2+z^2)
Let's divide numerator and denominator of fraction by SQRT(x^2 + z^2)
x = ( x / SQRT(x^2 + z^2) ) / SQRT( (x^2 + y^2 + z^2) / (x^2 + z^2) )
Note that x / SQRT(x^2 + z^2) = sin(Axz), so:
x = sin(Axz) / SQRT (1 + y^2 / (x^2 + z^2) )
Now multiply numerator and denominator of fraction inside SQRT by z^2
x = sin(Axz) / SQRT (1 + y^2  * z ^2 / (z^2 * (x^2 + z^2)) )
Note that z / SQRT(x^2 + z^2) = cos(Axz) and y / z = tan(Ayz), so finally:
x = sin(Axz) / SQRT (1 + cos(Axz)^2 * tan(Ayz)^2 )
Going back to our notation we get:
RxGyro = sin(Axz(n)) / SQRT (1 + cos(Axz(n))^2 * tan(Ayz(n))^2 )
same way we find that
RyGyro = sin(Ayz(n)) / SQRT (1 + cos(Ayz(n))^2 * tan(Axz(n))^2 )
Now, finally we can find:
RzGyro  =  Sign(RzGyro)*SQRT(1 - RxGyro^2 - RyGyro^2).
Where Sign(RzGyro) = 1 when RzGyro>=0 , and Sign(RzGyro) = -1 when RzGyro<0.
One simple way to estimate this is to take:
Sign(RzGyro) = Sign(RzEst(n-1))
In practice be careful when RzEst(n-1) is close to 0. You may skip the gyro phase altogether in this case and assign:  Rgyro = Rest(n-1). Rz is used as a reference for calculating Axz and Ayz angles and when it's close to 0, values may oveflow and trigger bad results. You'll be in domain of large floating point numbers where tan() / atan() function implementations may lack precision.

So let's recap what we have so far, we are at step n of our algorithm and we have calculated the following values:
Racc - current readings from our accelerometer
Rgyro - obtained from Rest(n-1) and current gyroscope readings
Which values do we use to calculate the updated estimate Rest(n) ? You probably guessed that we'll use both. We'll use a weighted average, so that:
Rest(n) = (Racc * w1 + Rgyro * w2 ) / (w1 + w2)
We can simplify this formula by dividing both numerator and denominator of the fraction by w1.
Rest(n) = (Racc * w1/w1 + Rgyro * w2/w1 ) / (w1/w1 + w2/w1)
and after substituting w2/w1 = wGyro we get:
Rest(n) = (Racc + Rgyro * wGyro ) / (1 + wGyro)
In the above forumula wGyro tells us how much we trust our gyro compared to our accelerometer. This value can be chosen experimentally usually values between 5..20 will trigger good results.
The main difference of this algorithm from Kalman filter is that this weight is relatively fixed , whereas in Kalman filter the weights are permanently updated based on the measured noise of the accelerometer readings. Kalman filter is focused at giving you "the best" theoretical results, whereas this algorithm can give you results "good enough" for your practical application. You can implement an algorithm that adjusts wGyro depending on some noise factors that you measure, but fixed values will work well for most applications.
We are one step away from getting our updated estimated values:
RxEst(n) = (RxAcc + RxGyro * wGyro ) / (1 + wGyro)
RyEst(n) = (RyAcc + RyGyro * wGyro ) / (1 + wGyro)
RzEst(n) = (RzAcc + RzGyro * wGyro ) / (1 + wGyro)
Now let's  normalize this vector again:
R = SQRT(RxEst(n) ^2 + RyEst(n)^2 +  RzEst(n)^2 )
RxEst(n) = RxEst(n)/R
RyEst(n) = RyEst(n)/R
RzEst(n) = RzEst(n)/R
And we're ready to repeat our loop again.

This guide originally appeared on starlino.com, I've made a few light edits and re-posted it with permission. Thanks Starlino!

Reading analog (ADC) values on BeagleBone black

ADC value on BBB
There are 7 analog inputs on the BeagleBone.

ADC properties:
 - 12 bits (Output values in the range 0-4095)
 - 125ns sample time
 - 0-1.8V range (do not exceed!)
 - 2 uA current flows into the ADC pin in this range
 - If using a voltage divider, the lower leg (the one connected to ground) should be <= 1k Ohm
 - Since we are measuring millivolts, resistors with 0.1% error tolerance should be used in a voltage divider.
 - There is a 1.8V reference voltage VDD_ADC at Port 9 Pin 32.
 - There is a GNDA_ADC that should be grounded on Port9 Pin 34.
NamePin # Pin # Name
32 VDD_ADC
AIN433 34GNDA_ADC
AIN635 36 AIN5 
AIN2 37 38 AIN3 
AIN0 39 40 AIN1 
 The ADC values can be read very easily:

Original BeagleBone, later builds:
    beaglebone:~# cat /sys/devices/platform/omap/tsc/ain1
    1807
Original BeagleBone, older builds: 
    beaglebone:~# cat /sys/devices/platform/tsc/ain1
    1807
(Note that the path "ain1" maps to the pin "AIN0", the path "ain2" maps to the pin "AIN1", etc.)


BeagleBone black:
FIrst enable the ADC ports, then find out where they are and finall read them:

    sh-4.2# echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots
    sh-4.2# find /sys/ -name '*AIN*'
    /sys/devices/ocp.2/helper.14/AIN0
    /sys/devices/ocp.2/helper.14/AIN1
    /sys/devices/ocp.2/helper.14/AIN2
    /sys/devices/ocp.2/helper.14/AIN3
    /sys/devices/ocp.2/helper.14/AIN4
    /sys/devices/ocp.2/helper.14/AIN5
    /sys/devices/ocp.2/helper.14/AIN6
    /sys/devices/ocp.2/helper.14/AIN7
    sh-4.2# cat /sys/devices/ocp.2/helper.14/AIN1                         
    1588







The Analog to Digital Converter (ADC) on the BeagleBone is both a Touch Screen Controller (TSC) and a general purpose ADC. Depending on how many of the lines are reserved for the TSC (4, 5, or 8), the remaining lines can be used for reading analog values. One of the lines is connected to the power Management Integrated Circuit (PMIC, TPS65217) of the white Bone,  in order to sense the power used by the board. This does not appear to be the case for the new BeagleBone Black.
The basics 
To read the analog inputs on your BeagleBone Black, first enable the driver:
echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots
The analog inputs should now be activated and exported to the filesystem. To read their values, just cat the files:
cat /sys/devices/ocp.2/helper.11/AIN1
This will read the analog value of AIN1 (The pin is P9_40). What you see is a voltage between 0 and 1.8V, but in millivolts (0 to 1799). If you tie the pin high by shorting the pin to the analog VDD (P9_32), you will see a 1799. If you tie the pin low to (P9_34, Analog ground), you will see a 0. There is a bug in the driver, so the value you read is actually the previous value you read. For now, just read the value twice. More on that later.
Bug in the ADC driver
Note: This was tested on kernel 3.8.6, the one that came with the early BeagleBone Black.
The driver for the ADC was riddled with errors early on. This manifested itself as getting weird values from the ADC when reading from one or several pins in rapid succession:
adc_failing
Clearly, a negative value is not right. The reason why this occurs is that there is no test to make sure the ADC is finished with sampling the pin. Furthermore, when one pin is read, the reading of this pin triggers the ADC to sample a new value (for all the pins) for the next reading. For further reading, consult the Linux mainline source: ti_am335x_adc.c. This will probably be fixed in later veriosn of the kernel, but if you need a solution now, have a look at these adc-patches and see if you can’t figure it out : )
Troubleshooting
If your analog inputs do not show up at the above spot, make sure the helper module is loaded:
lsmod
This shows a list of loaded kernel modules, make sure “bone_iio_helper” shows up in the list.
If the helper modules is loaded, but the fiels are not in the right place, try searching for them:
find /sys -name *AIN*
This should show you a list of the analog input files. If not, go to forum and rant. Make sure you include the kernel version you are using:
root@beaglebone:~# uname -a
Linux beaglebone 3.8.6 #1 SMP Sat Apr 13 09:10:52 CEST 2013 armv7l GNU/Linux

I2C devices on BBB

Enable the I2C devices on the BeagleBone Black

On the BeagleBone Black, it's not all of the /dev/i2c-* devices that are enabled by default. The other i2c devices must be enabled before they can be used.

To enable the I2c-1 on the BeagleBone Black Rev A, B and C:
  1. Rev A/B: Open the file /media/BEAGLEBONE/uEnv.txt in an editor (vim/nano)
  2. Rec C: Open the file /boot/uboot/uEnv.txt in an editor (vim/nano)
  3. Add the key "capemgr.enable_partno="
  4. Add the ports you want to enable, comma separated (BB-I2C0, BB-I2C1, etc)
  5. Reboot
An example line looks like this:

root@beaglebone:/dev# cat /media/BEAGLEBONE/uEnv.txt
optargs=quiet drm.debug=7 capemgr.enable_partno=BB-I2C1


After reboot, the device is present in the device list:
root@beaglebone:/dev# ls -l /dev/i2c*
crw-rw---- 1 root tty     249, 0 Jan  1 01:18 /dev/ttyO0
crw-rw---- 1 root dialout 249, 4 Jan  1 01:18 /dev/ttyO4

Note: The I2C devices do not map one-to-one with the devices in /dev/. I.e. I2C-1 does not necessarily map to /dev/i2c-1, it could just as well be one of the other devs, e.g. /dev/i2c-2.

Testing the I2C devices


You can use the standard Linux i2c tools to test your i2c setup:

List all the enabled devices:
root@beaglebone:/dev# i2cdetect -l
i2c-0   i2c             OMAP I2C adapter                        I2C adapter
i2c-1   i2c             OMAP I2C adapter                        I2C adapter
Scan all addresses on one device:
root@beaglebone:/dev# i2cdetect -r 0
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0 using read byte commands.
I will probe address range 0x03-0x77.
Continue? [Y/n] Y
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: UU -- -- -- -- -- -- --
Write one byte to a device and an address:

i2cset -y 2 0x77 0xf4 0x34

Read one byte from a device and an address:

i2cdump -y 2 0x77


JavaScript / Node.js

In JavaScript / Node.js you can use the package "i2c" or the latest version of "bonescript" that includes the same package.
 - npm install i2c
 - npm install bonescript

I've had some problems with crashes in the i2c module (segmentation faults).

If you just need to read and write single bytes, you can also do this using normal file system (open /dev/i2c-1 for read+write) and set the device address using the "ioctl" module:
 - npm install ioctl

The code sequence:
1. Open /dev/i2c-1 for read+write
2. Use ioctl to set slave address: ioctl(fileHandle, I2C_SLAVE, address)

(I2C_SLAVE = 0x0703 )
Reference: 
http://beaglebone.cameon.net/home/i2c-devices






Documentation of I2c on 

Usually, i2c devices are controlled by a kernel driver. But it is also
possible to access all devices on an adapter from userspace, through
the /dev interface. You need to load module i2c-dev for this.

Each registered i2c adapter gets a number, counting from 0. You can
examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
Alternatively, you can run "i2cdetect -l" to obtain a formated list of all
i2c adapters present on your system at a given time. i2cdetect is part of
the i2c-tools package.

I2C device files are character device files with major device number 89
and a minor device number corresponding to the number assigned as 
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ..., 
i2c-10, ...). All 256 minor device numbers are reserved for i2c.


C example
=========

So let's say you want to access an i2c adapter from a C program. The
first thing to do is "#include <linux/i2c-dev.h>". Please note that
there are two files named "i2c-dev.h" out there, one is distributed
with the Linux kernel and is meant to be included from kernel
driver code, the other one is distributed with i2c-tools and is
meant to be included from user-space programs. You obviously want
the second one here.

Now, you have to decide which adapter you want to access. You should
inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
Adapter numbers are assigned somewhat dynamically, so you can not
assume much about them. They can even change from one boot to the next.

Next thing, open the device file, as follows:

  int file;
  int adapter_nr = 2; /* probably dynamically determined */
  char filename[20];
  
  snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
  file = open(filename, O_RDWR);
  if (file < 0) {
    /* ERROR HANDLING; you can check errno to see what went wrong */
    exit(1);
  }

When you have opened the device, you must specify with what device
address you want to communicate:

  int addr = 0x40; /* The I2C address */

  if (ioctl(file, I2C_SLAVE, addr) < 0) {
    /* ERROR HANDLING; you can check errno to see what went wrong */
    exit(1);
  }

Well, you are all set up now. You can now use SMBus commands or plain
I2C to communicate with your device. SMBus commands are preferred if
the device supports them. Both are illustrated below.

  __u8 reg = 0x10; /* Device register to access */
  __s32 res;
  char buf[10];

  /* Using SMBus commands */
  res = i2c_smbus_read_word_data(file, reg);
  if (res < 0) {
    /* ERROR HANDLING: i2c transaction failed */
  } else {
    /* res contains the read word */
  }

  /* Using I2C Write, equivalent of 
     i2c_smbus_write_word_data(file, reg, 0x6543) */
  buf[0] = reg;
  buf[1] = 0x43;
  buf[2] = 0x65;
  if (write(file, buf, 3) != 3) {
    /* ERROR HANDLING: i2c transaction failed */
  }

  /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
  if (read(file, buf, 1) != 1) {
    /* ERROR HANDLING: i2c transaction failed */
  } else {
    /* buf[0] contains the read byte */
  }

Note that only a subset of the I2C and SMBus protocols can be achieved by
the means of read() and write() calls. In particular, so-called combined
transactions (mixing read and write messages in the same transaction)
aren't supported. For this reason, this interface is almost never used by
user-space programs.

IMPORTANT: because of the use of inline functions, you *have* to use
'-O' or some variation when you compile your program!


Full interface description
==========================

The following IOCTLs are defined:

ioctl(file, I2C_SLAVE, long addr)
  Change slave address. The address is passed in the 7 lower bits of the
  argument (except for 10 bit addresses, passed in the 10 lower bits in this
  case).

ioctl(file, I2C_TENBIT, long select)
  Selects ten bit addresses if select not equals 0, selects normal 7 bit
  addresses if select equals 0. Default 0.  This request is only valid
  if the adapter has I2C_FUNC_10BIT_ADDR.

ioctl(file, I2C_PEC, long select)
  Selects SMBus PEC (packet error checking) generation and verification
  if select not equals 0, disables if select equals 0. Default 0.
  Used only for SMBus transactions.  This request only has an effect if the
  the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
  doesn't have any effect.

ioctl(file, I2C_FUNCS, unsigned long *funcs)
  Gets the adapter functionality and puts it in *funcs.

ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)
  Do combined read/write transaction without stop in between.
  Only valid if the adapter has I2C_FUNC_I2C.  The argument is
  a pointer to a

  struct i2c_rdwr_ioctl_data {
      struct i2c_msg *msgs;  /* ptr to array of simple messages */
      int nmsgs;             /* number of messages to exchange */
  }

  The msgs[] themselves contain further pointers into data buffers.
  The function will write or read data to or from that buffers depending
  on whether the I2C_M_RD flag is set in a particular message or not.
  The slave address and whether to use ten bit address mode has to be
  set in each message, overriding the values set with the above ioctl's.

ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)
  Not meant to be called  directly; instead, use the access functions
  below.

You can do plain i2c transactions by using read(2) and write(2) calls.
You do not need to pass the address byte; instead, set it through
ioctl I2C_SLAVE before you try to access the device.

You can do SMBus level transactions (see documentation file smbus-protocol 
for details) through the following functions:
  __s32 i2c_smbus_write_quick(int file, __u8 value);
  __s32 i2c_smbus_read_byte(int file);
  __s32 i2c_smbus_write_byte(int file, __u8 value);
  __s32 i2c_smbus_read_byte_data(int file, __u8 command);
  __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value);
  __s32 i2c_smbus_read_word_data(int file, __u8 command);
  __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value);
  __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value);
  __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
  __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, 
                                   __u8 *values);
All these transactions return -1 on failure; you can read errno to see
what happened. The 'write' transactions return 0 on success; the
'read' transactions return the read value, except for read_block, which
returns the number of values read. The block buffers need not be longer
than 32 bytes.

The above functions are all inline functions, that resolve to calls to
the i2c_smbus_access function, that on its turn calls a specific ioctl
with the data in a specific format. Read the source code if you
want to know what happens behind the screens.


Implementation details
======================

For the interested, here's the code flow which happens inside the kernel
when you use the /dev interface to I2C:

1* Your program opens /dev/i2c-N and calls ioctl() on it, as described in
section "C example" above.

2* These open() and ioctl() calls are handled by the i2c-dev kernel
driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(),
respectively. You can think of i2c-dev as a generic I2C chip driver
that can be programmed from user-space.

3* Some ioctl() calls are for administrative tasks and are handled by
i2c-dev directly. Examples include I2C_SLAVE (set the address of the
device you want to access) and I2C_PEC (enable or disable SMBus error
checking on future transactions.)

4* Other ioctl() calls are converted to in-kernel function calls by
i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter
functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which
performs an SMBus transaction using i2c-core.c:i2c_smbus_xfer().

The i2c-dev driver is responsible for checking all the parameters that
come from user-space for validity. After this point, there is no
difference between these calls that came from user-space through i2c-dev
and calls that would have been performed by kernel I2C chip drivers
directly. This means that I2C bus drivers don't need to implement
anything special to support access from user-space.

5* These i2c-core.c/i2c.h functions are wrappers to the actual
implementation of your I2C bus driver. Each adapter must declare
callback functions implementing these standard calls.
i2c.h:i2c_get_functionality() calls i2c_adapter.algo->functionality(),
while i2c-core.c:i2c_smbus_xfer() calls either
adapter.algo->smbus_xfer() if it is implemented, or if not,
i2c-core.c:i2c_smbus_xfer_emulated() which in turn calls
i2c_adapter.algo->master_xfer().

After your I2C bus driver has processed these requests, execution runs
up the call chain, with almost no processing done, except by i2c-dev to
package the returned data, if any, in suitable format for the ioctl.
 
 
 
EEPROM I2C 
 
/*
  2     Copyright (C) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
  3                                Philip Edelbrock <phil@netroedge.com>
  4     Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
  5     Copyright (C) 2003 IBM Corp.
  6     Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
  7 
  8     This program is free software; you can redistribute it and/or modify
  9     it under the terms of the GNU General Public License as published by
 10     the Free Software Foundation; either version 2 of the License, or
 11     (at your option) any later version.
 12 
 13     This program is distributed in the hope that it will be useful,
 14     but WITHOUT ANY WARRANTY; without even the implied warranty of
 15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16     GNU General Public License for more details.
 17 
 18     You should have received a copy of the GNU General Public License
 19     along with this program; if not, write to the Free Software
 20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 21 */
 22 
 23 #include <linux/kernel.h>
 24 #include <linux/init.h>
 25 #include <linux/module.h>
 26 #include <linux/slab.h>
 27 #include <linux/jiffies.h>
 28 #include <linux/i2c.h>
 29 #include <linux/mutex.h>
 30 
 31 /* Addresses to scan */
 32 static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
 33                                         0x55, 0x56, 0x57, I2C_CLIENT_END };
 34 
 35 /* Insmod parameters */
 36 I2C_CLIENT_INSMOD_1(eeprom);
 37 
 38 
 39 /* Size of EEPROM in bytes */
 40 #define EEPROM_SIZE             256
 41 
 42 /* possible types of eeprom devices */
 43 enum eeprom_nature {
 44         UNKNOWN,
 45         VAIO,
 46 };
 47 
 48 /* Each client has this additional data */
 49 struct eeprom_data {
 50         struct mutex update_lock;
 51         u8 valid;                       /* bitfield, bit!=0 if slice is valid */
 52         unsigned long last_updated[8];  /* In jiffies, 8 slices */
 53         u8 data[EEPROM_SIZE];           /* Register values */
 54         enum eeprom_nature nature;
 55 };
 56 
 57 
 58 static void eeprom_update_client(struct i2c_client *client, u8 slice)
 59 {
 60         struct eeprom_data *data = i2c_get_clientdata(client);
 61         int i;
 62 
 63         mutex_lock(&data->update_lock);
 64 
 65         if (!(data->valid & (1 << slice)) ||
 66             time_after(jiffies, data->last_updated[slice] + 300 * HZ)) {
 67                 dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice);
 68 
 69                 if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
 70                         for (i = slice << 5; i < (slice + 1) << 5; i += 32)
 71                                 if (i2c_smbus_read_i2c_block_data(client, i,
 72                                                         32, data->data + i)
 73                                                         != 32)
 74                                         goto exit;
 75                 } else {
 76                         for (i = slice << 5; i < (slice + 1) << 5; i += 2) {
 77                                 int word = i2c_smbus_read_word_data(client, i);
 78                                 if (word < 0)
 79                                         goto exit;
 80                                 data->data[i] = word & 0xff;
 81                                 data->data[i + 1] = word >> 8;
 82                         }
 83                 }
 84                 data->last_updated[slice] = jiffies;
 85                 data->valid |= (1 << slice);
 86         }
 87 exit:
 88         mutex_unlock(&data->update_lock);
 89 }
 90 
 91 static ssize_t eeprom_read(struct kobject *kobj, struct bin_attribute *bin_attr,
 92                            char *buf, loff_t off, size_t count)
 93 {
 94         struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
 95         struct eeprom_data *data = i2c_get_clientdata(client);
 96         u8 slice;
 97 
 98         if (off > EEPROM_SIZE)
 99                 return 0;
100         if (off + count > EEPROM_SIZE)
101                 count = EEPROM_SIZE - off;
102 
103         /* Only refresh slices which contain requested bytes */
104         for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++)
105                 eeprom_update_client(client, slice);
106 
107         /* Hide Vaio private settings to regular users:
108            - BIOS passwords: bytes 0x00 to 0x0f
109            - UUID: bytes 0x10 to 0x1f
110            - Serial number: 0xc0 to 0xdf */
111         if (data->nature == VAIO && !capable(CAP_SYS_ADMIN)) {
112                 int i;
113 
114                 for (i = 0; i < count; i++) {
115                         if ((off + i <= 0x1f) ||
116                             (off + i >= 0xc0 && off + i <= 0xdf))
117                                 buf[i] = 0;
118                         else
119                                 buf[i] = data->data[off + i];
120                 }
121         } else {
122                 memcpy(buf, &data->data[off], count);
123         }
124 
125         return count;
126 }
127 
128 static struct bin_attribute eeprom_attr = {
129         .attr = {
130                 .name = "eeprom",
131                 .mode = S_IRUGO,
132         },
133         .size = EEPROM_SIZE,
134         .read = eeprom_read,
135 };
136 
137 /* Return 0 if detection is successful, -ENODEV otherwise */
138 static int eeprom_detect(struct i2c_client *client, int kind,
139                          struct i2c_board_info *info)
140 {
141         struct i2c_adapter *adapter = client->adapter;
142 
143         /* EDID EEPROMs are often 24C00 EEPROMs, which answer to all
144            addresses 0x50-0x57, but we only care about 0x50. So decline
145            attaching to addresses >= 0x51 on DDC buses */
146         if (!(adapter->class & I2C_CLASS_SPD) && client->addr >= 0x51)
147                 return -ENODEV;
148 
149         /* There are four ways we can read the EEPROM data:
150            (1) I2C block reads (faster, but unsupported by most adapters)
151            (2) Word reads (128% overhead)
152            (3) Consecutive byte reads (88% overhead, unsafe)
153            (4) Regular byte data reads (265% overhead)
154            The third and fourth methods are not implemented by this driver
155            because all known adapters support one of the first two. */
156         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)
157          && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK))
158                 return -ENODEV;
159 
160         strlcpy(info->type, "eeprom", I2C_NAME_SIZE);
161 
162         return 0;
163 }
164 
165 static int eeprom_probe(struct i2c_client *client,
166                         const struct i2c_device_id *id)
167 {
168         struct i2c_adapter *adapter = client->adapter;
169         struct eeprom_data *data;
170         int err;
171 
172         if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
173                 err = -ENOMEM;
174                 goto exit;
175         }
176 
177         memset(data->data, 0xff, EEPROM_SIZE);
178         i2c_set_clientdata(client, data);
179         mutex_init(&data->update_lock);
180         data->nature = UNKNOWN;
181 
182         /* Detect the Vaio nature of EEPROMs.
183            We use the "PCG-" or "VGN-" prefix as the signature. */
184         if (client->addr == 0x57
185          && i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
186                 char name[4];
187 
188                 name[0] = i2c_smbus_read_byte_data(client, 0x80);
189                 name[1] = i2c_smbus_read_byte_data(client, 0x81);
190                 name[2] = i2c_smbus_read_byte_data(client, 0x82);
191                 name[3] = i2c_smbus_read_byte_data(client, 0x83);
192 
193                 if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) {
194                         dev_info(&client->dev, "Vaio EEPROM detected, "
195                                  "enabling privacy protection\n");
196                         data->nature = VAIO;
197                 }
198         }
199 
200         /* create the sysfs eeprom file */
201         err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
202         if (err)
203                 goto exit_kfree;
204 
205         return 0;
206 
207 exit_kfree:
208         kfree(data);
209 exit:
210         return err;
211 }
212 
213 static int eeprom_remove(struct i2c_client *client)
214 {
215         sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
216         kfree(i2c_get_clientdata(client));
217 
218         return 0;
219 }
220 
221 static const struct i2c_device_id eeprom_id[] = {
222         { "eeprom", 0 },
223         { }
224 };
225 
226 static struct i2c_driver eeprom_driver = {
227         .driver = {
228                 .name   = "eeprom",
229         },
230         .probe          = eeprom_probe,
231         .remove         = eeprom_remove,
232         .id_table       = eeprom_id,
233 
234         .class          = I2C_CLASS_DDC | I2C_CLASS_SPD,
235         .detect         = eeprom_detect,
236         .address_data   = &addr_data,
237 };
238 
239 static int __init eeprom_init(void)
240 {
241         return i2c_add_driver(&eeprom_driver);
242 }
243 
244 static void __exit eeprom_exit(void)
245 {
246         i2c_del_driver(&eeprom_driver);
247 }
248 
249 
250 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
251                 "Philip Edelbrock <phil@netroedge.com> and "
252                 "Greg Kroah-Hartman <greg@kroah.com>");
253 MODULE_DESCRIPTION("I2C EEPROM driver");
254 MODULE_LICENSE("GPL");
255 
256 module_init(eeprom_init);
257 module_exit(eeprom_exit);
258