A driver for the MMA8451 3-axis Accelerometer.

MMA8451.cpp

Committer:
wilminc
Date:
2019-10-02
Revision:
0:f1c020594c48
Child:
1:13c3035afa27

File content as of revision 0:f1c020594c48:

/**
 * @file      MMA8451.cpp
 * @brief     Driver for the MMA8451 3-axis Accelerometer
 * @author    Wilmin Ceballos (wceballos)
 * @version   1.0
 * @copyright MIT License
 *
 * Copyright (c) 2019 Wilmin Ceballos
 *
 * 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.
 *
 */

#include "MMA8451.h"

MMA8451::MMA8451(I2C &i2c, uint8_t i2cAddr) {
  _i2c = &i2c;
  _i2cAddr = static_cast<uint8_t>(i2cAddr) << 1;

  _i2c->frequency(MMA8451_I2C_CLOCK);
  init();
}

MMA8451::~MMA8451() {

}

bool MMA8451::init() {

  if(id() != 0x1A)
    return false;

  writeRegister(MMA8451_CTRL_REG2, 0x40); // Trigger soft reset
  // RST bit in CTRL_REG2 is deasserted when boot is finished
  uint8_t content;
  while(!readRegister(MMA8451_CTRL_REG2, &content) && (content & 0x40));
  writeRegister(MMA8451_CTRL_REG1, 0x01); // Active mode
  _sens = MMA8451_SENSITIVITY_2G;

  return true;
}

void MMA8451::getXYZ() {
  char ibuf[6] = {0}; // Incoming data
  char baseReg = MMA8451_OUT_X_MSB;
  
  _i2c->write(_i2cAddr, &baseReg, 1, true);
  _i2c->read(_i2cAddr, ibuf, 6, true);

  // Data is 14 bits -> 0b00DDDDDD_DDDDDDDD
  int16_t x_int = (static_cast<int16_t>(ibuf[0]))<<8 | ibuf[1]; x_int>>=2;
  int16_t y_int = (static_cast<int16_t>(ibuf[2]))<<8 | ibuf[3]; y_int>>=2;
  int16_t z_int = (static_cast<int16_t>(ibuf[4]))<<8 | ibuf[5]; z_int>>=2;

  int16_t div = 1;
  if(_sens == MMA8451_SENSITIVITY_2G)
    div = 4096;
  else if(_sens == MMA8451_SENSITIVITY_4G)
    div = 2048;
  else if(_sens == MMA8451_SENSITIVITY_8G)
    div = 1024;

  x = static_cast<float>(x_int) / div;
  y = static_cast<float>(y_int) / div;
  z = static_cast<float>(z_int) / div;
}

float MMA8451::getX() {
  x = _readAxis(MMA8451_OUT_X_MSB);
  return x;
}

float MMA8451::getY() {
  y = _readAxis(MMA8451_OUT_Y_MSB);
  return y;
}

float MMA8451::getZ() {
  z = _readAxis(MMA8451_OUT_Z_MSB);
  return z;
}

uint8_t MMA8451::id() {
    readRegister(MMA8451_WHO_AM_I, &_whoami);
    return _whoami;
}

bool MMA8451::readRegister(uint8_t reg, uint8_t *data) {
  int status = _i2c->write(_i2cAddr, (char*)&reg, 1, true);
  status |= _i2c->read(_i2cAddr, (char*)data, 1, true);
  if(status != 0)
    return false;
  return true;
}

bool MMA8451::writeRegister(uint8_t reg, uint8_t data) {
  char buf[2] = {reg, data};
  int status = _i2c->write(_i2cAddr, buf, 2, true);
  if(status != 0)
    return false;
  return true;
}

float MMA8451::_readAxis(uint8_t reg) {
  char buf[2] = {0}; // Incoming data
  
  _i2c->write(_i2cAddr, (char*)&reg, 1, true);
  _i2c->read(_i2cAddr, buf, 2, true);

  // Data is 14 bits -> 0b00DDDDDD_DDDDDDDD
  int16_t axisData = (static_cast<int16_t>(buf[0]))<<8 | buf[1]; axisData>>=2;

  int16_t div = 1;
  if(_sens == MMA8451_SENSITIVITY_2G)
    div = 4096;
  else if(_sens == MMA8451_SENSITIVITY_4G)
    div = 2048;
  else if(_sens == MMA8451_SENSITIVITY_8G)
    div = 1024;
    
  return (static_cast<float>(axisData) / div);
}

void MMA8451::setStandbyMode() {
  uint8_t content = 0;
  uint8_t mask = 0xFE;
  if(readRegister(MMA8451_CTRL_REG1, &content))
    writeRegister(MMA8451_CTRL_REG1, content & mask);
}

void MMA8451::setActiveMode() {
  uint8_t content = 0;
  uint8_t mask = 0x01;
  if(readRegister(MMA8451_CTRL_REG1, &content))
    writeRegister(MMA8451_CTRL_REG1, content | mask);
}

void MMA8451::setDataRate(mma8451_dataRate_t rate) {
  uint8_t content = 0;
  uint8_t mask = (static_cast<uint8_t>(rate) << 3) & 0x38;
  if(readRegister(MMA8451_CTRL_REG1, &content))
    writeRegister(MMA8451_CTRL_REG1, content | mask);
}

void MMA8451::setSensitivity(mma8451_sensitivity_t sens) {
  writeRegister(MMA8451_XYZ_DATA_CFG, sens);
  _sens = sens;
}