An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.
Dependencies: mbed FastIO FastPWM USBDevice
Fork of Pinscape_Controller by
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_F_STATUS 0x00 00022 #define REG_F_SETUP 0x09 00023 #define REG_WHO_AM_I 0x0D 00024 #define REG_CTRL_REG1 0x2A 00025 #define REG_CTRL_REG2 0x2B 00026 #define REG_CTRL_REG3 0x2c 00027 #define REG_CTRL_REG4 0x2D 00028 #define REG_CTRL_REG5 0x2E 00029 #define REG_OFF_X 0x2F 00030 #define REG_OFF_Y 0x30 00031 #define REG_OFF_Z 0x31 00032 #define XYZ_DATA_CFG_REG 0x0E 00033 #define REG_OUT_X_MSB 0x01 00034 #define REG_OUT_Y_MSB 0x03 00035 #define REG_OUT_Z_MSB 0x05 00036 00037 #define UINT14_MAX 16383 00038 00039 #define CTL_ACTIVE 0x01 00040 #define FS_MASK 0x03 00041 #define FS_2G 0x00 00042 #define FS_4G 0x01 00043 #define FS_8G 0x02 00044 00045 #define F_STATUS_XDR_MASK 0x01 // F_STATUS - X sample ready 00046 #define F_STATUS_YDR_MASK 0x02 // F_STATUS - Y sample ready 00047 #define F_STATUS_ZDR_MASK 0x04 // F_STATUS - Z sample ready 00048 #define F_STATUS_XYZDR_MASK 0x08 // F_STATUS - XYZ sample ready 00049 #define F_STATUS_CNT_MASK 0x3F // F_STATUS register mask for FIFO count 00050 00051 #define F_MODE_MASK 0xC0 // F_SETUP register mask for FIFO mode 00052 #define F_WMRK_MASK 0x3F // F_SETUP register mask for FIFO watermark 00053 00054 #define F_MODE_DISABLED 0x00 // FIFO disabled 00055 #define F_MODE_CIRC 0x40 // circular FIFO 00056 #define F_MODE_STOP 0x80 // FIFO stops when full 00057 #define F_MODE_TRIGGER 0xC0 // FIFO triggers interrupt when watermark reached 00058 00059 #define HPF_OUT_MASK 0x10 00060 00061 #define SMODS_MASK 0x18 00062 00063 #define MODS_MASK 0x03 00064 #define MODS_NORMAL 0x00 // mode 00 = normal power mode 00065 #define MODS_LOW_NOISE 0x01 // mode 01 = low noise, low power 00066 #define MODS_HI_RES 0x02 // mode 10 = high resolution 00067 #define MODS_LOW_POWER 0x03 // mode 11 = low power 00068 00069 #define DR_MASK 0x38 00070 #define DR_800_HZ 0x00 00071 #define DR_400_HZ 0x08 00072 #define DR_200_HZ 0x10 00073 #define DR_100_HZ 0x18 00074 #define DR_50_HZ 0x20 00075 #define DR_12_HZ 0x28 00076 #define DR_6_HZ 0x30 00077 #define DR_1_HZ 0x38 00078 00079 #define F_READ_MASK 0x02 // CTRL_REG1 F_READ bit - sets data size mode: 00080 // 1=fast read, 8-bit data; 0=14-bit data 00081 00082 #define CTRL_REG3_IPOL_MASK 0x02 00083 #define CTRL_REG3_PPOD_MASK 0x01 00084 00085 #define INT_EN_DRDY 0x01 00086 #define INT_CFG_DRDY 0x01 00087 00088 00089 MMA8451Q::MMA8451Q(PinName sda, PinName scl, int addr) : m_i2c(sda, scl), m_addr(addr) 00090 { 00091 // set the I2C to fast mode 00092 m_i2c.frequency(400000); 00093 00094 // initialize parameters 00095 init(); 00096 } 00097 00098 // reset the accelerometer and set our parameters 00099 void MMA8451Q::init() 00100 { 00101 // reset all registers to power-on reset values 00102 uint8_t d0[2] = { REG_CTRL_REG2, 0x40 }; 00103 writeRegs(d0,2 ); 00104 00105 // wait for the reset bit to clear 00106 do { 00107 readRegs(REG_CTRL_REG2, d0, 1); 00108 } while ((d0[0] & 0x40) != 0); 00109 00110 // go to standby mode 00111 standby(); 00112 00113 // turn off FIFO mode - this is required before changing the F_READ bit 00114 readRegs(REG_F_SETUP, d0, 1); 00115 uint8_t d0a[2] = { REG_F_SETUP, 0 }; 00116 writeRegs(d0a, 2); 00117 00118 // read the curent config register 00119 uint8_t d1[1]; 00120 readRegs(XYZ_DATA_CFG_REG, d1, 1); 00121 00122 // set 2g mode by default 00123 uint8_t d2[2] = { XYZ_DATA_CFG_REG, (d1[0] & ~FS_MASK) | FS_2G }; 00124 writeRegs(d2, 2); 00125 00126 // read the ctl2 register 00127 uint8_t d3[1]; 00128 readRegs(REG_CTRL_REG2, d3, 1); 00129 00130 // set the high resolution mode 00131 uint8_t d4[2] = {REG_CTRL_REG2, (d3[0] & ~MODS_MASK) | MODS_HI_RES}; 00132 writeRegs(d4, 2); 00133 00134 // set 800 Hz mode, 14-bit data (clear the F_READ bit) 00135 uint8_t d5[1]; 00136 readRegs(REG_CTRL_REG1, d5, 1); 00137 uint8_t d6[2] = {REG_CTRL_REG1, (d5[0] & ~(DR_MASK | F_READ_MASK)) | DR_800_HZ}; 00138 writeRegs(d6, 2); 00139 00140 // set circular FIFO mode 00141 uint8_t d7[1]; 00142 readRegs(REG_F_SETUP, d7, 1); 00143 uint8_t d8[2] = {REG_F_SETUP, (d7[0] & ~F_MODE_MASK) | F_MODE_CIRC}; 00144 writeRegs(d8, 2); 00145 00146 // enter active mode 00147 active(); 00148 } 00149 00150 MMA8451Q::~MMA8451Q() { } 00151 00152 bool MMA8451Q::sampleReady() 00153 { 00154 uint8_t d[1]; 00155 readRegs(REG_F_STATUS, d, 1); 00156 return (d[0] & F_STATUS_XYZDR_MASK) == F_STATUS_XYZDR_MASK; 00157 } 00158 00159 int MMA8451Q::getFIFOCount() 00160 { 00161 uint8_t d[1]; 00162 readRegs(REG_F_STATUS, d, 1); 00163 return d[0] & F_STATUS_CNT_MASK; 00164 } 00165 00166 void MMA8451Q::setInterruptMode(int pin) 00167 { 00168 // go to standby mode 00169 standby(); 00170 00171 // set IRQ push/pull and active high 00172 uint8_t d1[1]; 00173 readRegs(REG_CTRL_REG3, d1, 1); 00174 uint8_t d2[2] = { 00175 REG_CTRL_REG3, 00176 (d1[0] & ~CTRL_REG3_PPOD_MASK) | CTRL_REG3_IPOL_MASK 00177 }; 00178 writeRegs(d2, 2); 00179 00180 // set pin 2 or pin 1 00181 readRegs(REG_CTRL_REG5, d1, 1); 00182 uint8_t d3[2] = { 00183 REG_CTRL_REG5, 00184 (d1[0] & ~INT_CFG_DRDY) | (pin == 1 ? INT_CFG_DRDY : 0) 00185 }; 00186 writeRegs(d3, 2); 00187 00188 // enable data ready interrupt 00189 readRegs(REG_CTRL_REG4, d1, 1); 00190 uint8_t d4[2] = { REG_CTRL_REG4, d1[0] | INT_EN_DRDY }; 00191 writeRegs(d4, 2); 00192 00193 // enter active mode 00194 active(); 00195 } 00196 00197 void MMA8451Q::clearInterruptMode() 00198 { 00199 // go to standby mode 00200 standby(); 00201 00202 // clear the interrupt register 00203 uint8_t d1[2] = { REG_CTRL_REG4, 0 }; 00204 writeRegs(d1, 2); 00205 00206 // enter active mode 00207 active(); 00208 } 00209 00210 void MMA8451Q::setRange(int g) 00211 { 00212 // go to standby mode 00213 standby(); 00214 00215 // read the curent config register 00216 uint8_t d1[1]; 00217 readRegs(XYZ_DATA_CFG_REG, d1, 1); 00218 00219 // figure the mode flag for the desired G setting 00220 uint8_t mode = (g == 8 ? FS_8G : g == 4 ? FS_4G : FS_2G); 00221 00222 // set new mode 00223 uint8_t d2[2] = { XYZ_DATA_CFG_REG, (d1[0] & ~FS_MASK) | mode }; 00224 writeRegs(d2, 2); 00225 00226 // enter active mode 00227 active(); 00228 } 00229 00230 void MMA8451Q::standby() 00231 { 00232 // read the current control register 00233 uint8_t d1[1]; 00234 readRegs(REG_CTRL_REG1, d1, 1); 00235 00236 // wait for standby mode 00237 do { 00238 // write it back with the Active bit cleared 00239 uint8_t d2[2] = { REG_CTRL_REG1, d1[0] & ~CTL_ACTIVE }; 00240 writeRegs(d2, 2); 00241 00242 readRegs(REG_CTRL_REG1, d1, 1); 00243 } while (d1[0] & CTL_ACTIVE); 00244 } 00245 00246 void MMA8451Q::active() 00247 { 00248 // read the current control register 00249 uint8_t d1[1]; 00250 readRegs(REG_CTRL_REG1, d1, 1); 00251 00252 // write it back out with the Active bit set 00253 uint8_t d2[2] = { REG_CTRL_REG1, d1[0] | CTL_ACTIVE }; 00254 writeRegs(d2, 2); 00255 } 00256 00257 uint8_t MMA8451Q::getWhoAmI() { 00258 uint8_t who_am_i = 0; 00259 readRegs(REG_WHO_AM_I, &who_am_i, 1); 00260 return who_am_i; 00261 } 00262 00263 float MMA8451Q::getAccX() { 00264 return (float(getAccAxis(REG_OUT_X_MSB))/4096.0); 00265 } 00266 00267 void MMA8451Q::getAccXY(float &x, float &y) 00268 { 00269 // read the X and Y output registers 00270 uint8_t res[4]; 00271 readRegs(REG_OUT_X_MSB, res, 4); 00272 00273 // translate the x value 00274 uint16_t acc = (res[0] << 8) | (res[1]); 00275 x = int16_t(acc)/(4*4096.0); 00276 00277 // translate the y value 00278 acc = (res[2] << 9) | (res[3]); 00279 y = int16_t(acc)/(4*4096.0); 00280 } 00281 00282 void MMA8451Q::getAccXYZ(float &x, float &y, float &z) 00283 { 00284 // read the X, Y, and Z output registers 00285 uint8_t res[6]; 00286 readRegs(REG_OUT_X_MSB, res, 6); 00287 00288 // translate the x value 00289 uint16_t acc = (res[0] << 8) | (res[1]); 00290 x = int16_t(acc)/(4*4096.0); 00291 00292 // translate the y value 00293 acc = (res[2] << 8) | (res[3]); 00294 y = int16_t(acc)/(4*4096.0); 00295 00296 // translate the z value 00297 acc = (res[4] << 8) | (res[5]); 00298 z = int16_t(acc)/(4*4096.0); 00299 } 00300 00301 void MMA8451Q::getAccXYZ(int &x, int &y, int &z) 00302 { 00303 // read the X, Y, and Z output registers 00304 uint8_t res[6]; 00305 readRegs(REG_OUT_X_MSB, res, 6); 00306 00307 // translate the register values 00308 x = xlat14(&res[0]); 00309 y = xlat14(&res[2]); 00310 z = xlat14(&res[4]); 00311 } 00312 00313 float MMA8451Q::getAccY() { 00314 return (float(getAccAxis(REG_OUT_Y_MSB))/4096.0); 00315 } 00316 00317 float MMA8451Q::getAccZ() { 00318 return (float(getAccAxis(REG_OUT_Z_MSB))/4096.0); 00319 } 00320 00321 void MMA8451Q::getAccAllAxis(float * res) { 00322 res[0] = getAccX(); 00323 res[1] = getAccY(); 00324 res[2] = getAccZ(); 00325 } 00326 00327 int16_t MMA8451Q::getAccAxis(uint8_t addr) { 00328 int16_t acc; 00329 uint8_t res[2]; 00330 readRegs(addr, res, 2); 00331 00332 acc = (res[0] << 6) | (res[1] >> 2); 00333 if (acc > UINT14_MAX/2) 00334 acc -= UINT14_MAX; 00335 00336 return acc; 00337 } 00338 00339 void MMA8451Q::readRegs(int addr, uint8_t * data, int len) { 00340 char t[1] = {addr}; 00341 m_i2c.write(m_addr, t, 1, true); 00342 m_i2c.read(m_addr, (char *)data, len); 00343 } 00344 00345 void MMA8451Q::writeRegs(uint8_t * data, int len) { 00346 m_i2c.write(m_addr, (char *)data, len); 00347 }
Generated on Wed Jul 13 2022 03:30:11 by 1.7.2