Works with 8g

Fork of MMA8452 by Ashley Mills

Revision:
11:dfd1e0afcb7b
Parent:
10:ca9ba7ad4e94
Child:
12:172540ff6b8b
--- a/MMA8452.cpp	Tue Mar 04 11:14:34 2014 +0000
+++ b/MMA8452.cpp	Tue Mar 04 16:23:40 2014 +0000
@@ -1,4 +1,4 @@
-// Author: Nicholas Herriot
+// Author: Nicholas Herriot, Ashley Mills
 /* Copyright (c) 2013 Vodafone, MIT License
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
@@ -17,15 +17,20 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-# include "MMA8452.h"
+#include "MMA8452.h"
+#include "mbed.h"
+
+extern Serial pc;
 
 // Connect module at I2C address using I2C port pins sda and scl
-MMA8452::MMA8452(PinName sda, PinName scl,int frequency) : m_i2c(sda, scl) , m_frequency(frequency) {
-    //m_i2c.frequency(m_frequency);
-    
-    // setup read and write addresses to avoid duplication
-   _readAddress   = (MMA8452_ADDRESS<<1) | 0x01;
-   _writeAddress  = (MMA8452_ADDRESS<<1) & 0xFE;
+MMA8452::MMA8452(PinName sda, PinName scl, int frequency) : _i2c(sda, scl) , _frequency(frequency) {
+   DBG("Creating MMA8452");
+   _i2c.frequency(_frequency);
+   
+   // setup read and write addresses to avoid duplication
+   _readAddress   = MMA8452_ADDRESS | 0x01;
+   _writeAddress  = MMA8452_ADDRESS & 0xFE;
+   DBG("Done");
 }
 
 
@@ -34,99 +39,93 @@
 
 // Setting the control register bit 1 to true to activate the MMA8452
 int MMA8452::activate() {
-    // set control register 1 to active
-    char init[2] = {CTRL_REG_1,ACTIVE};
-    
     // perform write and return error code
-    return m_i2c.write(_writeAddress,init,2);
+    return logicalORRegister(CTRL_REG_1,MMA8452_ACTIVE_MASK);
 }
 
-
-// Get 'Fast Read Mode' called F_READ. If bit 1 is set '1' then F_READ is active. Fast read will skip LSB when reading xyz
-// resisters from 0x01 to 0x06. When F_READ is '0' then all 6 registers will be read.
-
-int MMA8452::get_CTRL_Reg1(int* dst)
-{   
-   return readRegister(CTRL_REG_1,dst); 
+// 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);
 }
 
-// Setting the control register bit 1 to true to activate the MMA8452
-int MMA8452::standby()
-{
-    // set control register 1 to standby
-    char init[2] = {CTRL_REG_1,STANDBY};
-    
-    // write to the register and return the error code
-    return m_i2c.write(_writeAddress,init,2);
+// this reads a register, applies a bitmask with logical AND, sets a value with logical OR,
+// and optionally goes into and out of standby at the beginning and end of the function respectively
+int MMA8452::maskAndApplyRegister(char reg, char mask, char value, int toggleActivation) {
+   if(toggleActivation) {
+       if(standby()) {
+          return 1;
+       }
+   }
+   
+   // read from register
+   char oldValue = 0;
+   if(readRegister(reg,&oldValue)) {
+      return 1;
+   }
+   
+   // apply bitmask
+   oldValue &= mask;
+   
+   // set value
+   oldValue |= value;
+   
+   // write back to register
+   if(writeRegister(reg,oldValue)) {
+      return 1;
+   }
+   
+   if(toggleActivation) {
+       if(activate()) {
+          return 1;
+       }
+   }
+   return 0;
 }
 
-
-
-// Device initialization
-void MMA8452::init()
-{
-    
-    writeRegister(INTSU_STATUS, 0x10);      // automatic interrupt after every measurement
-    writeRegister(SR_STATUS, 0x00);         // 120 Samples/Second
-    writeRegister(MODE_STATUS, 0x01);       // Active Mode
-    
+int MMA8452::setDynamicRange(DynamicRange range, int toggleActivation) {
+   return maskAndApplyRegister(
+      MMA8452_XYZ_DATA_CFG,
+      MMA8452_DYNAMIC_RANGE_MASK,
+      range,
+      toggleActivation
+   );
 }
 
-// Get real time status of device - it can be STANDBY, WAKE or SLEEP
-int MMA8452::getSystemMode(int *dst)
-{
-    return readRegister(SYSMOD,dst);
+int MMA8452::setDataRate(DataRateHz dataRate, int toggleActivation) {
+   return maskAndApplyRegister(
+       MMA8452_CTRL_REG_1,
+       MMA8452_DATA_RATE_MASK,
+       dataRate<<MMA8452_DATA_RATE_MASK_SHIFT,
+       toggleActivation
+   );
 }
 
-
-
-// Get real time status of device - it can be STANDBY, WAKE or SLEEP
-int MMA8452::getStatus(int* dst)
-{
-    return readRegister(STATUS,dst);
+int MMA8452::setBitDepth(BitDepth depth,int toggleActivation) {
+   return maskAndApplyRegister(
+      MMA8452_CTRL_REG_1,
+      MMA8452_BIT_DEPTH_MASK,
+      depth<<MMA8452_BIT_DEPTH_MASK_SHIFT,
+      toggleActivation
+   );
 }
 
 
 // Get device ID 
-int MMA8452::getDeviceID(int *dst)
+int MMA8452::getDeviceID(char *dst)
 {
     return readRegister(WHO_AM_I,dst);
 }
 
 
-/*
-// Reads x data
-int MMA8452::read_x(int& xaxisLSB)
-{
-    char mcu_address = (MMA8452_ADDRESS<<1);
-    m_i2c.start();
-    if( m_i2c.write( mcu_address & 0xFE) == 0)          // just good practice to force bit 1 to a '0' by ANDing with 0xFE
-    {
-        return 1;                                       // we failed to write the mcu address on the bus to initiate dialogue 
-    }
-    if( m_i2c.write( OUT_X_MSB) == 0) 
-    {
-        return 1;                                       // we failed to write 'X axis LSB' to the chip
-    }
-    m_i2c.start();
-    if( m_i2c.write( mcu_address | 0x01) == 0)          // this is asking to read the slave mcu address - even though it's a 'write' method!!! Crap API...
-    {
-        return 1;                                       // we failed to request a read from that mcu - this really is just writing the mcu vaule on the bus
-    }
-    xaxisLSB  = m_i2c.read(0);
-    m_i2c.stop();
-    return 0;
-}
-*/
-
 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(m_i2c.write(_writeAddress,register_address,1,true) == 0)
+    if(_i2c.write(_writeAddress,register_address,1,true) == 0)
     {
-        if(m_i2c.read(_readAddress,dst,len)==0)
+        if(_i2c.read(_readAddress,dst,len)==0)
         {
            return 0;
         }
@@ -144,8 +143,7 @@
 // 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)
-{   
+int MMA8452::readRawX(char *xaxis) {   
     return readRaw(OUT_X_MSB,xaxis,2);  
 }
 
@@ -178,37 +176,57 @@
 {
     char mcu_address = (MMA8452_ADDRESS <<1);
 
-    m_i2c.start();                  // Start
-    m_i2c.write(mcu_address);              // A write to device 0x98
-    m_i2c.write(OUT_Y_MSB);             // Register to read
-    m_i2c.start();                  
-    m_i2c.write(mcu_address);              // Read from device 0x99
-    int y = m_i2c.read(0);         // Read the data
-    m_i2c.stop();
+    _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);
     
-    m_i2c.start();                  // Start
-    m_i2c.write(mcu_address);              // A write to device 0x98
-    m_i2c.write(OUT_Z_MSB);             // Register to read
-    m_i2c.start();                  
-    m_i2c.write(mcu_address);              // Read from device 0x99
-    int z = m_i2c.read(0);         // Read the data
-    m_i2c.stop();
+    _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)) {
+      return MMA8452::DYNAMIC_RANGE_UNKNOWN;
+   }
+   rval &= (MMA8452_DYNAMIC_RANGE_MASK^0xFF);
+   return (MMA8452::DynamicRange)rval;
+}
+
+MMA8452::DataRateHz MMA8452::getDataRate() {
+   char rval = 0;
+   if(readRegister(MMA8452_CTRL_REG_1,&rval)) {
+      return MMA8452::RATE_UNKNOWN;
+   }
+   // logical AND with inverse of mask
+   rval = rval&(MMA8452_DATA_RATE_MASK^0xFF);
+   // shift back into position
+   rval >>= MMA8452_DATA_RATE_MASK_SHIFT;
+   return (MMA8452::DataRateHz)rval;
+}
+
 // Reads xyz
 int MMA8452::readRawXYZ(char *x, char *y, char *z) 
 {
@@ -217,12 +235,12 @@
     char mcu_address = (MMA8452_ADDRESS <<1);
     char register_buffer[6] ={0,0,0,0,0,0};
     const char Addr_X = OUT_X_MSB;
-    m_i2c.write(mcu_address);              // A write to device 0x98
-    m_i2c.write(MMA8452_ADDRESS, &Addr_X, 1);         // Pointer to the OUT_X_MSB register
+    _i2c.write(mcu_address);              // A write to device 0x98
+    _i2c.write(MMA8452_ADDRESS, &Addr_X, 1);         // Pointer to the OUT_X_MSB register
     
-    if(m_i2c.write(mcu_address,&Addr_X,1) == 0)
+    if(_i2c.write(mcu_address,&Addr_X,1) == 0)
     {
-        if(m_i2c.read(mcu_address,register_buffer,6) == 0)
+        if(_i2c.read(mcu_address,register_buffer,6) == 0)
         {
             *x = register_buffer[1];
             *y = register_buffer[3];
@@ -241,47 +259,159 @@
 
 }
 
-        // Write register (The device must be placed in Standby Mode to change the value of the registers) 
-void MMA8452::writeRegister(char addr, char data)
-{
+// apply an AND mask to a register. read register value, apply mask, write it back
+int MMA8452::logicalANDRegister(char addr, char mask) {
+   char value = 0;
+   // read register value
+   if(readRegister(addr,&value)) {
+      return 0;
+   }
+   // apply mask
+   value &= mask;
+   return writeRegister(addr,value);
+}
+
+
+// apply an OR mask to a register. read register value, apply mask, write it back
+int MMA8452::logicalORRegister(char addr, char mask) {
+   char value = 0;
+   // read register value
+   if(readRegister(addr,&value)) {
+      return 0;
+   }
+   // apply mask
+   value |= mask;
+   return writeRegister(addr,value);
+}
+
 
-    char cmd[2] = {0, 0};
-    
-    cmd[0] = MODE_STATUS;
-    cmd[1] = 0x00;                      // Standby Mode on
-    m_i2c.write(MMA8452_ADDRESS, cmd, 2);
-  
-    cmd[0] = addr;
-    cmd[1] = data;                      // New value of the register
-    m_i2c.write(MMA8452_ADDRESS, cmd, 2); 
-      
-    cmd[0] = MODE_STATUS;
-    cmd[1] = 0x01;                      // Active Mode on
-    m_i2c.write(MMA8452_ADDRESS, cmd, 2);
-                  
+// 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;
+   // read register value
+   if(readRegister(addr,&value)) {
+      return 0;
+   }
+   // apply mask
+   value ^= mask;
+   return writeRegister(addr,value);
+}
+
+// Write register (The device must be placed in Standby Mode to change the value of the registers) 
+int MMA8452::writeRegister(char addr, char data) {
+    // what this actually does is the following
+    // 1. tell I2C bus to start transaction
+    // 2. tell slave we want to write (slave address & write flag)
+    // 3. send the write address
+    // 4. send the data to write
+    // 5. tell I2C bus to end transaction
+
+    // we can wrap this up in the I2C library write function
+    char buf[2] = {0,0};
+    buf[0] = addr;
+    buf[1] = data;
+    return _i2c.write(MMA8452_ADDRESS, buf,2);
+    // note, could also do return writeRegister(addr,&data,1);
 }
 
-        // Read from specified MMA7660FC register
-int MMA8452::readRegister(char addr, int *dst)
-{
+
+int MMA8452::writeRegister(char addr, char *data, int nbytes) {
+    // writing multiple bytes is a little bit annoying because
+    // the I2C library doesn't support sending the address separately
+    // so we just do it manually
     
-    m_i2c.start();
-    if( m_i2c.write(_writeAddress) == 0)
-    {
-        return 1;                                   // we failed to write the mcu address on the bus to initiate dialogue 
+    // 1. tell I2C bus to start transaction
+    _i2c.start();
+    // 2. tell slave we want to write (slave address & write flag)
+    if(_i2c.write(_writeAddress)!=1) {
+       return 1;
+    }
+    // 3. send the write address
+    if(_i2c.write(addr)!=1) {
+       return 1;
+    }
+    // 4. send the data to write
+    for(int i=0; i<nbytes; i++) {
+       if(_i2c.write(data[i])!=1) {
+          return 1;
+       }
+    }
+    // 5. tell I2C bus to end transaction
+    _i2c.stop();
+    return 0;
+}
+
+int MMA8452::readRegister(char addr, char *dst, int nbytes) {
+    // this is a bit odd, but basically proceeds like this
+    // 1. Send a start command
+    // 2. Tell the slave we want to write (slave address & write flag)
+    // 3. Send the address of the register (addr)
+    // 4. Send another start command to delineate read portion
+    // 5. Tell the slave we want to read (slave address & read flag)
+    // 6. Read the register value bytes
+    // 7. Send a stop command
+    
+    // we can wrap this process in the I2C library read and write commands
+    if(_i2c.write(MMA8452_ADDRESS,&addr,1,true)) {
+       return 1;
     }
-    if( m_i2c.write(addr) == 0) 
-    {
-        return 1;                                       // we failed to write 'status' to the chip
-    }
-    m_i2c.start();
-    if( m_i2c.write(_readAddress) == 0)          // this is asking to read the slave mcu address - even though it's a 'write' method!!! Crap API...
-    {
-        return 1;                                       // we failed to request a read from that mcu - this really is just writing the mcu vaule on the bus
-    }
-    *dst = m_i2c.read(0);
-    m_i2c.stop();      
- 
-    return 0;
-    
+    return _i2c.read(MMA8452_ADDRESS,dst,nbytes);
+}
+
+// most registers are 1 byte, so here is a convenience function
+int MMA8452::readRegister(char addr, char *dst) {
+    return readRegister(addr,dst,1);
 }
+
+void MMA8452::debugRegister(char reg) {
+   // get register value
+   char v = 0;
+   if(readRegister(reg,&v)) {
+      DBG("Error reading control register");
+      return;
+   }
+   // print out details
+   switch(reg) {
+      case MMA8452_CTRL_REG_1:
+         DBG("CTRL_REG_1 has value: 0x%x",v);
+         DBG(" 7  ALSP_RATE_1: %d",(v&0x80)>>7);
+         DBG(" 6  ALSP_RATE_0: %d",(v&0x40)>>6);
+         DBG(" 5  DR2: %d",        (v&0x20)>>5);
+         DBG(" 4  DR1: %d",        (v&0x10)>>4);
+         DBG(" 3  DR0: %d",        (v&0x08)>>3);
+         DBG(" 2  LNOISE: %d",     (v&0x04)>>2);
+         DBG(" 1  FREAD: %d",      (v&0x02)>>1);
+         DBG(" 0  ACTIVE: %d",     (v&0x01));
+      break;
+        
+      case MMA8452_XYZ_DATA_CFG:
+         DBG("XYZ_DATA_CFG has value: 0x%x",v);
+         DBG(" 7  Unused: %d", (v&0x80)>>7);
+         DBG(" 6  0: %d",      (v&0x40)>>6);
+         DBG(" 5  0: %d",      (v&0x20)>>5);
+         DBG(" 4  HPF_Out: %d",(v&0x10)>>4);
+         DBG(" 3  0: %d",      (v&0x08)>>3);
+         DBG(" 2  0: %d",      (v&0x04)>>2);
+         DBG(" 1  FS1: %d",    (v&0x02)>>1);
+         DBG(" 0  FS0: %d",    (v&0x01));
+         switch(v&0x03) {
+            case 0:
+               DBG("Dynamic range: 2G");
+            break;
+            case 1:
+               DBG("Dynamic range: 4G");
+            break;
+            case 2:
+               DBG("Dynamic range: 8G");
+            break;
+            default:
+               DBG("Unknown dynamic range");
+            break;
+         }
+      break;
+      
+      default:
+         DBG("Unknown register address: 0x%x",reg);
+      break;
+   }
+}
\ No newline at end of file