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.

Files at this revision

API Documentation at this revision

Comitter:
ashleymills
Date:
Tue Mar 04 17:50:47 2014 +0000
Parent:
11:dfd1e0afcb7b
Child:
13:4bd8b4cd479d
Commit message:
Added basic raw reading back in after remake.

Changed in this revision

MMA8452.cpp Show annotated file Show diff for this revision Revisions of this file
MMA8452.h Show annotated file Show diff for this revision Revisions of this file
--- a/MMA8452.cpp	Tue Mar 04 16:23:40 2014 +0000
+++ b/MMA8452.cpp	Tue Mar 04 17:50:47 2014 +0000
@@ -25,11 +25,17 @@
 // Connect module at I2C address using I2C port pins sda and scl
 MMA8452::MMA8452(PinName sda, PinName scl, int frequency) : _i2c(sda, scl) , _frequency(frequency) {
    DBG("Creating MMA8452");
+   
+   // set I2C frequency
    _i2c.frequency(_frequency);
    
-   // setup read and write addresses to avoid duplication
+   // setup read and write addresses for convenience
    _readAddress   = MMA8452_ADDRESS | 0x01;
    _writeAddress  = MMA8452_ADDRESS & 0xFE;
+   
+   // set some defaults
+   _bitDepth = BIT_DEPTH_UNKNOWN;
+   setBitDepth(BIT_DEPTH_12);
    DBG("Done");
 }
 
@@ -40,13 +46,13 @@
 // Setting the control register bit 1 to true to activate the MMA8452
 int MMA8452::activate() {
     // perform write and return error code
-    return logicalORRegister(CTRL_REG_1,MMA8452_ACTIVE_MASK);
+    return logicalORRegister(MMA8452_CTRL_REG_1,MMA8452_ACTIVE_MASK);
 }
 
 // Setting the control register bit 1 to 0 to standby the MMA8452
 int MMA8452::standby() {
     // perform write and return error code
-    return logicalANDRegister(CTRL_REG_1,MMA8452_STANDBY_MASK);
+    return logicalANDRegister(MMA8452_CTRL_REG_1,MMA8452_STANDBY_MASK);
 }
 
 // this reads a register, applies a bitmask with logical AND, sets a value with logical OR,
@@ -102,6 +108,7 @@
 }
 
 int MMA8452::setBitDepth(BitDepth depth,int toggleActivation) {
+   _bitDepth = depth;
    return maskAndApplyRegister(
       MMA8452_CTRL_REG_1,
       MMA8452_BIT_DEPTH_MASK,
@@ -110,105 +117,25 @@
    );
 }
 
-
-// Get device ID 
-int MMA8452::getDeviceID(char *dst)
-{
-    return readRegister(WHO_AM_I,dst);
+int MMA8452::isXYZReady() {
+   char rval = 0;
+   if(readRegister(MMA8452_STATUS,&rval)) {
+      return 0;
+   }
+   return (rval&MMA8452_STATUS_ZYXDR_MASK);
 }
-
-
-int MMA8452::readRaw(char src, char *dst, int len) {
-    // this is the register we want to get data from               
-    char register_address[1];
-    register_address[0] = src;
-    
-    if(_i2c.write(_writeAddress,register_address,1,true) == 0)
-    {
-        if(_i2c.read(_readAddress,dst,len)==0)
-        {
-           return 0;
-        }
-    }
-    
-    // failure case, zero array and return error
-    for(int i=0; i<len; i++) {
-       dst[i] = 0x00;
-    }
-    return 1;   
-}
-
-// Reads x data. This method reads two registers containing the x-axis values from the accelerometer. 
-// It takes a 2 byte char array and copies the register values into the buffer. If it fails the char array
-// is set to '0'. It returns '0' success '1' fail. This method does nothing to the registers - just returns
-// the raw data.
-//int MMA8452::read_x(int& xaxisLSB)
-int MMA8452::readRawX(char *xaxis) {   
-    return readRaw(OUT_X_MSB,xaxis,2);  
-}
-
-
-// Reads y data. This method reads two registers containing the x-axis values from the accelerometer. 
-// It takes a 2 byte char array and copies the register values into the buffer. If it fails the char array
-// is set to '0'. It returns '0' success '1' fail. This method does nothing to the registers - just returns
-// the raw data.
-
-int MMA8452::readRawY(char *yaxis) {
-   return readRaw(OUT_Y_MSB,yaxis,2);
+ 
+int MMA8452::getDeviceID(char *dst) {
+   return readRegister(MMA8452_WHO_AM_I,dst);
 }
 
-
-
-// Reads z data. This method reads two registers containing the x-axis values from the accelerometer. 
-// It takes a 2 byte char array and copies the register values into the buffer. If it fails the char array
-// is set to '0'. It returns '0' success '1' fail. This method does nothing to the registers - just returns
-// the raw data.
-
-int MMA8452::readRawZ(char *zaxis)
-{
-   return readRaw(OUT_Z_MSB,zaxis,2);
+int MMA8452::getStatus(char* dst) {
+   return readRegister(MMA8452_STATUS,dst);
 }
 
-
-
-// Reads y data
-int MMA8452::read_y()
-{
-    char mcu_address = (MMA8452_ADDRESS <<1);
-
-    _i2c.start();                  // Start
-    _i2c.write(mcu_address);              // A write to device 0x98
-    _i2c.write(OUT_Y_MSB);             // Register to read
-    _i2c.start();                  
-    _i2c.write(mcu_address);              // Read from device 0x99
-    int y = _i2c.read(0);         // Read the data
-    _i2c.stop();
-    
-    return y; 
-
-}
-
-// Reads z data
-int MMA8452::read_z()
-{
-    char mcu_address = (MMA8452_ADDRESS <<1);
-    
-    _i2c.start();                  // Start
-    _i2c.write(mcu_address);              // A write to device 0x98
-    _i2c.write(OUT_Z_MSB);             // Register to read
-    _i2c.start();                  
-    _i2c.write(mcu_address);              // Read from device 0x99
-    int z = _i2c.read(0);         // Read the data
-    _i2c.stop();
-    
-    return z;
-
-}
-
-
 MMA8452::DynamicRange MMA8452::getDynamicRange() {
    char rval = 0;
-   if(readRegister(MMA8452_CTRL_REG_1,&rval)) {
+   if(readRegister(MMA8452_XYZ_DATA_CFG,&rval)) {
       return MMA8452::DYNAMIC_RANGE_UNKNOWN;
    }
    rval &= (MMA8452_DYNAMIC_RANGE_MASK^0xFF);
@@ -228,35 +155,15 @@
 }
 
 // Reads xyz
-int MMA8452::readRawXYZ(char *x, char *y, char *z) 
-{
-    
-    
-    char mcu_address = (MMA8452_ADDRESS <<1);
-    char register_buffer[6] ={0,0,0,0,0,0};
-    const char Addr_X = OUT_X_MSB;
-    _i2c.write(mcu_address);              // A write to device 0x98
-    _i2c.write(MMA8452_ADDRESS, &Addr_X, 1);         // Pointer to the OUT_X_MSB register
-    
-    if(_i2c.write(mcu_address,&Addr_X,1) == 0)
-    {
-        if(_i2c.read(mcu_address,register_buffer,6) == 0)
-        {
-            *x = register_buffer[1];
-            *y = register_buffer[3];
-            *z = register_buffer[5];
-            return 0;           // yahoooooo
-        }
-        else
-        {
-            return 1;           // failed oh nooo!
-        }    
-    }
-    else
-    {
-        return 1;               // failed oh nooo!
-    }
-
+int MMA8452::readRawXYZ(char *dst) {
+   if(_bitDepth==BIT_DEPTH_UNKNOWN) {
+      return 1;
+   }
+   int readLen = 3;
+   if(_bitDepth==BIT_DEPTH_12) {
+      readLen = 6;
+   }
+   return readRegister(MMA8452_OUT_X_MSB,dst,readLen);
 }
 
 // apply an AND mask to a register. read register value, apply mask, write it back
@@ -284,7 +191,6 @@
    return writeRegister(addr,value);
 }
 
-
 // apply an OR mask to a register. read register value, apply mask, write it back
 int MMA8452::logicalXORRegister(char addr, char mask) {
    char value = 0;
@@ -367,7 +273,7 @@
    // get register value
    char v = 0;
    if(readRegister(reg,&v)) {
-      DBG("Error reading control register");
+      DBG("Error reading specified register");
       return;
    }
    // print out details
@@ -410,6 +316,18 @@
          }
       break;
       
+      case MMA8452_STATUS:
+         DBG("STATUS has value: 0x%x",v);
+         DBG(" 7  ZYXOW: %d",(v&0x80)>>7);
+         DBG(" 6  ZOW: %d",  (v&0x40)>>6);
+         DBG(" 5  YOW: %d",  (v&0x20)>>5);
+         DBG(" 4  XOW: %d",  (v&0x10)>>4);
+         DBG(" 3  ZYXDR: %d",(v&0x08)>>3);
+         DBG(" 2  ZDR: %d",  (v&0x04)>>2);
+         DBG(" 1  YDR: %d",  (v&0x02)>>1);
+         DBG(" 0  XDR: %d",  (v&0x01));
+      break;
+      
       default:
          DBG("Unknown register address: 0x%x",reg);
       break;
--- a/MMA8452.h	Tue Mar 04 16:23:40 2014 +0000
+++ b/MMA8452.h	Tue Mar 04 17:50:47 2014 +0000
@@ -74,42 +74,44 @@
 #endif
 
 // Register descriptions found in section 6 of pdf
-#define STATUS 0x00                         // Type 'read' : Real time status, should return 0x00
-#define OUT_X_MSB 0x01                      // Type 'read' : x axis - 8 most significatn bit of a 12 bit sample
-#define OUT_X_LSB 0x02                      // Type 'read' : x axis - 4 least significatn bit of a 12 bit sample
-#define OUT_Y_MSB 0x03                      // Type 'read' : y axis - 8 most significatn bit of a 12 bit sample
-#define OUT_Y_LSB 0x04                      // Type 'read' : y axis - 4 least significatn bit of a 12 bit sample
-#define OUT_Z_MSB 0x05                      // Type 'read' : z axis - 8 most significatn bit of a 12 bit sample
-#define OUT_Z_LSB 0x06                      // Type 'read' : z axis - 4 least significatn bit of a 12 bit sample
+#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
 
-#define SYSMOD 0x0B                         // Type 'read' : This tells you if device is active, sleep or standy 0x00=STANDBY 0x01=WAKE 0x02=SLEEP
-#define WHO_AM_I 0x0D                       // Type 'read' : This should return the device id of 0x2A
+// 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 PL_STATUS 0x10                      // Type 'read' : This shows portrait landscape mode orientation
-#define PL_CFG 0x11                         // Type 'read/write' : This allows portrait landscape configuration
-#define PL_COUNT 0x12                       // Type 'read' : This is the portraint landscape debounce counter
-#define PL_BF_ZCOMP 0x13                    // Type 'read' :
-#define PL_THS_REG 0x14                     // Type 'read' :
+#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 FF_MT_CFG 0X15                      // Type 'read/write' : Freefaul motion functional block configuration
-#define FF_MT_SRC 0X16                      // Type 'read' : Freefaul motion event source register
-#define FF_MT_THS 0X17                      // Type 'read' : Freefaul motion threshold register
-#define FF_COUNT 0X18                       // Type 'read' : Freefaul motion debouce counter
+#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 ASLP_COUNT 0x29                     // Type 'read/write' : Counter settings for auto sleep
-#define CTRL_REG_1 0x2A                     // Type 'read/write' :
-#define CTRL_REG_2 0x2B                     // Type 'read/write' :
-#define CTRL_REG_3 0x2C                     // Type 'read/write' :
-#define CTRL_REG_4 0x2D                     // Type 'read/write' :
-#define CTRL_REG_5 0x2E                     // Type 'read/write' :
+#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)
@@ -120,23 +122,27 @@
 #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
- 
-#define MMA8452_XYZ_DATA_CFG 0x0E
-#define MMA8452_CTRL_REG_1 0x2A
 
+// 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
  
 class MMA8452         
 {        
@@ -151,7 +157,8 @@
         
        enum BitDepth {
            BIT_DEPTH_12=0x00,
-           BIT_DEPTH_8 // 1 sets fast read mode, hence the inversion
+           BIT_DEPTH_8, // 1 sets fast read mode, hence the inversion
+           BIT_DEPTH_UNKNOWN
        };
        
        enum DataRateHz {
@@ -228,21 +235,19 @@
         */        
       int getDeviceID(char* dst);  
       
-      int read_y();
-      
-      int read_z();  
+      int getStatus(char* dst);  
 
       /** Read the x register of the MMA8452
         *
         * @returns The value of x acceleration
         */
-      int readRawX(char *xaxis);
-      //int read_x(int& xaxisLSB);
+      int readRawX(char *dst);
+      
       /** Read the y register of the MMA8452
-        *
-        * @returns The value of y acceleration
-        */
-      int readRawY(char *yaxis);
+       * @param dst The destination buffer
+       * @returns The value of y acceleration
+       */
+      int readRawY(char *dst);
       
       /** Read the z register of the MMA8452
         *
@@ -250,30 +255,41 @@
         */
        int readRawZ(char * zaxis);
       
-      /** Read the x,y and z registers of the MMA8452
+      /** 
+       * Read the x,y, and z registers of the MMA8452.
        *
-       * takes a 2 byte char buffer to store the value
-       * for each axis.
-       * returns 0 for success, and 1 for failure
-       *
+       * @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 readRawXYZ(char *x, char *y, char *z); 
+      int readRawXYZ(char *dst); 
+      
+      int isXYZReady();
             
-        /** Read from specified MMA8452 register
-         *
-         * @param addr The internal registeraddress of the MMA8452
-         * @returns The value of the register
-         */
+      /** 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 specified MMA8452 register
+       /** 
+        * Write to the specified MMA8452 register.
         *
-        * @param addr The internal registeraddress of the MMA8452
-        * @param data New value of the 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);
@@ -285,6 +301,7 @@
       int setDataRate(DataRateHz dataRate, int toggleActivation=1);
       DynamicRange getDynamicRange();
       DataRateHz getDataRate();
+      BitDepth getBitDepth();
       
       void debugRegister(char reg);
    
@@ -296,6 +313,8 @@
       int _frequency;
       int _readAddress;
       int _writeAddress;
+      
+      BitDepth _bitDepth;
          
 };