An input/output controller for virtual pinball machines, with plunger position tracking, accelerometer-based nudge sensing, button input encoding, and feedback device control.

Dependencies:   USBDevice mbed FastAnalogIn FastIO FastPWM SimpleDMA

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MMA8451Q.cpp Source File

MMA8451Q.cpp

00001 /* Copyright (c) 2010-2011 mbed.org, MIT License
00002 *
00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004 * and associated documentation files (the "Software"), to deal in the Software without
00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
00007 * Software is furnished to do so, subject to the following conditions:
00008 *
00009 * The above copyright notice and this permission notice shall be included in all copies or
00010 * substantial portions of the Software.
00011 *
00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017 */
00018 
00019 #include "MMA8451Q.h"
00020 
00021 #define REG_WHO_AM_I      0x0D
00022 #define REG_CTRL_REG_1    0x2A
00023 #define REG_CTRL_REG_2    0x2B
00024 #define REG_CTRL_REG_3    0x2c
00025 #define REG_CTRL_REG_4    0x2D
00026 #define REG_CTRL_REG_5    0x2E
00027 #define REG_OFF_X         0x2F
00028 #define REG_OFF_Y         0x30
00029 #define REG_OFF_Z         0x31
00030 #define XYZ_DATA_CFG_REG  0x0E
00031 #define REG_OUT_X_MSB     0x01
00032 #define REG_OUT_Y_MSB     0x03
00033 #define REG_OUT_Z_MSB     0x05
00034 
00035 #define UINT14_MAX        16383
00036 
00037 #define CTL_ACTIVE        0x01
00038 #define FS_MASK           0x03
00039 #define FS_2G             0x00
00040 #define FS_4G             0x01
00041 #define FS_8G             0x02
00042 
00043 #define HPF_OUT_MASK      0x10
00044 
00045 #define MODS1_MASK        0x02
00046 #define MODS0_MASK        0x01
00047 #define SMODS_MASK        0x18
00048 #define MODS_MASK         0x03
00049 
00050 #define DR_MASK           0x38
00051 #define DR_800_HZ         0x00
00052 #define DR_400_HZ         0x08
00053 #define DR_200_HZ         0x10
00054 #define DR_100_HZ         0x18
00055 #define DR_50_HZ          0x20
00056 #define DR_12_HZ          0x28
00057 #define DR_6_HZ           0x30
00058 #define DR_1_HZ           0x38
00059 
00060 #define CTRL_REG3_IPOL_MASK  0x02
00061 #define CTRL_REG3_PPOD_MASK  0x01
00062 
00063 #define INT_EN_DRDY       0x01
00064 #define INT_CFG_DRDY      0x01
00065 
00066 
00067 MMA8451Q::MMA8451Q(PinName sda, PinName scl, int addr) : m_i2c(sda, scl), m_addr(addr) 
00068 {
00069     // initialize parameters
00070     init();
00071 }
00072 
00073 // reset the accelerometer and set our parameters
00074 void MMA8451Q::init()
00075 {    
00076     // reset all registers to power-on reset values
00077     uint8_t d0[2] = { REG_CTRL_REG_2, 0x40 };
00078     writeRegs(d0,2 );
00079     
00080     // wait for the reset bit to clear
00081     do {
00082         readRegs(REG_CTRL_REG_2, d0, 1);
00083     } while ((d0[0] & 0x40) != 0);
00084     
00085     // go to standby mode
00086     standby();
00087     
00088     // read the curent config register
00089     uint8_t d1[1];
00090     readRegs(XYZ_DATA_CFG_REG, d1, 1);
00091     
00092     // set 2g mode
00093     uint8_t d2[2] = { XYZ_DATA_CFG_REG, (d1[0] & ~FS_MASK) | FS_2G };
00094     writeRegs(d2, 2);
00095     
00096     // read the ctl2 register
00097     uint8_t d3[1];
00098     readRegs(REG_CTRL_REG_2, d3, 1);
00099     
00100     // set the high resolution mode
00101     uint8_t d4[2] = {REG_CTRL_REG_2, (d3[0] & ~MODS_MASK) | MODS1_MASK};
00102     writeRegs(d4, 2);
00103     
00104     // set 800 Hz mode
00105     uint8_t d5[1];
00106     readRegs(REG_CTRL_REG_1, d5, 1);
00107     uint8_t d6[2] = {REG_CTRL_REG_1, (d5[0] & ~DR_MASK) | DR_800_HZ};
00108     writeRegs(d6, 2);
00109     
00110     // enter active mode
00111     active();
00112 }
00113 
00114 MMA8451Q::~MMA8451Q() { }
00115 
00116 void MMA8451Q::setInterruptMode(int pin)
00117 {
00118     // go to standby mode
00119     standby();
00120 
00121     // set IRQ push/pull and active high
00122     uint8_t d1[1];
00123     readRegs(REG_CTRL_REG_3, d1, 1);
00124     uint8_t d2[2] = {
00125         REG_CTRL_REG_3, 
00126         (d1[0] & ~CTRL_REG3_PPOD_MASK) | CTRL_REG3_IPOL_MASK
00127     };
00128     writeRegs(d2, 2);
00129     
00130     // set pin 2 or pin 1
00131     readRegs(REG_CTRL_REG_5, d1, 1);
00132     uint8_t d3[2] = { 
00133         REG_CTRL_REG_5, 
00134         (d1[0] & ~INT_CFG_DRDY) | (pin == 1 ? INT_CFG_DRDY : 0)
00135     };
00136     writeRegs(d3, 2);
00137     
00138     // enable data ready interrupt
00139     readRegs(REG_CTRL_REG_4, d1, 1);
00140     uint8_t d4[2] = { REG_CTRL_REG_4, d1[0] | INT_EN_DRDY };
00141     writeRegs(d4, 2);
00142     
00143     // enter active mode
00144     active();
00145 }
00146 
00147 void MMA8451Q::standby()
00148 {
00149     // read the current control register
00150     uint8_t d1[1];
00151     readRegs(REG_CTRL_REG_1, d1, 1);
00152     
00153     // wait for standby mode
00154     do {
00155         // write it back with the Active bit cleared
00156         uint8_t d2[2] = { REG_CTRL_REG_1, d1[0] & ~CTL_ACTIVE };
00157         writeRegs(d2, 2);
00158     
00159         readRegs(REG_CTRL_REG_1, d1, 1);
00160     } while (d1[0] & CTL_ACTIVE);
00161 }
00162 
00163 void MMA8451Q::active()
00164 {
00165     // read the current control register
00166     uint8_t d1[1];
00167     readRegs(REG_CTRL_REG_1, d1, 1);
00168     
00169     // write it back out with the Active bit set
00170     uint8_t d2[2] = { REG_CTRL_REG_1, d1[0] | CTL_ACTIVE };
00171     writeRegs(d2, 2);
00172 }
00173 
00174 uint8_t MMA8451Q::getWhoAmI() {
00175     uint8_t who_am_i = 0;
00176     readRegs(REG_WHO_AM_I, &who_am_i, 1);
00177     return who_am_i;
00178 }
00179 
00180 float MMA8451Q::getAccX() {
00181     return (float(getAccAxis(REG_OUT_X_MSB))/4096.0);
00182 }
00183 
00184 void MMA8451Q::getAccXY(float &x, float &y) 
00185 {
00186     // read the X and Y output registers
00187     uint8_t res[4];
00188     readRegs(REG_OUT_X_MSB, res, 4);
00189     
00190     // translate the x value
00191     uint16_t acc = (res[0] << 8) | (res[1]);
00192     x = int16_t(acc)/(4*4096.0);
00193     
00194     // translate the y value
00195     acc = (res[2] << 9) | (res[3]);
00196     y = int16_t(acc)/(4*4096.0);
00197 }
00198 
00199 void MMA8451Q::getAccXYZ(float &x, float &y, float &z)
00200 {
00201     // read the X, Y, and Z output registers
00202     uint8_t res[6];
00203     readRegs(REG_OUT_X_MSB, res, 6);
00204     
00205     // translate the x value
00206     uint16_t acc = (res[0] << 8) | (res[1]);
00207     x = int16_t(acc)/(4*4096.0);
00208     
00209     // translate the y value
00210     acc = (res[2] << 8) | (res[3]);
00211     y = int16_t(acc)/(4*4096.0);
00212     
00213     // translate the z value
00214     acc = (res[4] << 8) | (res[5]);
00215     z = int16_t(acc)/(4*4096.0);
00216 }
00217 
00218 float MMA8451Q::getAccY() {
00219     return (float(getAccAxis(REG_OUT_Y_MSB))/4096.0);
00220 }
00221 
00222 float MMA8451Q::getAccZ() {
00223     return (float(getAccAxis(REG_OUT_Z_MSB))/4096.0);
00224 }
00225 
00226 void MMA8451Q::getAccAllAxis(float * res) {
00227     res[0] = getAccX();
00228     res[1] = getAccY();
00229     res[2] = getAccZ();
00230 }
00231 
00232 int16_t MMA8451Q::getAccAxis(uint8_t addr) {
00233     int16_t acc;
00234     uint8_t res[2];
00235     readRegs(addr, res, 2);
00236 
00237     acc = (res[0] << 6) | (res[1] >> 2);
00238     if (acc > UINT14_MAX/2)
00239         acc -= UINT14_MAX;
00240 
00241     return acc;
00242 }
00243 
00244 void MMA8451Q::readRegs(int addr, uint8_t * data, int len) {
00245     char t[1] = {addr};
00246     m_i2c.write(m_addr, t, 1, true);
00247     m_i2c.read(m_addr, (char *)data, len);
00248 }
00249 
00250 void MMA8451Q::writeRegs(uint8_t * data, int len) {
00251     m_i2c.write(m_addr, (char *)data, len);
00252 }