I am trying to read acceleration values from a ADXL345 via I2C. I've successfully configured the accelerometer with a resolution of 16G.

Test 1: 180° rotation along the y axis in 16G resolution. The acceleration along the Z axis is shown below:

Using a 16g configuration, the resolution is too low. I changed it to 2g in order to get a more accurate value of gravity and performed the same test.

Test 2: 180° rotation along the y axis in 2G resolution. The acceleration along the Z axis is shown below:

As you can see, the is a roll over effect probably caused by the number of bits used in the register to save the value. With 16g mode the module uses a 13 bit register, with 2/4/8g mode it uses a 10bit register.

Which approach do you suggest to reconstruct the acceleration value?

In this question @davidcary mentioned the roll over effect.

EDIT

I am reading two bytes, it is the same code I used for the 16g mode

def read_word(self,adr):
val = (high << 8) + low
return val

if (val >= 0x8000):
return -((65535 - val) + 1)
else:
return val
[...]



Here is a screenshot of the registers containing the Zaxis values

Note

Here is another problem, I will open another question for this but it is worth pointing out the following problem. Please focus on the Z axis only

Test: tilt from 0° to 180° and back to 0° twice, then from 0° to -180° and back to 0° twice.

Figure 1: Raw data

As you can see, the shift is not costant. The average shift is around 58.000 but sometimes it is smaller than this. If we apply the same correction to all shify occurence we will end up with this:

Figure 2: Unwrapped data

If the threshold after which the correction should be applied is not correctly defined, the resulting data won't be accurate. In Figure 2 the acceleration along the Z axis after the test is different from the initial zero value which means disaster...

• How many bits are you reading? Looks like you are ignoring the top bits. – uint128_t Mar 24 '16 at 15:56
• I am reading two bytes. Please see my edit – UserK Mar 24 '16 at 15:58
• DO you have static data from this device? electronics.stackexchange.com/q/327336/54870 – Brethlosze Sep 4 '17 at 5:40
• – UserK Sep 7 '17 at 14:43

The reconstruction you are looking for is called unwrapping. I have implemented this in C++ with good results last year when measuring the total revolution of a car wheel. In matlab: link

Q = unwrap(P,tol)


The "roll over" observed (actually, a wrapping) is not caused by register overflow, but by the signal change of measured gravity acceleration. The tolerance tol should be half the peak-to-peak amplitude observed.

In C, it would be something like this (haven't tested this, but the idea is here):

void unwrap(int *P, int tol, int len)
{
for (int index = 1; index < len; index++)
{
// Upwards wrapping
while (P[index-1] - P[index] > tol)
{
P[index] += 2*tol;
}
// Downwards wrapping
while (P[index] - P[index-1] > tol)
{
P[index] -= 2*tol;
}
}
}

• Thank you Vicente! Exhaustive answer! I correct the title – UserK Mar 24 '16 at 16:54
• How do you handle noise in conjunction with unwrapping? – UserK Mar 24 '16 at 17:37
• Maybe a median filter with a 3 samples window will do the job – UserK Mar 24 '16 at 17:42
• @UserK In my application I had designed and implemented a FIR that filtered data input before unwrapping. It was pretty efficient in C++ using deque containers. You could determine window length and coefficients to your needs using matlab toolboxes. The maths behind FIR implementation is as simple as a dot product, the design is the tricky bit. – Vicente Cunha Mar 24 '16 at 17:49