MMA8562 giving strange acceleration values

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MMA8562 giving strange acceleration values

Jump to solution
1,743 Views
mortenpiil
Contributor I

Hi I've just started using the MMA8562 sensor in a project where I want to calculate my position as time goes by.

I want to do this by using a gyro (FXAS21002C) and the accelerometer.

I would like to get the 3 axis acc values with 12.5Hz sample rate and after correcting with the gyro values double integrate to find my position in x and y as time goes by.

So far the setup is stationary on my desk.

If the PCB is flat I get good results: x and y is near zero and I see the gravity in the z channel (value of around 16600) , and samples come in with 12.5Hz

But if I lift the PCB edge a few (5-10) degrees the z component disapears - so I get all three values near zero - gravity disapeared???

The MMA8562 can then measure with or without the gravity acceleration and it can change from second to second??

If I put the PCB on the side I can get the gravity in the X direction - but again the value can then disappear without warning.

These are the commands I use to intialize the MMA8562:

    IIC_WriteReg(0x1d, 0x2b, 0x40); //Reset accelerometer

    __delay_ms(10);

    IIC_WriteReg(0x1d, 0x2b, 0x00); //remove reset - maybe not nessesary

    __delay_ms(1);

    IIC_WriteReg(0x1d, 0x0e, 0x00); //select 2g range

    __delay_ms(1);

    IIC_WriteReg(0x1d, 0x2b, 0x12); //High resolution

    __delay_ms(1);

    IIC_WriteReg(0x1d, 0x2c, 0x02); //Interrupt active high

    __delay_ms(1);

    IIC_WriteReg(0x1d, 0x2d, 0x01); //Interrupt on Data Ready

    __delay_ms(1);

    IIC_WriteReg(0x1d, 0x2e, 0x01); //Data ready comes out on Int1 pin

    __delay_ms(1);

    IIC_WriteReg(0x1d, 0x2a, 0x29); //Sample at 12.5Hz and activate

Is there some more registers I need to program to just get the raw accelerations?

Here is an example where I have rotated the PCB up to vertical - I write out every 25 samples and move the board very slowly

ACC  X:   -80  Y:   -32  Z: 16672 first the board i laying flat on the desk

ACC  X:   -80  Y:   -32  Z: 16672 

ACC  X:   -96  Y:   -16  Z: 16672

ACC  X:   -80  Y:   -48  Z: 16672

ACC  X:   -80  Y:   -32  Z: 16672

ACC  X:   -96  Y:   -32  Z: 16688

ACC  X:   -80  Y:   -32  Z: 16688  Now I start lifting the PCB

ACC  X:  1552  Y:   -32  Z:   -32   Some of the gravity is now in the X channel, but where is the Z component?

ACC  X:  -112  Y:   -64  Z:   -48    Now all is gone

ACC  X:  6176  Y:   -48  Z: 15376  This is what I would expect 

ACC  X:  6192  Y:   -32  Z:   -32    There goes the Z component again

ACC  X:  9760  Y:   304  Z:   -16   --

ACC  X:  -112  Y:  -112  Z:  -128   all gone!

ACC  X:   -64  Y:    16  Z:   -64   

ACC  X:   -96  Y:   -64  Z:  -112   

ACC  X: 15648  Y:   -32  Z:  3856    Here We are at almost vartical - all good

ACC  X:  -128  Y:   -64  Z:   -48    all gone

ACC  X:   -96  Y:   -64  Z:  3344    Now we got Z back but where is X?

ACC  X:   -16  Y:   -96  Z:  2928  

ACC  X: 15872  Y:   -96  Z:   -80   Here's X but no Z

Any help would be greatly appreciated.

Morten

Labels (2)
0 Kudos
1 Solution
931 Views
TomasVaverka
NXP TechSupport
NXP TechSupport

Hi Morten,

Sorry for the delay in getting back yo you.

Looking at your snapshots, it seems that your burst read is correct and the X,Y and Z data are read at the right time (STATUS reg = 0x0F). However, since the problem is random, we need to record more samples. It would also be useful to monitor the interrupt pins.

It may be the sprintf() function causing a timing problem. I am afraid we really need to see what is going on the I2C bus and interrupt pins and compare that with your debug output.

Regards,

Tomas

View solution in original post

0 Kudos
9 Replies
931 Views
TomasVaverka
NXP TechSupport
NXP TechSupport

Hi Morten,

It seems that you are not converting properly the raw data from accelerometer registers 0x01 – 0x06 to signed 12-bit values. You should use something like this:

// Signed 12-bit accelerometer data

Xout_12_bit = ((short) (OUT_X_MSB<<8 | OUT_X_LSB)) >> 4;            // Compute 12-bit X-axis acceleration output value

Yout_12_bit = ((short) (OUT_Y_MSB<<8 | OUT_Y_LSB)) >> 4;            // Compute 12-bit Y-axis acceleration output value

Zout_12_bit = ((short) (OUT_Z_MSB<<8 | OUT_Z_LSB)) >> 4;            // Compute 12-bit Z-axis acceleration output value

Is this what you are doing, or something very close anyway?

You might also find useful my complete example code for the MMA8652FC.

Let me know whether or not this helps, or if you have any other questions.

Regards,

Tomas

PS: If my answer helps to solve your question, please mark it as "Correct". Thank you.

0 Kudos
931 Views
mortenpiil
Contributor I

Hi Tomas,

I have now made sure my ReadRegs routine works by reading the  control registers 1-5 in all 9 million times and checking that I get back what I programmed - not one false value received.

So it must be the mma8652 that is giving strange xyz values dependent on the angle that gravity enters the chip.

I have also brought up my second development board and that behaves the same way as I described 6 hours ago.

Any help would be greatly apreciated.

Morten

0 Kudos
931 Views
TomasVaverka
NXP TechSupport
NXP TechSupport

Hi Morten,

First of all, the way I am converting the raw data from registers 0x01 – 0x06 to 12-bit signed values is correct. In addition to your procedure, I am shifting the complete 16-bit signed value (OUT_X_MSB<<8 | OUT_X_LSB) 4 bits to right to get the 12-bit signed values, not only the LSB register as you stated.

However, your problem does not seem to be related to the data conversion as it happens randomly and even with the device sitting stationary on your desk. It sounds to me more like a timing issue or something like that. Do you have a logic analyzer to check the timing and data on the bus? What board and MCU are you actually using?

Regards,

Tomas

0 Kudos
931 Views
mortenpiil
Contributor I

Hi Tomas,

Have you had a chance to look at the timing shots I posted on october second?

Hoping for a solution

Morten

0 Kudos
932 Views
TomasVaverka
NXP TechSupport
NXP TechSupport

Hi Morten,

Sorry for the delay in getting back yo you.

Looking at your snapshots, it seems that your burst read is correct and the X,Y and Z data are read at the right time (STATUS reg = 0x0F). However, since the problem is random, we need to record more samples. It would also be useful to monitor the interrupt pins.

It may be the sprintf() function causing a timing problem. I am afraid we really need to see what is going on the I2C bus and interrupt pins and compare that with your debug output.

Regards,

Tomas

0 Kudos
931 Views
mortenpiil
Contributor I

Hi Tomas,

I found out what was wrong - it was my code - I used a buffer to receive my data declared as:

char buf[7];

When I started to make traces for you with good and bad samples I changed my code to only run single reads on demand and output extra debug information.

When looking at that it was obvious what was wrong:

ACC  X:    -7  Y:    20  Z:  1040

S:ffff X:00 ff90 Y:01 40 Z:41 00

In the last line I dump all 7 bytes received, the status byte and 3 times 2 byte acceleration bytes.

See the status byte is written as ffff and the least significant X acceleration byte is ff90 - so the C compiler sign extended the bytes for me before I added in the least significant byte!

So after changing to this buffer:

unsigned char buf[7];

Everything works perfectly.

Thanks Morten

0 Kudos
931 Views
mortenpiil
Contributor I

Hi Tomas,

You are quite right, of cause - I missed your parenteses before the shift right operation.

I have a 2 channel storage scope and will try to capture - but I'm afraid I just broke one of the pull-up resistors off trying to get it.

Right now my system does not work at all.

Anyway it is our own surface mount PCB.

It uses the Microchip MCU dsPIC33 running at 70MHz and the I2C bus is about 4 cm's long and the pull-ups are 4,7 kohm

I'm running the bus at 400 kHz using the build-in I2C circuit.

On the bus are the MCU, an MMA8652 accelerometer, an FXAS21002C gyro and the MAG3110 compass

Okay, I switched to my backup board, here's the trace of reading 7 registers starting at adr 0 from the MMA8652

https://dl.dropboxusercontent.com/u/2651504/whole.png

And here's zoom'ed a bit more

https://dl.dropboxusercontent.com/u/2651504/zoom.png

If I need to zoom somewhere else let me know.

Best regards Morten

0 Kudos
931 Views
mortenpiil
Contributor I

Hi Tomas,

I have now tried to work with all my I2C devices, and I get strange values from all of them.

I have tried to lower my bitrate on the bus - I'm now running 250kHz

Here is a trace of the whole of a 7 byte read from adr 0 and up

Read7bytes.png

Here I've zoomed in on the first part of the transfer

zoom.png

And here's further zoomed on the last bit of the zoom above

zoom2.png

Here's how I've set up the different devices:

#define aAcce 0x1d

#define aGyro 0x20

#define aComp 0x0e

//registers in the MM8652 acceleromter

#define aDaCfg 0x0e

#define aCtrl1 0x2a

#define aCtrl2 0x2b

#define aCtrl3 0x2c

#define aCtrl4 0x2d

#define aCtrl5 0x2e

//registers in the FXA21002C Gyro

#define gCtrl0 0x0d

#define gCtrl1 0x13

#define gCtrl2 0x14

//registers in the MAG3110 Magnetometer

#define cCtrl1 0x10

#define cCtrl2 0x11

    //disable I2C devices

    IIC_WriteReg(aComp, cCtrl1, 0x00); //stop magnetometer

    IIC_WriteReg(aAcce, aCtrl1, 0x00); //stop accelerometer

    IIC_WriteReg(aGyro, gCtrl1, 0x00); //stop gyro

    //reset i2Cdevices

    IIC_WriteReg(aComp, cCtrl2, 0x10); //reset magnetometer

    IIC_WriteReg(aAcce, aCtrl2, 0x40); //Reset accelerometer

    IIC_WriteReg(aGyro, gCtrl1, 0x40); //Reset gyro

    __delay_ms(10);

    //Setup MMA8652 Accelerometer

    IIC_WriteReg(aAcce, aDaCfg, 0x00); //select 2g range

    IIC_WriteReg(aAcce, aCtrl2, 0x02); //High resolution

    IIC_WriteReg(aAcce, aCtrl3, 0x02); //Interrupt active high

    IIC_WriteReg(aAcce, aCtrl4, 0x01); //Interrupt on Data Ready

    IIC_WriteReg(aAcce, aCtrl5, 0x01); //Data ready comes out on Int1 pin

    IIC_WriteReg(aAcce, aCtrl1, 0x29); //Sample at 12.5Hz and activate

   

    //Setup Gyro FXAS21002C

    IIC_WriteReg(aGyro, gCtrl0, 0x03); //250 degrees per second

    IIC_WriteReg(aGyro, gCtrl2, 0x0e); //Interrupt at data ready on pin 1 active high

    IIC_WriteReg(aGyro, gCtrl1, 0x1f); //Sample at 12.Hz and activate

   

    //setup MAG3110 Magnetometer

    IIC_WriteReg(aComp, cCtrl2, 0x80); //run continous

    IIC_WriteReg(aComp, cCtrl1, 0x19); //Sample at 10Hz and activate

This is my code to get the acceleration values, I now use you code Tomas so I place the values in the low 12 bits of a signed integer

I then check that the sum of the absolute acceration values are at least 900 - othervise the MM8652 has dropped measuring gravity

- and check that I can read the control registers correctly.

   int X,Y,Z;

    int AccTid=0, GyroTid=0, MagTid=0;

    unsigned long g=0, z=0, i2cgood=0, i2cbad=0;

  while(1) {

        if (AccDataRdy) {

            char buf[7];

            IIC_ReadRegs(aAcce, 0, 7, buf);

            X = (buf[1]<<8 | buf[2])>>4;

            Y = (buf[3]<<8 | buf[4])>>4;

            Z = (buf[5]<<8 | buf[6])>>4;

            int tot;

            tot = abs(X) + abs(Y)+ abs(Z);

            if (tot < 900) z++; else g++;

            if (CheckRegs) {

                //Now check read all written I2C registers

                IIC_ReadRegs(aAcce, aCtrl1, 7, buf); //First MMA8652 accelerometer

                if (buf[0] == 0x29) i2cgood++; else i2cbad++; //Check CTRL_REG1

                if (buf[1] == 0x02) i2cgood++; else i2cbad++; //Check CTRL_REG2

                if (buf[2] == 0x02) i2cgood++; else i2cbad++; //Check CTRL_REG3

                if (buf[3] == 0x01) i2cgood++; else i2cbad++; //Check CTRL_REG4

                if (buf[4] == 0x01) i2cgood++; else i2cbad++; //Check CTRL_REG5

                if (IIC_ReadReg(aAcce, aDaCfg) == 0x00) i2cgood++; else i2cbad++; //Check XYZ_DATA_CFG

                IIC_ReadRegs(aGyro, gCtrl1, 2, buf); //Next Gyro FXAS21002C

                if (buf[0] == 0x1f) i2cgood++; else i2cbad++; //Check CTRL_REG1

                if (buf[1] == 0x0e) i2cgood++; else i2cbad++; //Check CTRL_REG2

                if (IIC_ReadReg(aGyro, gCtrl0) == 0x03) i2cgood++; else i2cbad++; //Check CTRL_REG0

                IIC_ReadRegs(aComp, cCtrl1, 2, buf); //Last MAG3110 Magnetometer

                if (buf[0] == 0x19) i2cgood++; else i2cbad++; //Check CTRL_REG1

                //CTRL_REG2 can't be read back - always reads as 0

    //            if (buf[1] == 0x80) i2cgood++; else i2cbad++; //Check CTRL_REG2

            }

            AccTid++;

            if (AccTid >= 25) {

                AccTid=0;

                while (!DebugDone);

                sprintf(DebugInfo,"ACC  X:%6d  Y:%6d  Z:%6d    -g: %lu  +g: %lu  -r: %lu  +r: %lu\r\n",  X, Y, Z, z,g, i2cbad, i2cgood);

//                z=g=0;

                SendDebugInfo(DebugInfo);

            }

        }

Here's an example of my debug output:

ACC  X:    -2  Y:    -1  Z:  1043    -g: 5364  +g: 51286  -r: 0  +r: 566500

ACC  X:    -2  Y:    -5  Z:    -1    -g: 5368  +g: 51307  -r: 0  +r: 566750

ACC  X:    -2  Y:    -2  Z:  1042    -g: 5370  +g: 51330  -r: 0  +r: 567000

ACC  X:    -1  Y:    -2  Z:  1042    -g: 5370  +g: 51355  -r: 0  +r: 567250

ACC  X:    -2  Y:    -3  Z:  1042    -g: 5374  +g: 51376  -r: 0  +r: 567500

ACC  X:    -2  Y:    -3  Z:  1042    -g: 5376  +g: 51399  -r: 0  +r: 567750

ACC  X:    -3  Y:    -2  Z:  1043    -g: 5376  +g: 51424  -r: 0  +r: 568000

ACC  X:    -3  Y:    -3  Z:    -1    -g: 5378  +g: 51447  -r: 0  +r: 568250

ACC  X:    16  Y:    -2  Z:  1041    -g: 5381  +g: 51469  -r: 0  +r: 568500

ACC  X:    -4  Y:    -2  Z:  1041    -g: 5386  +g: 51489  -r: 0  +r: 568750

ACC  X:    -3  Y:    -4  Z:  1040    -g: 5387  +g: 51513  -r: 0  +r: 569000

As you can fom this test - horizontal gavity is dropped around 10% of the samples

-g (without gravity) is 5387 samples and good samples is 51513

Half a million control registers have been read and all the reads returned the expected values.

If I tilt the board about 10 degrees about 40% of the samples has no gravity

ACC  X:   176  Y:    -3  Z:  1025    -g: 19377  +g: 30511  -r: 0  +r: 498880

ACC  X:   176  Y:    -3  Z:  1026    -g: 19381  +g: 30532  -r: 0  +r: 499130

ACC  X:    -3  Y:    -7  Z:    -2    -g: 19387  +g: 30551  -r: 0  +r: 499380

ACC  X:   177  Y:    -4  Z:  1024    -g: 19397  +g: 30566  -r: 0  +r: 499630

ACC  X:   177  Y:    -3  Z:  1024    -g: 19407  +g: 30581  -r: 0  +r: 499880

I hope this is enough information for you to pinpoint what I'm doing wrong.

I have attached the log files - one line for every 25 samples.

The gyro seems to drift a lot - I've made code that averages the first 16 samples of each channel and I then subtract that from the raw samples - but a simple integation (summation) of the samples still drift - If I then redo my offset it starts to drift in other directions

We are talking about 100,000 LSB in around 10 minutes at 12.5 Hz samplerate

The compass is pointing south (I believe) and returns

X jumping between either 0 or 2000

Y relatively stable at 800-1000

Z around zero

But I can read the control registers from both devices - very strange

Morten

0 Kudos
931 Views
mortenpiil
Contributor I

Hi Thomas,

Thanks for your quick reply. We seem to setup the same registers ( I believe I had found your very nice link before :smileyhappy:)

I did not show how I convert the samples. Here how I do it:

            int X,Y,Z;     //16 bits signed ints

            char buf[7];

            IIC_ReadRegs(0x1d, 0, 7, buf);  //reads 7 auto incrementing bytes starting from address 0

                                                                //buf[0] contains the status byte, typically 0x07 for new xyz data

            X = buf[1]<<8 | buf[2];

            Y = buf[3]<<8 | buf[4];

            Z = buf[5]<<8 | buf[6];

I do believe your code is actually wrong because you shift the LSB down 4 places.

The Spec pdf says the data is placed in the upper 4 bits of OUT_X_LSB and the lower 4 bits are zero

So my code places the 12 bits in the top part of the 16 bits integer, where your code places it like this:

hhhhhhhh0000llll

You can also see below that my samples comes out as multiples of 16 because the low 4 bits are zero.

But that aside my problem is that laying flat on the table sometimes the data I get back is wrong.

Here is some output where I have adjusted the PCB to get minimum x and y values, I've now added to the end of the line how many of the samples where abs(x)+abs(y)+abs(z) is below 15500 i.e. where gravity has disappeared and the last number is the number of samples with gravity (remember I only dump a line for every 25th sample)

ACC  X:   -32  Y:    16  Z: 16640    0 25

ACC  X:   -48  Y:    16  Z: 16640    3 22

ACC  X:   -16  Y:    16  Z: 16656    1 24

ACC  X:   -32  Y:    16  Z:     -16    1 24

ACC  X:   -16  Y:    16  Z: 16640    0 25

ACC  X:   -32  Y:    16  Z: 16640    2 23

ACC  X:   -32  Y:      0  Z: 16640    2 23

ACC  X:   -32  Y:    16  Z: 16640    0 25

ACC  X:   -32  Y:    32  Z: 16640    0 25

So you see that I had 9 out of 225 samples where the result is wrong, the chip does not detect the gravity (line 4)

Now if i tilt the PCB a little bit - so X begins to point down I get these very nice results

ACC  X:  2576  Y:   -80  Z: 16416    0 25

ACC  X:  2592  Y:   -80  Z: 16416    0 25

ACC  X:  2592  Y:   -80  Z: 16416    0 25

ACC  X:  2592  Y:   -96  Z: 16432    0 25

ACC  X:  2592  Y:   -96  Z: 16416    0 25

ACC  X:  2592  Y:   -80  Z: 16416    0 25

ACC  X:  2592  Y:   -96  Z: 16416    0 25

ACC  X:  2592  Y:   -80  Z: 16416    0 25

See how I have ~0.16g in the X direction and the Z has deminished a bit.

Now I tilt it just a little bit more, and see what happens:

ACC  X:  -128  Y:   -96  Z:   -32    25 0

ACC  X:  -128  Y:   -96  Z:   -32    25 0

ACC  X:  2928  Y:   -96  Z:   -32    25 0

ACC  X:  -128  Y:   -80  Z:   -32    25 0

ACC  X:  -128  Y:   -96  Z:   -32    25 0

ACC  X:  2928  Y:   -80  Z:   -32    25 0

ACC  X:  2928  Y:   -96  Z:   -32    25 0

ACC  X:  -128  Y:   -80  Z:   -32    25 0

ACC  X:  -128  Y:   -80  Z:   -32    25 0

ACC  X:  -128  Y:   -96  Z:   -32    25 0

ACC  X:  -128  Y:   -96  Z:   -32    25 0

Sometimes I get the 0.175g in the X direction - but ALL the Z direction is gone!!

Do I have a bad chip? Or is there some other register that I need to disable - I thinking that the chip has some Portrait/Landscape things - but they should be disabled after reset as I read the Spec.

0 Kudos