Mateusz Grzywacz / MMA845x

Fork of MMA845x by Multi-Hackers

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MMA845x.cpp Source File

MMA845x.cpp

Go to the documentation of this file.
00001 /**
00002  * @file    MMA845x.cpp
00003  * @brief   Device driver - MMA845X 3-axis accelerometer IC W/RTOS support
00004  * @author  Tim Barr
00005  * @version 1.0
00006  * @see     http://cache.freescale.com/files/sensors/doc/data_sheet/MMA8451Q.pdf
00007  * @see     http://cache.freescale.com/files/sensors/doc/data_sheet/MMA8452Q.pdf
00008  * @see     http://cache.freescale.com/files/sensors/doc/data_sheet/MMA8453Q.pdf
00009  *
00010  * Copyright (c) 2015
00011  *
00012  * Licensed under the Apache License, Version 2.0 (the "License");
00013  * you may not use this file except in compliance with the License.
00014  * You may obtain a copy of the License at
00015  *
00016  *     http://www.apache.org/licenses/LICENSE-2.0
00017  *
00018  * Unless required by applicable law or agreed to in writing, software
00019  * distributed under the License is distributed on an "AS IS" BASIS,
00020  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00021  * See the License for the specific language governing permissions and
00022  * limitations under the License.
00023  *
00024  * 5/5/2015 Forked from https://developer.mbed.org/users/sam_grove/code/MMA845x/
00025  *
00026  * 6/20/2015 TAB Added setup functions and polling data capability. Also added RTOS calls
00027  * TODO Still need to add interrupt support for other Accelerometer mode support
00028  */
00029 
00030 #include "MMA845x.h"
00031 #include "mbed_debug.h"
00032 #include "rtos.h"
00033 
00034 MMA845x::MMA845x(I2C &i2c, SA0 const i2c_addr, InterruptIn* int1, InterruptIn* int2)
00035 {
00036     _i2c =  &i2c;
00037     _int1 = int1;
00038     _int2 = int2;
00039 
00040     _i2c_addr = (0x1c | i2c_addr) << 1;
00041 
00042     MMA845x::init();
00043 
00044     return;
00045 }
00046 
00047 uint8_t MMA845x::init(void)
00048 {
00049     uint8_t result = 0;
00050     uint8_t i = 0;
00051     char reg_val[1];
00052 
00053     _who_am_i = 0x00;
00054 
00055     // Reset all registers to POR values
00056     result = MMA845x::writeRegister(CTRL_REG2, 0xFF);        //REG 0x2B
00057     if (result == 0) {
00058 
00059         do {
00060             // wait for the reset bit to clear. readRegister may error out so we re-try 10 times
00061             osDelay(200);
00062             reg_val[0] = 0x40;
00063             result = MMA845x::readRegister(CTRL_REG2,1,reg_val);
00064             reg_val[0] = reg_val[0] & 0x40;
00065             i++;
00066         } while(((reg_val[0] != 0)||( result != 0)) && (i<=10));
00067     }
00068 
00069     if (result == 0) {
00070         result = MMA845x::readRegister(WHO_AM_I,1,reg_val);
00071     }
00072 
00073     switch (reg_val[0]) {
00074         case MMA8451 :
00075         case MMA8452 :
00076         case MMA8453 :
00077             _who_am_i= reg_val[0];
00078             if ((_int1 == NULL) && (_int2 == NULL))
00079                 _polling_mode = true;
00080             else _polling_mode = false;
00081             break;
00082         default:
00083             debug ("Device not supported by this library!\n\r");
00084             result = 1;
00085     }
00086 
00087     if(result != 0) {
00088         debug("MMA845x:init failed\n\r");
00089     }
00090 
00091 
00092     return result;
00093 }
00094 
00095 uint8_t MMA845x::setCommonParameters(RANGE range, RESOLUTION resolution, LOW_NOISE lo_noise,
00096                                      DATA_RATE data_rate, OVERSAMPLE_MODE os_mode, HPF_MODE hpf_mode) const
00097 {
00098     uint8_t result = 0;
00099     char datain[1];
00100     uint8_t dataout = 0;
00101 
00102     result |= MMA845x::readRegister(SYSMOD,1,datain); // Make sure MMA845x is in Stand-By mode
00103     if ((datain[0] & 0x03) != 0 ) {
00104         debug ("MMA845x not in STAND BY mode\n\f");
00105         debug("MMA845x:setCommonParameters failed\n\r");
00106         result = 1;
00107         return result;
00108     }
00109 
00110     result |= MMA845x::readRegister(CTRL_REG1, 1, datain);
00111     dataout = (datain[0] & 0xC1) | resolution | lo_noise | data_rate; // 0b ‭0010 1010
00112     result |= MMA845x::writeRegister(CTRL_REG1, dataout);        // Set resolution, Low Noise mode, and data rate
00113 
00114     result |= MMA845x::readRegister(CTRL_REG2,1, datain);
00115     dataout = (datain[0] & 0xFC) | os_mode;
00116     result |= MMA845x::writeRegister(CTRL_REG2, dataout);        // Set Oversample mode for Active State
00117 
00118     result |= MMA845x::readRegister(XYZ_DATA_CFG,1, datain);
00119     dataout = range | hpf_mode;
00120     result |= MMA845x::writeRegister(XYZ_DATA_CFG, dataout);     //Set HPF mode and range
00121 
00122 //    result |= MMA845x::readRegister(HP_FILTER_CUTOFF,1, datain);
00123 //    result |= MMA845x::writeRegister(HP_FILTER_CUTOFF, dataout); //REG 0xF HPF settings
00124 
00125     if(result != 0) {
00126         debug("MMA845x:setParameters failed\n\r");
00127     }
00128 
00129     return result;
00130 
00131 }
00132 
00133 uint8_t MMA845x::enableMotionDetect(void) const
00134 {
00135     uint8_t result = 0;
00136     return result;
00137 }
00138 
00139 uint8_t MMA845x::enablePulseDetect(char x_threshold , char y_threshold, char z_threshold, char window, char latency, INTERRUPT_PIN pin) const
00140 {
00141     uint8_t result = 0;
00142     result |= MMA845x::writeRegister(MMA845x::PULSE_CFG, (0b01000000 | (x_threshold?0b1:0) | (y_threshold?0b100:0) | (z_threshold?0b10000:0))); // enable tap latch & single taps on every axis
00143     MMA845x::writeRegister(MMA845x::PULSE_THSX, x_threshold & 127); // some thresholds
00144     MMA845x::writeRegister(MMA845x::PULSE_THSY, y_threshold & 127);
00145     MMA845x::writeRegister(MMA845x::PULSE_THSZ, z_threshold & 127);
00146     MMA845x::writeRegister(MMA845x::PULSE_TMLT, window); // time window. unit of 5ms
00147     MMA845x::writeRegister(MMA845x::PULSE_LTCY, latency); // set latency to 300..ms ?..?
00148     MMA845x::writeRegister(MMA845x::HP_FILTER_CUTOFF, 0b00110000); // by-pass High pass filter for pulse processing // for good meausure (??)
00149 
00150     result |= configInterrupt(INT_PULSE, pin);
00151 
00152     return result;
00153 }
00154 
00155 uint8_t MMA845x::enableOrientationDetect(uint8_t debounce_steps, INTERRUPT_PIN pin) const
00156 {
00157     uint8_t result = 0;
00158     // if(_who_am_i != MMA8451) {
00159     //     debug("%s %d: Feature not compatible with the connected device.\n", __FILE__, __LINE__);
00160     //     result = 1;
00161     // }
00162     // ↑ not true. MMA8451 is the only one supporting variable trip-angle values
00163 
00164     MMA845x::writeRegister(PL_COUNT, debounce_steps);
00165     MMA845x::writeRegister(PL_CFG, 0b11000000); // enable and set debounce counter to clear out of {clear, decrement}
00166 
00167     result |= configInterrupt(INT_LNDPRT, pin);
00168 
00169     return result;
00170 }
00171 
00172 uint8_t MMA845x::enableTransientDetect(void) const
00173 {
00174     uint8_t result = 0;
00175     return result;
00176 }
00177 
00178 uint8_t MMA845x::enableAutoSleep(void) const
00179 {
00180     uint8_t result = 0;
00181     return result;
00182 }
00183 
00184 uint8_t MMA845x::enableFIFO(void) const
00185 {
00186     uint8_t result = 0;
00187 
00188     if(_who_am_i != MMA8451 ) {
00189         debug("%s %d: Feature not compatible with the connected device.\n", __FILE__, __LINE__);
00190         result = 1;
00191     }
00192 
00193     return result;
00194 }
00195 
00196 uint8_t MMA845x::configInterrupt(INTERRUPT_CFG_EN_SOURCE function, INTERRUPT_PIN pin) const
00197 {
00198     uint8_t result = 0;
00199     char datain[1];
00200     uint8_t dataout;
00201 
00202     if (pin != INT_NONE) {
00203         // enable interrupt
00204         result |= MMA845x::readRegister(CTRL_REG4, 1, datain);
00205         dataout = (datain[0] | function);
00206         result |= MMA845x::writeRegister(CTRL_REG4, dataout);
00207 
00208         //set pin for the interrupt
00209         result |= MMA845x::readRegister(CTRL_REG5, 1, datain);
00210         if (pin == 0)   dataout = (datain[0] & ~function); // clearing bit
00211         else            dataout = (datain[0] | function);  // setting bit
00212     } else {
00213         // disable interrupt
00214         result |= MMA845x::readRegister(CTRL_REG4, 1, datain);
00215         dataout = (datain[0] & ~function);
00216         result |= MMA845x::writeRegister(CTRL_REG4, dataout);
00217     }
00218     return result;
00219 }
00220 
00221 uint8_t MMA845x::activeMode(void) const
00222 {
00223     uint8_t result = 0;
00224     char datain[1];
00225     uint8_t dataout;
00226 
00227     result |= MMA845x::readRegister(CTRL_REG1,1, datain);
00228     dataout = (datain[0] & 0xFE) | 0x01 ;
00229     result |= MMA845x::writeRegister(CTRL_REG1, dataout);        // Set to active mode
00230 
00231     return result;
00232 }
00233 uint8_t MMA845x::standbyMode(void) const
00234 {
00235     uint8_t result = 0;
00236     char datain[1];
00237     uint8_t dataout;
00238 
00239     result |= MMA845x::readRegister(CTRL_REG1,1, datain);
00240     dataout = (datain[0] & 0xFE);
00241     result |= MMA845x::writeRegister(CTRL_REG1, dataout);        // Set to standby mode
00242 
00243     return result;
00244 }
00245 
00246 uint8_t MMA845x::getStatus(void) const
00247 {
00248     uint8_t result = 0;
00249     char datain[1];
00250     uint8_t dataout;
00251 
00252     result = MMA845x::readRegister(STATUS,1, datain);
00253 
00254     if (result != 0)
00255         dataout = result;
00256     else
00257         dataout = datain[0];
00258 
00259     return dataout;
00260 }
00261 
00262 int16_t MMA845x::getX(void)
00263 {
00264     char datain[2];
00265 
00266     if (_polling_mode) {
00267         MMA845x::readRegister(OUT_X_MSB,2, datain);
00268         _data._x  = ((datain[0] << 8) | datain[1]);  /* data is 14 bit signed with 2 LSB = 0 */
00269         _data._x  /= 4;        /* need to shift first to preserve sign then /4 to remove LSBs */
00270     }
00271     return _data._x ;
00272 
00273 }
00274 
00275 int16_t MMA845x::getY(void)
00276 {
00277     char datain[2];
00278 
00279     if (_polling_mode) {
00280         MMA845x::readRegister(OUT_Y_MSB,2, datain);
00281         _data._y  = ((datain[0] << 8) | datain[1]);   /* data is 14 bit signed with 2 LSB = 0 */
00282         _data._y  /= 4;        /* need to shift first to preserve sign then /4 to remove LSBs */
00283     }
00284     return _data._y ;
00285 }
00286 
00287 int16_t MMA845x::getZ(void)
00288 {
00289     char datain[2];
00290 
00291     if (_polling_mode) {
00292         MMA845x::readRegister(OUT_Z_MSB,2, datain);
00293         _data._z  = ((datain[0] << 8) | datain[1]);   /* data is 14 bit signed with 2 LSB = 0 */
00294         _data._z  /= 4;        /* need to shift first to preserve sign then /4 to remove LSBs */
00295     }
00296 
00297     return _data._z ;
00298 }
00299 
00300 MMA845x_DATA MMA845x::getXYZ(void)
00301 {
00302     char datain[6];
00303 
00304     if (_polling_mode) {
00305         MMA845x::readRegister(OUT_X_MSB,6, datain);   /* data is 14 bit signed with 2 LSB = 0 */
00306         _data._x  = ((datain[0] << 8) | datain[1]);    /* need to shift first to preserve sign */
00307         _data._x  /= 4;                                /* then /4 to remove LSBs */
00308         _data._y  = ((datain[2] << 8) | datain[3]);
00309         _data._y  /= 4;
00310         _data._z  = ((datain[4] << 8) | datain[5]);
00311         _data._z  /= 4;
00312     }
00313 
00314     return _data;
00315 }
00316 
00317 char MMA845x::getWhoAmI(void) const
00318 {
00319     return _who_am_i;
00320 }
00321 
00322 uint8_t MMA845x::writeRegister(uint8_t const reg, uint8_t const data) const
00323 {
00324     char buf[2] = {reg, data};
00325     uint8_t result = 0;
00326 
00327     buf[0] = reg;
00328     buf[1] = data;
00329 
00330     result |= _i2c->write(_i2c_addr, buf, 2);
00331 
00332     if (result != 0) {
00333         debug("MMA845x::writeRegister failed r-%d\n\r",result);
00334     }
00335 
00336     return result;
00337 }
00338 
00339 uint8_t MMA845x::readRegister(uint8_t const reg, uint8_t count, char* data) const
00340 {
00341     uint8_t result = 0;
00342     char reg_out[1];
00343 
00344     reg_out[0] = reg;
00345     _i2c->lock();
00346 
00347     // MMA8451Q expects a repeated start from the master
00348     result |= _i2c->write(_i2c_addr,reg_out,1,true);
00349 
00350     if (result != 0) {
00351         debug("MMA845x::readRegister failed write r- %d\n\r", result);
00352         goto exit;
00353     }
00354 
00355     result |= _i2c->read(_i2c_addr,data,count,false);
00356 
00357     if (result != 0) {
00358         debug("MMA845x::readRegister failed read r-%d\n\r",result);
00359     }
00360 
00361 exit:
00362     _i2c->unlock();
00363     return result;
00364 }