Class Module for MMA845x I2C Accelerometer.

Dependents:   mDotEVBM2X MTDOT-EVBDemo-DRH MTDOT-BOX-EVB-Factory-Firmware-LIB-108 MTDOT-UDKDemo_Senet ... more

Fork of MMA845x by Sam Grove

Revision:
1:41af2b3eefb5
Parent:
0:9d1e3a344e4f
Child:
2:70df6adad015
--- a/MMA845x.cpp	Fri Mar 29 21:51:11 2013 +0000
+++ b/MMA845x.cpp	Mon Jul 06 19:53:27 2015 +0000
@@ -1,13 +1,13 @@
 /**
  * @file    MMA845x.cpp
- * @brief   Device driver - MMA845X 3-axis accelerometer IC
- * @author  sam grove
+ * @brief   Device driver - MMA845X 3-axis accelerometer IC W/RTOS support
+ * @author  Tim Barr
  * @version 1.0
  * @see     http://cache.freescale.com/files/sensors/doc/data_sheet/MMA8451Q.pdf
  * @see     http://cache.freescale.com/files/sensors/doc/data_sheet/MMA8452Q.pdf
  * @see     http://cache.freescale.com/files/sensors/doc/data_sheet/MMA8453Q.pdf
  *
- * Copyright (c) 2013
+ * Copyright (c) 2015
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,155 +20,318 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ * 5/5/2015 Forked from https://developer.mbed.org/users/sam_grove/code/MMA845x/
+ *
+ * 6/20/2015 TAB Added setup functions and polling data capability. Also added RTOS calls
+ * TODO Still need to add interrupt support for other Accelerometer mode support
  */
  
 #include "MMA845x.h"
+#include "mbed_debug.h"
+#include "rtos.h"
  
-MMA845x::MMA845x(I2C &i2c, InterruptIn &int1, InterruptIn &int2, MMA845x_SA0 const i2c_addr)
+MMA845x::MMA845x(I2C &i2c, SA0 const i2c_addr, InterruptIn* int1, InterruptIn* int2)
 {
     _i2c =  &i2c;
-    _int1 = &int1;
-    _int2 = &int2;
-    
-    _i2c_addr = (0x1c << 2) | (i2c_addr << 0x1);
- 
-    return;
-}
-
-void MMA845x::init(void) const
-{
-    uint8_t reg_val = 0;
-    
-    _i2c->frequency(400000);
-    
-    // Reset all registers to POR values
-    MMA845x::writeRegister(CTRL_REG2, 0xFF);        //REG 0x2B
-    do{
-        // wait for the reset bit to clear
-        reg_val = MMA845x::readRegister(CTRL_REG2) & 0x40;
-    }while(reg_val);
-    
-    // setup the registers that are common among modes
-    MMA845x::writeRegister(CTRL_REG1, 0xd8);        //REG 0x2A
-    MMA845x::writeRegister(CTRL_REG2, 0x00);        //REG 0x2B
-    MMA845x::writeRegister(CTRL_REG3, 0x00);        //REG 0x2C
+    _int1 = int1;
+    _int2 = int2;
     
-    MMA845x::writeRegister(XYZ_DATA_CFG, 0x0);      //REG 0xE HPF / scale +/-2,4,8g
-    MMA845x::writeRegister(HP_FILTER_CUTOFF, 0x0);  //REG 0xF HPF settings
-    
-    return;
-}
-
-void MMA845x::enableDataReadyMode(void) const
-{
+    _i2c_addr = (0x1c | i2c_addr) << 1;
+ 
     MMA845x::init();
-    MMA845x::writeRegister(SYSMOD, 0x1);        //REG 0x0B
-    MMA845x::writeRegister(INT_SOURCE, 0x1);    //REG 0x0C
-    // need to finish up these config registers..... 3/8/13
-    
-}
 
-void MMA845x::enableMotionMode(void) const{}
-void MMA845x::enablePulseMode(void) const{}
-
-void MMA845x::enableOrientationMode(void) const
-{
-    uint16_t who_am_i = MMA845x::readRegister(WHO_AM_I);
-    if(who_am_i != MMA8451)
-    {
-        error("%s %d: Feature not compatible with the connected device.\n", __FILE__, __LINE__);
-    }
-    
     return;
 }
 
-void MMA845x::enableTransitMode(void) const{}
-void MMA845x::enableAutoSleepMode(void) const{}
-
-void MMA845x::enableFIFOMode(void) const
+uint8_t MMA845x::init(void)
 {
-    uint16_t who_am_i = MMA845x::readRegister(WHO_AM_I);
-    if(who_am_i != MMA8451)
+    uint8_t result = 0;
+    uint8_t i = 0;
+    char reg_val[1];
+    
+    _i2c->frequency(100000);
+    _who_am_i = 0x00;
+    
+    // Reset all registers to POR values
+    result = MMA845x::writeRegister(CTRL_REG2, 0xFF);        //REG 0x2B
+    if (result == 0){
+
+      do{
+           // wait for the reset bit to clear. readRegister may error out so we re-try 10 times
+	      osDelay(200);
+    	  reg_val[0] = 0x40;
+           result = MMA845x::readRegister(CTRL_REG2,1,reg_val);
+           reg_val[0] = reg_val[0] & 0x40;
+           i++;
+       }while(((reg_val[0] != 0)||( result != 0)) && (i<=10));
+    }
+
+    if (result == 0){
+        result = MMA845x::readRegister(WHO_AM_I,1,reg_val);
+    }
+
+    switch (reg_val[0]){
+    case MMA8451:
+    case MMA8452:
+    case MMA8453:
+        _who_am_i= reg_val[0];
+        if ((_int1 == NULL) && (_int2 == NULL))
+        	_polling_mode = true;
+        else _polling_mode = false;
+        break;
+    default:
+    	debug ("Device not supported by this library!\n\r");
+    	result = 1;
+    }
+
+    if(result != 0)
     {
-        error("%s %d: Feature not compatible with the connected device.\n", __FILE__, __LINE__);
+        debug("MMA845x:init failed\n\r");
+    }
+    
+
+     return result;
+}
+
+uint8_t MMA845x::setCommonParameters(RANGE range, RESOLUTION resolution, LOW_NOISE lo_noise,
+									 DATA_RATE data_rate, OVERSAMPLE_MODE os_mode, HPF_MODE hpf_mode) const
+{
+    uint8_t result = 0;
+    char datain[1];
+    uint8_t dataout = 0;
+
+    result |= MMA845x::readRegister(SYSMOD,1,datain); // Make sure MMA845x is in Stand-By mode
+    if ((datain[0] & 0x03) != 0 ){
+    	debug ("MMA845x not in STAND BY mode\n\f");
+        debug("MMA845x:setCommonParameters failed\n\r");
+        result = 1;
+        return result;
+    }
+
+    result |= MMA845x::readRegister(CTRL_REG1, 1, datain);
+    dataout = (datain[0] & 0xB1) | resolution | lo_noise | data_rate;
+    result |= MMA845x::writeRegister(CTRL_REG1, dataout);        // Set resolution, Low Noise mode, and data rate
+
+    result |= MMA845x::readRegister(CTRL_REG2,1, datain);
+    dataout = (datain[0] & 0xFB) | os_mode;
+    result |= MMA845x::writeRegister(CTRL_REG2, dataout);        // Set Oversample mode
+
+    result |= MMA845x::readRegister(XYZ_DATA_CFG,1, datain);
+    dataout = range | hpf_mode;
+    result |= MMA845x::writeRegister(XYZ_DATA_CFG, dataout);     //Set HPF mode and range
+
+//    result |= MMA845x::readRegister(HP_FILTER_CUTOFF,1, datain);
+//    result |= MMA845x::writeRegister(HP_FILTER_CUTOFF, dataout); //REG 0xF HPF settings
+
+    if(result != 0)
+    {
+        debug("MMA845x:setParameters failed\n\r");
+    }
+    
+     return result;
+    
+}
+
+uint8_t MMA845x::enableMotionDetect(void) const
+{
+    uint8_t result = 0;
+    return result;
     }
     
-    //MMA845x::writeRegister(
+uint8_t MMA845x::enablePulseDetect(void) const
+{
+    uint8_t result = 0;
+    return result;
+    }
+
+uint8_t MMA845x::enableOrientationDetect(void) const
+{
+    uint8_t result = 0;
+
+    if(_who_am_i != MMA8451)
+    {
+        debug("%s %d: Feature not compatible with the connected device.\n", __FILE__, __LINE__);
+        result = 1;
+    }
     
-    return;
+    return result;
+}
+
+uint8_t MMA845x::enableTransientDetect(void) const
+{
+    uint8_t result = 0;
+    return result;
+    }
+    
+uint8_t MMA845x::enableAutoSleep(void) const
+{
+    uint8_t result = 0;
+    return result;
+    }
+
+uint8_t MMA845x::enableFIFO(void) const
+{
+    uint8_t result = 0;
+
+    if(_who_am_i != MMA8451)
+    {
+        debug("%s %d: Feature not compatible with the connected device.\n", __FILE__, __LINE__);
+        result = 1;
+    }
+    
+    return result;
 }
 
-uint16_t MMA845x::getX(void) const
+uint8_t MMA845x::activeMode(void) const
+{
+    uint8_t result = 0;
+    char datain[1];
+    uint8_t dataout;
+
+    result |= MMA845x::readRegister(CTRL_REG1,1, datain);
+    dataout = (datain[0] & 0xFE) | 0x01 ;
+    result |= MMA845x::writeRegister(CTRL_REG1, dataout);        // Set to active mode
+
+    return result;
+    }
+uint8_t MMA845x::standbyMode(void) const
+{
+    uint8_t result = 0;
+    char datain[1];
+    uint8_t dataout;
+
+    result |= MMA845x::readRegister(CTRL_REG1,1, datain);
+    dataout = (datain[0] & 0xFE);
+    result |= MMA845x::writeRegister(CTRL_REG1, dataout);        // Set to standby mode
+
+    return result;
+    }
+
+uint8_t MMA845x::getStatus(void) const
 {
-    return _data._x;
+    uint8_t result = 0;
+    char datain[1];
+    uint8_t dataout;
+
+    result = MMA845x::readRegister(STATUS,1, datain);
+
+    if (result != 0)
+    	dataout = result;
+    else
+    	dataout = datain[0];
+
+    return dataout;
+    }
+
+int16_t MMA845x::getX(void)
+{
+    char datain[2];
+
+	if (_polling_mode)
+    {
+        MMA845x::readRegister(OUT_X_MSB,2, datain);
+        _data._x = ((datain[0] << 8) | datain[1]);  /* data is 14 bit signed with 2 LSB = 0 */
+        _data._x /= 4;        /* need to shift first to preserve sign then /4 to remove LSBs */
+    }
+	return _data._x;
+
 }
     
-uint16_t MMA845x::getY(void) const
+int16_t MMA845x::getY(void)
 {
-    return _data._y;
+    char datain[2];
+
+    if (_polling_mode)
+    {
+        MMA845x::readRegister(OUT_Y_MSB,2, datain);
+        _data._y = ((datain[0] << 8) | datain[1]);   /* data is 14 bit signed with 2 LSB = 0 */
+        _data._y /= 4;        /* need to shift first to preserve sign then /4 to remove LSBs */
+    }
+    	return _data._y;
 }
 
-uint16_t MMA845x::getZ(void) const
+int16_t MMA845x::getZ(void)
 {
+    char datain[2];
+
+    if (_polling_mode)
+    {
+        MMA845x::readRegister(OUT_Z_MSB,2, datain);
+        _data._z = ((datain[0] << 8) | datain[1]);   /* data is 14 bit signed with 2 LSB = 0 */
+        _data._z /= 4;        /* need to shift first to preserve sign then /4 to remove LSBs */
+    }
+
     return _data._z;
 }
     
-MMA845x_DATA MMA845x::getXYZ(void) const
+MMA845x_DATA MMA845x::getXYZ(void)
 {
+    char datain[6];
+
+    if (_polling_mode)
+    {
+        MMA845x::readRegister(OUT_X_MSB,6, datain);   /* data is 14 bit signed with 2 LSB = 0 */
+        _data._x = ((datain[0] << 8) | datain[1]);    /* need to shift first to preserve sign */
+        _data._x /= 4;                                /* then /4 to remove LSBs */
+        _data._y = ((datain[2] << 8) | datain[3]);
+        _data._y /= 4;
+        _data._z = ((datain[4] << 8) | datain[5]);
+        _data._z /= 4;
+    }
+
     return _data;
 }
 
-void MMA845x::writeRegister(uint8_t const reg, uint8_t const data) const
+char MMA845x::getWhoAmI(void) const
+{
+    return _who_am_i;
+}
+
+uint8_t MMA845x::writeRegister(uint8_t const reg, uint8_t const data) const
 {
     char buf[2] = {reg, data};
     uint8_t result = 0;
+
+    buf[0] = reg;
+    buf[1] = data;
     
-    __disable_irq(); // Tickers and other timebase events can jack up the I2C bus for some deicse
-    result = _i2c->write(_i2c_addr, buf, 2);
-    __enable_irq();  // Just need to block during the transaction
+//    __disable_irq(); // Tickers and other timebase events can jack up the I2C bus for some devices
+    result |= _i2c->write(_i2c_addr, buf, 2);
+//    __enable_irq();  // Just need to block during the transaction
     
-    if(0 != result)
+    if(result != 0)
     {
-        error("%s %d: I2c write failed\n", __FILE__, __LINE__);
+        debug("MMA845x:writeRegister failed r-%d\n\r",result);
     }
     
-    return;
+    return result;
 }
 
-uint8_t MMA845x::readRegister(uint8_t const reg) const
+uint8_t MMA845x::readRegister(uint8_t const reg, uint8_t count, char* data) const
 {
-    uint8_t result = 1, data = 0;
+    uint8_t result = 0;
+    char reg_out[1];
     
-    __disable_irq(); // Tickers and other timebase events can jack up the I2C bus
-    _i2c->start();
-    result &= _i2c->write(_i2c_addr);
-    result &= _i2c->write(reg);
-    // issue a repeated start...
-    _i2c->start();
-    result &= _i2c->write(_i2c_addr | 0x01);
-    // read with nak
-    data = _i2c->read(0);
-    _i2c->stop();
-    __enable_irq();  // Just need to block during the transaction
-    
-    if(1 != result)
+    reg_out[0] = reg;
+ //   __disable_irq(); // Tickers and other timebase events can jack up the I2C bus for some devices
+      result |= _i2c->write(_i2c_addr,reg_out,1,true);
+ //   __enable_irq();  // Just need to block during the transaction
+
+    if(result != 0)
     {
-        error("%s %d: I2C read failed\n", __FILE__, __LINE__);
+        debug("MMA845x::readRegister failed write r- %d\n\r", result);
+        return result;
     }
     
-    return data;
-}
-
-void MMA845x::registerDump(void) const
-{
-    uint8_t reg_val = 0;
+ //   __disable_irq(); // Tickers and other timebase events can jack up the I2C bus for some devices
+      result |= _i2c->read(_i2c_addr,data,count,false);
+//    __enable_irq();  // Just need to block during the transaction
     
-    for(int i=0; i<0x80; i++)
+    if(result != 0)
     {
-        reg_val = MMA845x::readRegister(i);
-        printf("Reg 0x%02x: 0x%02x \n", i, reg_val);
+        debug("MMA845x::readRegister failed read r-%d\n\r",result);
     }
     
-    return;
+    return result;
 }
-