Library for driving the MMA8452 accelerometer over I2C

Dependents:   MMA8452_Test MMA8452_Demo Dualing_Tanks IMU-Controlled_MP3_Player ... more

Here is a simple example:

#include "mbed.h"
#include "MMA8452.h"

int main() {
   Serial pc(USBTX,USBRX);
   pc.baud(115200);
   double x = 0, y = 0, z = 0;

   MMA8452 acc(p28, p27, 40000);
   acc.setBitDepth(MMA8452::BIT_DEPTH_12);
   acc.setDynamicRange(MMA8452::DYNAMIC_RANGE_4G);
   acc.setDataRate(MMA8452::RATE_100);
   
   while(1) {
      if(!acc.isXYZReady()) {
         wait(0.01);
         continue;
      }
      acc.readXYZGravity(&x,&y,&z);
      pc.printf("Gravities: %lf %lf %lf\r\n",x,y,z);
   }
}

An easy way to test that this actually works is to run the loop above and hold the MMA8452 parallel to the ground along the respective axis (and upsidedown in each axis). You will see 1G on the respective axis and 0G on the others.

MMA8452.h

Committer:
ashleymills
Date:
2014-03-06
Revision:
19:4d6cd7140a71
Parent:
18:27d839e6dc0e
Child:
20:d55e9d7eb17e

File content as of revision 19:4d6cd7140a71:

#pragma once

// Authors: Ashley Mills, Nicholas Herriot
/* Copyright (c) 2013 Vodafone, MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 * and associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

// the SparkFun breakout board defaults to 1, set to 0 if SA0 jumper on the bottom of the board is set
// see the Table 10. I2C Device Address Sequence in Freescale MMA8452Q pdf
 
#include "mbed.h" 

#define MMA8452_DEBUG 1

// More info on MCU Master address can be found on section 5.10.1 of http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MMA8452Q
#define SA0 1
#if SA0
  #define MMA8452_ADDRESS 0x3A // 0x1D<<1  // SA0 is high, 0x1C if low - 
#else
  #define MMA8452_ADDRESS 0x38 // 0x1C<<1
#endif

// Register descriptions found in section 6 of pdf
#define MMA8452_STATUS 0x00                 // Type 'read' : Status of the data registers
#define MMA8452_OUT_X_MSB 0x01              // Type 'read' : x axis - MSB of 2 byte sample
#define MMA8452_OUT_X_LSB 0x02              // Type 'read' : x axis - LSB of 2 byte sample
#define MMA8452_OUT_Y_MSB 0x03              // Type 'read' : y axis - MSB of 2 byte sample
#define MMA8452_OUT_Y_LSB 0x04              // Type 'read' : y axis - LSB of 2 byte sample
#define MMA8452_OUT_Z_MSB 0x05              // Type 'read' : z axis - MSB of 2 byte sample
#define MMA8452_OUT_Z_LSB 0x06              // Type 'read' : z axis - LSB of 2 byte sample

// register definitions
#define MMA8452_XYZ_DATA_CFG 0x0E

#define MMA8452_SYSMOD 0x0B                         // Type 'read' : This tells you if device is active, sleep or standy 0x00=STANDBY 0x01=WAKE 0x02=SLEEP
#define MMA8452_WHO_AM_I 0x0D                       // Type 'read' : This should return the device id of 0x2A

#define MMA8452_PL_STATUS 0x10                      // Type 'read' : This shows portrait landscape mode orientation
#define MMA8452_PL_CFG 0x11                         // Type 'read/write' : This allows portrait landscape configuration
#define MMA8452_PL_COUNT 0x12                       // Type 'read' : This is the portraint landscape debounce counter
#define MMA8452_PL_BF_ZCOMP 0x13                    // Type 'read' :
#define MMA8452_PL_THS_REG 0x14                     // Type 'read' :

#define MMA8452_FF_MT_CFG 0X15                      // Type 'read/write' : Freefaul motion functional block configuration
#define MMA8452_FF_MT_SRC 0X16                      // Type 'read' : Freefaul motion event source register
#define MMA8452_FF_MT_THS 0X17                      // Type 'read' : Freefaul motion threshold register
#define MMA8452_FF_COUNT 0X18                       // Type 'read' : Freefaul motion debouce counter

#define MMA8452_ASLP_COUNT 0x29                     // Type 'read/write' : Counter settings for auto sleep
#define MMA8452_CTRL_REG_1 0x2A                     // Type 'read/write' :
#define MMA8452_CTRL_REG_2 0x2B                     // Type 'read/write' :
#define MMA8452_CTRL_REG_3 0x2C                     // Type 'read/write' :
#define MMA8452_CTRL_REG_4 0x2D                     // Type 'read/write' :
#define MMA8452_CTRL_REG_5 0x2E                     // Type 'read/write' :

// Defined in table 13 of the Freescale PDF
/// xxx these all need to have better names
#define STANDBY 0x00                        // State value returned after a SYSMOD request, it can be in state STANDBY, WAKE or SLEEP
#define WAKE 0x01                           // State value returned after a SYSMOD request, it can be in state STANDBY, WAKE or SLEEP
#define SLEEP 0x02                          // State value returned after a SYSMOD request, it can be in state STANDBY, WAKE or SLEEP
#define ACTIVE 0x01                         // Stage value returned and set in Control Register 1, it can be STANDBY=00, or ACTIVE=01
 
#define TILT_STATUS 0x03        // Tilt Status (Read only)
#define SRST_STATUS 0x04        // Sample Rate Status Register (Read only)
#define SPCNT_STATUS 0x05       // Sleep Count Register (Read/Write)
#define INTSU_STATUS 0x06       // Interrupt Setup Register
#define MODE_STATUS 0x07        // Mode Register (Read/Write)
#define SR_STATUS 0x08          // Auto-Wake and Active Mode Portrait/Landscape Samples per Seconds Register (Read/Write)
#define PDET_STATUS 0x09        // Tap/Pulse Detection Register (Read/Write)
#define PD_STATUS 0xA           // Tap/Pulse Debounce Count Register (Read/Write)
 
// masks for enabling/disabling standby
#define MMA8452_ACTIVE_MASK 0x01
#define MMA8452_STANDBY_MASK 0xFE

// mask for dynamic range reading and writing
#define MMA8452_DYNAMIC_RANGE_MASK 0xFC

// mask and shift for data rate reading and writing
#define MMA8452_DATA_RATE_MASK 0xC7
#define MMA8452_DATA_RATE_MASK_SHIFT 0x03

// mask and shift for general reading and writing
#define MMA8452_WRITE_MASK 0xFE
#define MMA8452_READ_MASK 0x01

// mask and shift for bit depth reading and writing
#define MMA8452_BIT_DEPTH_MASK 0xFD
#define MMA8452_BIT_DEPTH_MASK_SHIFT 0x01

// status masks and shifts
#define MMA8452_STATUS_ZYXDR_MASK 0x08
#define MMA8452_STATUS_ZDR_MASK 0x04
#define MMA8452_STATUS_YDR_MASK 0x02
#define MMA8452_STATUS_XDR_MASK 0x01
 
class MMA8452         
{        
    public:
    
       enum DynamicRange {
           DYNAMIC_RANGE_2G=0x00,
           DYNAMIC_RANGE_4G,
           DYNAMIC_RANGE_8G,
           DYNAMIC_RANGE_UNKNOWN
       };
        
       enum BitDepth {
           BIT_DEPTH_12=0x00,
           BIT_DEPTH_8, // 1 sets fast read mode, hence the inversion
           BIT_DEPTH_UNKNOWN
       };
       
       enum DataRateHz {
          RATE_800=0x00,
          RATE_400,
          RATE_200,
          RATE_100,
          RATE_50,
          RATE_12_5,
          RATE_6_25,
          RATE_1_563,
          RATE_UNKNOWN
       };
       
        
       /**
        * Create an accelerometer object connected to the specified I2C pins.
        *
        * @param sda I2C data port
        * @param scl I2C clock port
        * @param frequency 
        * 
        */ 
      MMA8452(PinName sda, PinName scl, int frequency);
       
      /// Destructor
      ~MMA8452();
      
      /**
       * Puts the MMA8452 in active mode.
       * @return 0 on success, 1 on failure.
       */
      int activate();
 
      /**
       * Puts the MMA8452 in standby.
       * @return 0 on success, 1 on failure.
       */
      int standby();      
      
       /** Initialization of device MMA8452 (required)
        */
      void init();
    
       /**
        * Read the device ID from the accelerometer (should be 0x2a)
        *
        * @param pointer to store the ID
        * @return 0 on success, 1 on failure.
        */        
      int getDeviceID(char* dst);  
      
      int getStatus(char* dst);  
      
      /** 
       * Read the x,y, and z registers of the MMA8452.
       *
       * @param dst The destination buffer. Note that this needs to be 3 bytes for
       * BIT_DEPTH_8 and 6 bytes for BIT_DEPTH_12. It is upto the caller to ensure this.
       * @return 0 for success, and 1 for failure
       */ 
      int readXYZRaw(char *dst);
      
      int readXRaw(char *dst);
      int readYRaw(char *dst);
      int readZRaw(char *dst);
      
      /**
       * Read the x, y, and z counts of the MMA7452 axes.
       * 
       * Count resolution is either 8 bits or 12 bits, and the range is either +-2G, +-4G, or +-8G
       * depending on settings.
       * 
       * This function queries the MMA8452 and returns the signed counts for each axes.
       *
       * @param x Pointer to integer to store x count
       * @param y Pointer to integer to store y count
       * @param z Pointer to integer to store z count
       * @return 0 on success, 1 on failure
       */
      int readXYZCounts(int *x, int *y, int *z);
      int readXCount(int *x);
      int readYCount(int *y);
      int readZCount(int *z);
      
      int readXYZGravity(double *x, double *y, double *z);
      
      
      /// Returns 1 if data has been internally sampled (is available) for the x-axis since last read, 0 otherwise.
      int isXReady();
      
      /// Returns 1 if data has been internally sampled (is available) for the y-axis since last read, 0 otherwise.
      int isYReady();
      
      /// Returns 1 if data has been internally sampled (is available) for the z-axis since last read, 0 otherwise.
      int isZReady();
      
      /// Returns 1 if data has been internally sampled (is available) for all axes since last read, 0 otherwise.
      int isXYZReady();
            
      /** 
       * Read from specified MMA8452 register.
       *
       * @param addr The internal registeraddress of the MMA8452
       * @return The value of the register
       */
      int readRegister(char addr, char *dst);
      
      int readRegister(char addr, char *dst, int nbytes);
        
       /** 
        * Write to the specified MMA8452 register.
        *
        * @param addr The internal register address
        * @param data Data to write
        */    
      int writeRegister(char addr, char data);
      
       /** 
        * Write a data buffer to the specified MMA8452 register.
        *
        * @param addr The internal register address
        * @param data Data buffer to write
        * @param nbytes The length of the data buffer to write
        */    
      int writeRegister(char addr, char *data, int nbytes);
      
      int logicalANDRegister(char addr, char mask);
      int logicalORRegister(char addr, char mask);
      int logicalXORRegister(char addr, char mask);
      
      int setDynamicRange(DynamicRange range, int toggleActivation=1);
      int setBitDepth(BitDepth depth, int toggleActivation=1);
      int setDataRate(DataRateHz dataRate, int toggleActivation=1);
      
      DynamicRange getDynamicRange();
      DataRateHz getDataRate();
      BitDepth getBitDepth();
      
      #ifdef MMA8452_DEBUG
      void debugRegister(char reg);
      #endif
   
    private:
      int readRaw(char src, char *dst, int len);
      int maskAndApplyRegister(char reg, char mask, char value, int toggleActivation);
      
      int twelveBitToSigned(char *buf);
      int eightBitToSigned(char *buf);
      double convertCountToGravity(int count, int countsPerG);
      char getMaskedRegister(int reg, char mask);
    
      I2C _i2c;
      int _frequency;
      int _readAddress;
      int _writeAddress;
      
      BitDepth _bitDepth;
      DynamicRange _dynamicRange;
         
};