Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
MMA8452.cpp
00001 // Authors: Ashley Mills, Nicholas Herriot 00002 /* Copyright (c) 2013 Vodafone, MIT License 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00005 * and associated documentation files (the "Software"), to deal in the Software without restriction, 00006 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 00007 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 00008 * furnished to do so, subject to the following conditions: 00009 * 00010 * The above copyright notice and this permission notice shall be included in all copies or 00011 * substantial portions of the Software. 00012 * 00013 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00014 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00015 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00016 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00017 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00018 */ 00019 00020 #include "MMA8452.h" 00021 #include "mbed.h" 00022 00023 #ifdef MMA8452_DEBUG 00024 // you need to define Serial pc(USBTX,USBRX) somewhere for the below line to make sense 00025 extern Serial pc; 00026 #define MMA8452_DBG(...) pc.printf(__VA_ARGS__); pc.printf("\r\n"); 00027 #else 00028 #define MMA8452_DBG(...) 00029 #endif 00030 00031 // Connect module at I2C address using I2C port pins sda and scl 00032 MMA8452::MMA8452(PinName sda, PinName scl, int frequency) : _i2c(sda, scl) , _frequency(frequency) { 00033 MMA8452_DBG("Creating MMA8452"); 00034 00035 // set I2C frequency 00036 _i2c.frequency(_frequency); 00037 00038 // setup read and write addresses for convenience 00039 _readAddress = MMA8452_ADDRESS | 0x01; 00040 _writeAddress = MMA8452_ADDRESS & 0xFE; 00041 00042 // set some defaults 00043 _bitDepth = BIT_DEPTH_UNKNOWN; 00044 setBitDepth(BIT_DEPTH_12); 00045 _dynamicRange = DYNAMIC_RANGE_UNKNOWN; 00046 setDynamicRange(DYNAMIC_RANGE_2G); 00047 00048 MMA8452_DBG("Done"); 00049 } 00050 00051 00052 // Destroys instance 00053 MMA8452::~MMA8452() {} 00054 00055 // Setting the control register bit 1 to true to activate the MMA8452 00056 int MMA8452::activate() { 00057 // perform write and return error code 00058 return logicalORRegister(MMA8452_CTRL_REG_1,MMA8452_ACTIVE_MASK); 00059 } 00060 00061 // Setting the control register bit 1 to 0 to standby the MMA8452 00062 int MMA8452::standby() { 00063 // perform write and return error code 00064 return logicalANDRegister(MMA8452_CTRL_REG_1,MMA8452_STANDBY_MASK); 00065 } 00066 00067 // this reads a register, applies a bitmask with logical AND, sets a value with logical OR, 00068 // and optionally goes into and out of standby at the beginning and end of the function respectively 00069 int MMA8452::maskAndApplyRegister(char reg, char mask, char value, int toggleActivation) { 00070 if(toggleActivation) { 00071 if(standby()) { 00072 return 1; 00073 } 00074 } 00075 00076 // read from register 00077 char oldValue = 0; 00078 if(readRegister(reg,&oldValue)) { 00079 return 1; 00080 } 00081 00082 // apply bitmask 00083 oldValue &= mask; 00084 00085 // set value 00086 oldValue |= value; 00087 00088 // write back to register 00089 if(writeRegister(reg,oldValue)) { 00090 return 1; 00091 } 00092 00093 if(toggleActivation) { 00094 if(activate()) { 00095 return 1; 00096 } 00097 } 00098 return 0; 00099 } 00100 00101 int MMA8452::setDynamicRange(DynamicRange range, int toggleActivation) { 00102 _dynamicRange = range; 00103 return maskAndApplyRegister( 00104 MMA8452_XYZ_DATA_CFG, 00105 MMA8452_DYNAMIC_RANGE_MASK, 00106 range, 00107 toggleActivation 00108 ); 00109 } 00110 00111 int MMA8452::setDataRate(DataRateHz dataRate, int toggleActivation) { 00112 return maskAndApplyRegister( 00113 MMA8452_CTRL_REG_1, 00114 MMA8452_DATA_RATE_MASK, 00115 dataRate<<MMA8452_DATA_RATE_MASK_SHIFT, 00116 toggleActivation 00117 ); 00118 } 00119 00120 int MMA8452::setBitDepth(BitDepth depth,int toggleActivation) { 00121 _bitDepth = depth; 00122 return maskAndApplyRegister( 00123 MMA8452_CTRL_REG_1, 00124 MMA8452_BIT_DEPTH_MASK, 00125 depth<<MMA8452_BIT_DEPTH_MASK_SHIFT, 00126 toggleActivation 00127 ); 00128 } 00129 00130 char MMA8452::getMaskedRegister(int addr, char mask) { 00131 char rval = 0; 00132 if(readRegister(addr,&rval)) { 00133 return 0; 00134 } 00135 return (rval&mask); 00136 } 00137 00138 int MMA8452::isXYZReady() { 00139 return getMaskedRegister(MMA8452_STATUS,MMA8452_STATUS_ZYXDR_MASK)>0; 00140 } 00141 00142 int MMA8452::isXReady() { 00143 return getMaskedRegister(MMA8452_STATUS,MMA8452_STATUS_XDR_MASK)>0; 00144 } 00145 00146 int MMA8452::isYReady() { 00147 return getMaskedRegister(MMA8452_STATUS,MMA8452_STATUS_YDR_MASK)>0; 00148 } 00149 00150 int MMA8452::isZReady() { 00151 return getMaskedRegister(MMA8452_STATUS,MMA8452_STATUS_ZDR_MASK)>0; 00152 } 00153 00154 00155 int MMA8452::getDeviceID(char *dst) { 00156 return readRegister(MMA8452_WHO_AM_I,dst); 00157 } 00158 00159 int MMA8452::getStatus(char* dst) { 00160 return readRegister(MMA8452_STATUS,dst); 00161 } 00162 00163 MMA8452::DynamicRange MMA8452::getDynamicRange() { 00164 char rval = 0; 00165 if(readRegister(MMA8452_XYZ_DATA_CFG,&rval)) { 00166 return MMA8452::DYNAMIC_RANGE_UNKNOWN; 00167 } 00168 rval &= (MMA8452_DYNAMIC_RANGE_MASK^0xFF); 00169 return (MMA8452::DynamicRange)rval; 00170 } 00171 00172 MMA8452::DataRateHz MMA8452::getDataRate() { 00173 char rval = 0; 00174 if(readRegister(MMA8452_CTRL_REG_1,&rval)) { 00175 return MMA8452::RATE_UNKNOWN; 00176 } 00177 // logical AND with inverse of mask 00178 rval = rval&(MMA8452_DATA_RATE_MASK^0xFF); 00179 // shift back into position 00180 rval >>= MMA8452_DATA_RATE_MASK_SHIFT; 00181 return (MMA8452::DataRateHz)rval; 00182 } 00183 00184 // Reads xyz 00185 int MMA8452::readXYZRaw(char *dst) { 00186 if(_bitDepth==BIT_DEPTH_UNKNOWN) { 00187 return 1; 00188 } 00189 int readLen = 3; 00190 if(_bitDepth==BIT_DEPTH_12) { 00191 readLen = 6; 00192 } 00193 return readRegister(MMA8452_OUT_X_MSB,dst,readLen); 00194 } 00195 00196 int MMA8452::readXRaw(char *dst) { 00197 if(_bitDepth==BIT_DEPTH_UNKNOWN) { 00198 return 1; 00199 } 00200 int readLen = 1; 00201 if(_bitDepth==BIT_DEPTH_12) { 00202 readLen = 2; 00203 } 00204 return readRegister(MMA8452_OUT_X_MSB,dst,readLen); 00205 } 00206 00207 int MMA8452::readYRaw(char *dst) { 00208 if(_bitDepth==BIT_DEPTH_UNKNOWN) { 00209 return 1; 00210 } 00211 int readLen = 1; 00212 if(_bitDepth==BIT_DEPTH_12) { 00213 readLen = 2; 00214 } 00215 return readRegister(MMA8452_OUT_Y_MSB,dst,readLen); 00216 } 00217 00218 int MMA8452::readZRaw(char *dst) { 00219 if(_bitDepth==BIT_DEPTH_UNKNOWN) { 00220 return 1; 00221 } 00222 int readLen = 1; 00223 if(_bitDepth==BIT_DEPTH_12) { 00224 readLen = 2; 00225 } 00226 return readRegister(MMA8452_OUT_Z_MSB,dst,readLen); 00227 } 00228 00229 int MMA8452::readXYZCounts(int *x, int *y, int *z) { 00230 char buf[6]; 00231 if(readXYZRaw((char*)&buf)) { 00232 return 1; 00233 } 00234 if(_bitDepth==BIT_DEPTH_12) { 00235 *x = twelveBitToSigned(&buf[0]); 00236 *y = twelveBitToSigned(&buf[2]); 00237 *z = twelveBitToSigned(&buf[4]); 00238 } else { 00239 *x = eightBitToSigned(&buf[0]); 00240 *y = eightBitToSigned(&buf[1]); 00241 *z = eightBitToSigned(&buf[2]); 00242 } 00243 00244 return 0; 00245 } 00246 00247 int MMA8452::readXCount(int *x) { 00248 char buf[2]; 00249 if(readXRaw((char*)&buf)) { 00250 return 1; 00251 } 00252 if(_bitDepth==BIT_DEPTH_12) { 00253 *x = twelveBitToSigned(&buf[0]); 00254 } else { 00255 *x = eightBitToSigned(&buf[0]); 00256 } 00257 return 0; 00258 } 00259 00260 int MMA8452::readYCount(int *y) { 00261 char buf[2]; 00262 if(readYRaw((char*)&buf)) { 00263 return 1; 00264 } 00265 if(_bitDepth==BIT_DEPTH_12) { 00266 *y = twelveBitToSigned(&buf[0]); 00267 } else { 00268 *y = eightBitToSigned(&buf[0]); 00269 } 00270 return 0; 00271 } 00272 00273 int MMA8452::readZCount(int *z) { 00274 char buf[2]; 00275 if(readZRaw((char*)&buf)) { 00276 return 1; 00277 } 00278 if(_bitDepth==BIT_DEPTH_12) { 00279 *z = twelveBitToSigned(&buf[0]); 00280 } else { 00281 *z = eightBitToSigned(&buf[0]); 00282 } 00283 return 0; 00284 } 00285 00286 double MMA8452::convertCountToGravity(int count, int countsPerG) { 00287 return (double)count/(double)countsPerG; 00288 } 00289 00290 int MMA8452::getCountsPerG() { 00291 // assume starting with DYNAMIC_RANGE_2G and BIT_DEPTH_12 00292 int countsPerG = 1024; 00293 if(_bitDepth==BIT_DEPTH_8) { 00294 countsPerG = 64; 00295 } 00296 switch(_dynamicRange) { 00297 case DYNAMIC_RANGE_4G: 00298 countsPerG /= 2; 00299 break; 00300 case DYNAMIC_RANGE_8G: 00301 countsPerG /= 4; 00302 break; 00303 } 00304 return countsPerG; 00305 } 00306 00307 int MMA8452::readXYZGravity(double *x, double *y, double *z) { 00308 int xCount = 0, yCount = 0, zCount = 0; 00309 if(readXYZCounts(&xCount,&yCount,&zCount)) { 00310 return 1; 00311 } 00312 int countsPerG = getCountsPerG(); 00313 00314 *x = convertCountToGravity(xCount,countsPerG); 00315 *y = convertCountToGravity(yCount,countsPerG); 00316 *z = convertCountToGravity(zCount,countsPerG); 00317 return 0; 00318 } 00319 00320 int MMA8452::readXGravity(double *x) { 00321 int xCount = 0; 00322 if(readXCount(&xCount)) { 00323 return 1; 00324 } 00325 int countsPerG = getCountsPerG(); 00326 00327 *x = convertCountToGravity(xCount,countsPerG); 00328 return 0; 00329 } 00330 00331 int MMA8452::readYGravity(double *y) { 00332 int yCount = 0; 00333 if(readYCount(&yCount)) { 00334 return 1; 00335 } 00336 int countsPerG = getCountsPerG(); 00337 00338 *y = convertCountToGravity(yCount,countsPerG); 00339 return 0; 00340 } 00341 00342 int MMA8452::readZGravity(double *z) { 00343 int zCount = 0; 00344 if(readZCount(&zCount)) { 00345 return 1; 00346 } 00347 int countsPerG = getCountsPerG(); 00348 00349 *z = convertCountToGravity(zCount,countsPerG); 00350 return 0; 00351 } 00352 00353 // apply an AND mask to a register. read register value, apply mask, write it back 00354 int MMA8452::logicalANDRegister(char addr, char mask) { 00355 char value = 0; 00356 // read register value 00357 if(readRegister(addr,&value)) { 00358 return 0; 00359 } 00360 // apply mask 00361 value &= mask; 00362 return writeRegister(addr,value); 00363 } 00364 00365 00366 // apply an OR mask to a register. read register value, apply mask, write it back 00367 int MMA8452::logicalORRegister(char addr, char mask) { 00368 char value = 0; 00369 // read register value 00370 if(readRegister(addr,&value)) { 00371 return 0; 00372 } 00373 // apply mask 00374 value |= mask; 00375 return writeRegister(addr,value); 00376 } 00377 00378 // apply an OR mask to a register. read register value, apply mask, write it back 00379 int MMA8452::logicalXORRegister(char addr, char mask) { 00380 char value = 0; 00381 // read register value 00382 if(readRegister(addr,&value)) { 00383 return 0; 00384 } 00385 // apply mask 00386 value ^= mask; 00387 return writeRegister(addr,value); 00388 } 00389 00390 // Write register (The device must be placed in Standby Mode to change the value of the registers) 00391 int MMA8452::writeRegister(char addr, char data) { 00392 // what this actually does is the following 00393 // 1. tell I2C bus to start transaction 00394 // 2. tell slave we want to write (slave address & write flag) 00395 // 3. send the write address 00396 // 4. send the data to write 00397 // 5. tell I2C bus to end transaction 00398 00399 // we can wrap this up in the I2C library write function 00400 char buf[2] = {0,0}; 00401 buf[0] = addr; 00402 buf[1] = data; 00403 return _i2c.write(MMA8452_ADDRESS, buf,2); 00404 // note, could also do return writeRegister(addr,&data,1); 00405 } 00406 00407 int MMA8452::eightBitToSigned(char *buf) { 00408 return (int8_t)*buf; 00409 } 00410 00411 int MMA8452::twelveBitToSigned(char *buf) { 00412 // cheat by using the int16_t internal type 00413 // all we need to do is convert to little-endian format and shift right 00414 int16_t x = 0; 00415 ((char*)&x)[1] = buf[0]; 00416 ((char*)&x)[0] = buf[1]; 00417 // note this only works because the below is an arithmetic right shift 00418 return x>>4; 00419 } 00420 00421 int MMA8452::writeRegister(char addr, char *data, int nbytes) { 00422 // writing multiple bytes is a little bit annoying because 00423 // the I2C library doesn't support sending the address separately 00424 // so we just do it manually 00425 00426 // 1. tell I2C bus to start transaction 00427 _i2c.start(); 00428 // 2. tell slave we want to write (slave address & write flag) 00429 if(_i2c.write(_writeAddress)!=1) { 00430 return 1; 00431 } 00432 // 3. send the write address 00433 if(_i2c.write(addr)!=1) { 00434 return 1; 00435 } 00436 // 4. send the data to write 00437 for(int i=0; i<nbytes; i++) { 00438 if(_i2c.write(data[i])!=1) { 00439 return 1; 00440 } 00441 } 00442 // 5. tell I2C bus to end transaction 00443 _i2c.stop(); 00444 return 0; 00445 } 00446 00447 int MMA8452::readRegister(char addr, char *dst, int nbytes) { 00448 // this is a bit odd, but basically proceeds like this 00449 // 1. Send a start command 00450 // 2. Tell the slave we want to write (slave address & write flag) 00451 // 3. Send the address of the register (addr) 00452 // 4. Send another start command to delineate read portion 00453 // 5. Tell the slave we want to read (slave address & read flag) 00454 // 6. Read the register value bytes 00455 // 7. Send a stop command 00456 00457 // we can wrap this process in the I2C library read and write commands 00458 if(_i2c.write(MMA8452_ADDRESS,&addr,1,true)) { 00459 return 1; 00460 } 00461 return _i2c.read(MMA8452_ADDRESS,dst,nbytes); 00462 } 00463 00464 // most registers are 1 byte, so here is a convenience function 00465 int MMA8452::readRegister(char addr, char *dst) { 00466 return readRegister(addr,dst,1); 00467 } 00468 00469 MMA8452::BitDepth MMA8452::getBitDepth() { 00470 return _bitDepth; 00471 } 00472 00473 #ifdef MMA8452_DEBUG 00474 void MMA8452::debugRegister(char reg) { 00475 // get register value 00476 char v = 0; 00477 if(readRegister(reg,&v)) { 00478 MMA8452_DBG("Error reading specified register"); 00479 return; 00480 } 00481 // print out details 00482 switch(reg) { 00483 case MMA8452_CTRL_REG_1: 00484 MMA8452_DBG("CTRL_REG_1 has value: 0x%x",v); 00485 MMA8452_DBG(" 7 ALSP_RATE_1: %d",(v&0x80)>>7); 00486 MMA8452_DBG(" 6 ALSP_RATE_0: %d",(v&0x40)>>6); 00487 MMA8452_DBG(" 5 DR2: %d", (v&0x20)>>5); 00488 MMA8452_DBG(" 4 DR1: %d", (v&0x10)>>4); 00489 MMA8452_DBG(" 3 DR0: %d", (v&0x08)>>3); 00490 MMA8452_DBG(" 2 LNOISE: %d", (v&0x04)>>2); 00491 MMA8452_DBG(" 1 FREAD: %d", (v&0x02)>>1); 00492 MMA8452_DBG(" 0 ACTIVE: %d", (v&0x01)); 00493 break; 00494 00495 case MMA8452_XYZ_DATA_CFG: 00496 MMA8452_DBG("XYZ_DATA_CFG has value: 0x%x",v); 00497 MMA8452_DBG(" 7 Unused: %d", (v&0x80)>>7); 00498 MMA8452_DBG(" 6 0: %d", (v&0x40)>>6); 00499 MMA8452_DBG(" 5 0: %d", (v&0x20)>>5); 00500 MMA8452_DBG(" 4 HPF_Out: %d",(v&0x10)>>4); 00501 MMA8452_DBG(" 3 0: %d", (v&0x08)>>3); 00502 MMA8452_DBG(" 2 0: %d", (v&0x04)>>2); 00503 MMA8452_DBG(" 1 FS1: %d", (v&0x02)>>1); 00504 MMA8452_DBG(" 0 FS0: %d", (v&0x01)); 00505 switch(v&0x03) { 00506 case 0: 00507 MMA8452_DBG("Dynamic range: 2G"); 00508 break; 00509 case 1: 00510 MMA8452_DBG("Dynamic range: 4G"); 00511 break; 00512 case 2: 00513 MMA8452_DBG("Dynamic range: 8G"); 00514 break; 00515 default: 00516 MMA8452_DBG("Unknown dynamic range"); 00517 break; 00518 } 00519 break; 00520 00521 case MMA8452_STATUS: 00522 MMA8452_DBG("STATUS has value: 0x%x",v); 00523 MMA8452_DBG(" 7 ZYXOW: %d",(v&0x80)>>7); 00524 MMA8452_DBG(" 6 ZOW: %d", (v&0x40)>>6); 00525 MMA8452_DBG(" 5 YOW: %d", (v&0x20)>>5); 00526 MMA8452_DBG(" 4 XOW: %d", (v&0x10)>>4); 00527 MMA8452_DBG(" 3 ZYXDR: %d",(v&0x08)>>3); 00528 MMA8452_DBG(" 2 ZDR: %d", (v&0x04)>>2); 00529 MMA8452_DBG(" 1 YDR: %d", (v&0x02)>>1); 00530 MMA8452_DBG(" 0 XDR: %d", (v&0x01)); 00531 break; 00532 00533 default: 00534 MMA8452_DBG("Unknown register address: 0x%x",reg); 00535 break; 00536 } 00537 } 00538 #endif
Generated on Tue Jul 12 2022 11:35:54 by
1.7.2