Works with 8g
Fork of MMA8452 by
MMA8452.cpp
- Committer:
- ashleymills
- Date:
- 2014-03-04
- Revision:
- 11:dfd1e0afcb7b
- Parent:
- 10:ca9ba7ad4e94
- Child:
- 12:172540ff6b8b
File content as of revision 11:dfd1e0afcb7b:
// 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 * 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 "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) : _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"); } // Destroys instance MMA8452::~MMA8452() {} // 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); } // 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); } // 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; } int MMA8452::setDynamicRange(DynamicRange range, int toggleActivation) { return maskAndApplyRegister( MMA8452_XYZ_DATA_CFG, MMA8452_DYNAMIC_RANGE_MASK, range, toggleActivation ); } int MMA8452::setDataRate(DataRateHz dataRate, int toggleActivation) { return maskAndApplyRegister( MMA8452_CTRL_REG_1, MMA8452_DATA_RATE_MASK, dataRate<<MMA8452_DATA_RATE_MASK_SHIFT, toggleActivation ); } 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(char *dst) { return readRegister(WHO_AM_I,dst); } 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); } // 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); } // 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)) { 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) { 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! } } // 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); } // 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); } 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 // 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; } 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; } }