MMA7455L question

01 Feb 2012

hi everybody :) i'm working on a project, where i need to interface the MMA7455L digital acceleromter to the mbed through SPI interface... my problem is that i simply can't calibrate the readings i have, and as a matter of fact, i have pretty strange values ! i need only to operate this accelerometer on the measurement mode, and i managed to declare and define the required registers, but as i said, i have values, probably in counts, and i can't convert them back to "g" 's ! any help???

01 Feb 2012

Hassan,

Have you seen this? http://mbed.org/users/espresso3389/programs/mma7455l_test/60ed4

If you still have problems, post your program so that the mbed comunity can help you.

Dave.

01 Feb 2012

thank you Dave for your reply :) actually, i saw this link before and i had some problems understanding it, so i'll post my code (and it seems simpler for me :D )

this is the header file

#ifndef MMA7455L_PROGRAM
#define MMA7455L_PROGRAM

#include "mbed.h"


class MMA7455L {

public:

    MMA7455L(PinName _sdo, PinName _sdi, PinName _sck, PinName _cs, DigitalOut& myled, DigitalOut& myled2); // constructor
    float get_x();
    float get_y();
    float get_z();
    void update_acceleration();
    int Who_Am_I();
    void calibrate(float maxx = 1, float minx = -1, float maxy = 1, float miny = -1, float maxz = 1, float minz = -1);
    int get_status();
    int A_x, A_y, A_z;

private:

    DigitalOut _CS; // is stands for chip select, or it may be called also slave selet (SS)
    DigitalOut led1;
    DigitalOut led2;
    SPI _spi;
    
    float accelerometer_status;
    int status();
    float _factor;
    float _minx, _maxx;
    float _miny, _maxy;
    float _minz, _maxz;
};
#endif <</code>>


and this is the source file

<<code>>
#include "MMA7455L.h"

// making some primary definitions for primary registers



#define X_OUT                                0x06

#define Y_OUT                                0x07

#define Z_OUT                                0x08

#define STATUS                               0x09

#define X_OFF_LSB                            0x10

#define Y_OFF_LSB                            0x12

#define Z_OFF_LSB                            0x14

#define WHO_AM_I                             0x0F

#define OFFSET_DRIFT_X_LSB                   0x10

#define OFFSET_DRIFT_X_MSB                   0x11

#define OFFSET_DRIFT_Y_LSB                   0x12

#define OFFSET_DRIFT_Y_MSB                   0x13

#define OFFSET_DRIFT_Z_LSB                   0x14

#define OFFSET_DRIFT_Z_MSB                   0x15

#define MODE_CONTROL_REGISTER                0x16 // from this register we can control what range of accelerations
                                                   //can be used and what mode it operates on (whether stand by, on,
                                                   // power down or what ever (see data sheet page 9)

#define INTERRUPT_LATCH_RESET                 0x17 //this register is responsible for making an interrupt if a certain
                                                   //condition was detected, like a zero g or crossing certain thershold
                                                   //(see page 15 in datasheet for more clarification)
                                                                    
#define CONTROL_1                             0x18  // this register is resposible for determining what axes are entabled
                                                    // in measurment
                                    
#define CONTROL_2                             0x19  //for motion detection (OR condition) or free fall detection (AND condition)

#define LEVEL_DETECTION_THRESHOLD_LIMIT_VALUE 0x1A  // here we assign the value of the threholds 
                                                    // see examples in page 11 in data sheet
  
#define PULSE_DETECTION_THRESHOLD_LIMIT_VALUE 0x1B

#define PULSE_DURATION_VALUE                  0x1C

#define LATENCY_TIME_VALUE                    0x1D   
                                                                              
#define DETECTION_SOURCE_REGISTER             0x0A  //mainly used to know whether some event was detected


// some useful auxillary constants

#define MMA7455L_READ                         0x00  //to know why read = 0 and write = 1, refer to page 18, last paragraph
 
#define MMA7455L_WRITE                        0x80

#define DATA_READY                            0x01


MMA7455L :: MMA7455L(PinName _sdo, PinName _sdi, PinName _sck, PinName _cs, DigitalOut& myled, DigitalOut& myled2):_spi(_sdo,_sdi,_sck), _CS(_cs), led1(myled), led2(myled2) // constructor
{
    _CS = 1; // means no interaction between the two devices
    _spi.format(8,0);
    _spi.frequency(8000000);
    
    //configuring the acceleromter registers
    
    //configuring the mode control register and seting it to measure 8g
    led1 = 1;
    _CS = 0;
    _spi.write(MMA7455L_WRITE | (MODE_CONTROL_REGISTER << 1) );
    _spi.write(0x01);                              //here we specify that the range of measurement is [0,0]
                                                   //which is the defalut, we specified the mode on which 
                                                   //the accelerometer operates, which is measurment, no 
                                                   //level or pulse detection for example
    _CS = 1;
    led1 = 0;
    
    //configuring the offset values for X
    _CS = 0;
    _spi.write(MMA7455L_WRITE | X_OFF_LSB);
    _spi.write(0xFF);
    _CS = 1;
    
    //configuring the offset values for y
    _CS = 0;
    _spi.write(MMA7455L_WRITE | Y_OFF_LSB);
    _spi.write(0xFF);
    _CS = 1;
    
    //configuring the offset values for Z
    _CS = 0;
    _spi.write(MMA7455L_WRITE | Z_OFF_LSB);
    _spi.write(0x28);
    _CS = 1;
    // configuring the interrupt latch
    led1 = 1;
    _CS = 0;
    _spi.write(MMA7455L_WRITE | (INTERRUPT_LATCH_RESET << 1) );
    _spi.write(0x03);
    _CS = 1;
    led1 = 0;
       
    //configuraing the control 1 register
    led1 = 1;
    _CS = 0;
    _spi.write(MMA7455L_WRITE | (CONTROL_1 << 1) ); // notice that we made this bitwise operation because
                                                    //the accel. itself specifies that there is a R?WR
                                                    //bit and 6 adress bits and the rest is not important
                                                    //so we need to make it zero anyway in order not to 
                                                    //truncate any part of the adress
    _spi.write(0x00); // which is the default anyway
    _CS = 1;
    led1 = 0;
    
    //configuring the control 2 regoster
    led1 = 1;
    _CS = 0;
    _spi.write(MMA7455L_WRITE | (CONTROL_2 << 1) );
    _spi.write(0x00);  // which is the defalut anyway
    _CS = 1;
    led1 = 0;
    
    //configuring level detection threshold limit value
    led1 = 1;
    _CS = 0;
    _spi.write(MMA7455L_WRITE | (LEVEL_DETECTION_THRESHOLD_LIMIT_VALUE << 1) );
    _spi.write(0x2F);
    _CS = 1;
    led1 = 0;
    
     //configuring pulse detection threshold limit value
     led1 = 1;
    _CS = 0;
    _spi.write(MMA7455L_WRITE | (PULSE_DETECTION_THRESHOLD_LIMIT_VALUE << 1) );
    _spi.write(0x2F);
    _CS = 1;
    led1 = 0;
    
    //configuring pulse duration value
    led1 = 1;
    _CS = 0;
    _spi.write(MMA7455L_WRITE | (PULSE_DURATION_VALUE << 1) );
    _spi.write(0x2F);
    _CS = 1;
    led1 = 0;
    
    
    //configuring latency time value
    led1 = 1;
    _CS = 0;
    _spi.write(MMA7455L_WRITE | (LATENCY_TIME_VALUE << 1) );
    _spi.write(0x2F);
    _CS = 1;
    wait(2);
    led1 = 0;
    
    A_x = A_y = A_z = 20;
    accelerometer_status = 6;
    
    calibrate();
}

void MMA7455L :: calibrate(float maxx, float minx, float maxy, float miny, float maxz, float minz)
{
    _minx = minx;   _maxx = maxx;
    _miny = miny;   _maxy = maxy;
    _minz = minz;   _maxz = maxz;
}

int MMA7455L :: status() // determines whether the data is ready to be read or not
{
    _CS = 0;
    _spi.write(MMA7455L_READ | (STATUS << 1) );
    int value = _spi.write(0x00);                       //note that we put 0x80 in order to write. notice that
                                                        //for writing, we need to have a 1 in the first bit sent
                                                        //or written, and also notice that accelerometer LIS302
                                                        //opposite orders for writing and reading (read = 1, write = 0)
    _CS = 1; 
    return value;                                                   
}

float MMA7455L :: get_x()
{
    return A_x;
} 

float MMA7455L :: get_y()
{
    return A_y;
} 

float MMA7455L :: get_z()
{
    return A_z;
} 

int MMA7455L :: get_status()
{
    _CS = 0;
    _spi.write(MMA7455L_READ | (STATUS << 1) );
    accelerometer_status = _spi.write(0x00);                       //note that we put 0x80 in order to write. notice that
                                                        //for writing, we need to have a 1 in the first bit sent
                                                        //or written, and also notice that accelerometer LIS302
                                                        //opposite orders for writing and reading (read = 1, write = 0)
    _CS = 1; 
    return accelerometer_status;
}

void MMA7455L :: update_acceleration()
{
    led2 = 1;
    wait(0.03);
    if ((get_status() & DATA_READY))
    {
        led2 = 0;
        _CS = 0;
        
        led1 = 1;
        //calculating acceleration in x direction
        _spi.write(MMA7455L_READ | (X_OUT << 1) );
               
        led1 = 0;
         wait(0.05);
        A_x =( _spi.write(0x00))/*((_spi.write(0x00)<<8) * 3.3 / 255) / 0.207*/;
        //float gradient = (2.0/(_maxx-_minx));
        //A_x =  (gradient*(float)(A_x)/16)+((-gradient*_maxx)+1);

        
        led1 = 1;
        //calculating acceleration in y direction
        _spi.write(MMA7455L_READ | (Y_OUT << 1) );
        A_y = _spi.write(0x00);
        wait(0.05);
        led1 = 0;
        
        led1 = 1;
        //calculating acceleration in z direction
        _spi.write(MMA7455L_READ | (Z_OUT << 1) );
        A_z = _spi.write(0x00);  
        
        _CS = 1;
        wait(0.05);
        led1 = 0;
        
        // here we make the calibration for the readings
    }
}

int MMA7455L :: Who_Am_I()
{
    _CS = 0;
    _spi.write(MMA7455L_READ | (WHO_AM_I << 1) );
    int value = _spi.write(0x00);
    _CS = 1;
    return value;
}
<</code>>


and this is the main file

<<code>>
#include "mbed.h"
#include "MMA7455L.h"

DigitalOut myled(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
Serial pc(USBTX, USBRX);
int main() {

    pc.printf("starting...\r\n");
    MMA7455L acc(p5,p6,p7,p14, led2, led3);
    int stat = 5;
    pc.printf("constructor completed\r\n");
    while(1) {
        pc.printf(" status is %d\r\n",acc.get_status() & 0x01 /*Who_Am_I()*/ );
        wait(0.06);
        acc.update_acceleration();
        pc.printf("%d %5d %5d\r\n\n\n", acc.A_x, acc.A_y, acc.A_z); 
        
    }
}

any help???

01 Feb 2012

by the way, there is another strange behaviour i observed and forgot to tell you about ... i tried to assign some value in the offset registers for x, y, and z as a type of testing, and i understood from the data sheet that this value should be subtracted from the readings, but actually i have the same readings as if they were not set ... any explaination??? thank you in advance :)

01 Feb 2012

another note is that if the accelerometer is left in a level position, the readings for x and y is in the order of 250, while the value for z is in the order of 10 ... is it normal?

02 Feb 2012

Hassan,

The values you are getting are wrong if your accelerometer is flat (ie z is pointing up or down). The values you should see are x and y close to 0 and z = approx +-1g. From the data sheet there are 3 possible values dependent on what range you use, 1g will be 64, 32 or 16. To work out the G value you need to divide 9.81 or your local G value by the count/g, ie 9.81/64 = 0.15328125, which you then multiply by the returned value. Also have you setup the Mode Control Register ?

Dave.

02 Feb 2012

thank you Dave very much for you reply and i really apprecite it. i think i managed to fix the problem. i eventually had values of ig in z direction when the accelerometer is flat, while having x and y reading near zero. my misstake was simply declaring the acceleration values in the class body as being int. when i tried to delcare them as "signed char", i had much better and more reasonable results, and the rest was simple, deviding by the sensetivity and subtracting the offset value (measured with accelerometer at rest and in level position). but would you please do me a favour and tell me what is the difference between asigining a byte read through SPI as "int" or "signed char" ? thank you so much in advance :)

02 Feb 2012

Hassan,

Good to hear you have fixed your problem! The difference between an Int and a signed char is an int is 32 bits ands the signed char is 8 bits,(on a 32bit system). To learn more go here http://www.cplusplus.com

edit: or here http://www.cplusplus.com/doc/tutorial/variables/

A clue is the sign bit! And where it is placed.

Dave