Extended driver to be able to configure the accelerometer for tap detection, orientation detection, and data ready interrupts.

Dependents:   FRDM-KL25Z_secret_knock bluetooth_robo01 robo_01

Fork of MMA8451Q by Emilio Monti

Committer:
maclobdell
Date:
Fri Mar 15 18:49:32 2013 +0000
Revision:
8:018aea85c0db
Parent:
7:e71c4d6398ea
updated header information

Who changed what in which revision?

UserRevisionLine numberNew contents of line
samux 1:d2630136d51e 1 /* Copyright (c) 2010-2011 mbed.org, MIT License
samux 1:d2630136d51e 2 *
samux 1:d2630136d51e 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
samux 1:d2630136d51e 4 * and associated documentation files (the "Software"), to deal in the Software without
samux 1:d2630136d51e 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
samux 1:d2630136d51e 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
samux 1:d2630136d51e 7 * Software is furnished to do so, subject to the following conditions:
samux 1:d2630136d51e 8 *
samux 1:d2630136d51e 9 * The above copyright notice and this permission notice shall be included in all copies or
samux 1:d2630136d51e 10 * substantial portions of the Software.
samux 1:d2630136d51e 11 *
samux 1:d2630136d51e 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
samux 1:d2630136d51e 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
samux 1:d2630136d51e 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
samux 1:d2630136d51e 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
samux 1:d2630136d51e 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
samux 1:d2630136d51e 17 */
samux 1:d2630136d51e 18
maclobdell 8:018aea85c0db 19 /* Driver extended by Mac Lobdell */
maclobdell 8:018aea85c0db 20 /* Added tap detection, orientation, and data ready interrupt capability */
maclobdell 8:018aea85c0db 21 /* Added capability to check interrupt source, tap type, and orientation */
maclobdell 8:018aea85c0db 22 /* See MMA8451Q.h for configuration to enable/disable different features */
maclobdell 7:e71c4d6398ea 23 /* Several bits and pieces taken from MMA8452Q basic example code by Nathan Seidle at SparkFun under Beerware license */
maclobdell 7:e71c4d6398ea 24
emilmont 0:6149091f755d 25 #include "MMA8451Q.h"
emilmont 0:6149091f755d 26
samux 1:d2630136d51e 27 #define REG_WHO_AM_I 0x0D
samux 1:d2630136d51e 28 #define REG_CTRL_REG_1 0x2A
emilmont 0:6149091f755d 29 #define REG_OUT_X_MSB 0x01
emilmont 0:6149091f755d 30 #define REG_OUT_Y_MSB 0x03
emilmont 0:6149091f755d 31 #define REG_OUT_Z_MSB 0x05
emilmont 0:6149091f755d 32
samux 1:d2630136d51e 33 #define UINT14_MAX 16383
emilmont 0:6149091f755d 34
maclobdell 5:c43505b5bc31 35 // Set the scale below either 2, 4 or 8
maclobdell 5:c43505b5bc31 36 #define SCALE 2; // Sets full-scale range to +/-2, 4, or 8g. Used to calc real g values.
maclobdell 5:c43505b5bc31 37 // Set the output data rate below. Value should be between 0 and 7
maclobdell 5:c43505b5bc31 38 #define DATARATE = 0; // 0=800Hz, 1=400, 2=200, 3=100, 4=50, 5=12.5, 6=6.25, 7=1.56
maclobdell 5:c43505b5bc31 39
maclobdell 5:c43505b5bc31 40 extern Serial pc;
maclobdell 5:c43505b5bc31 41
maclobdell 5:c43505b5bc31 42 MMA8451Q::MMA8451Q(PinName sda, PinName scl, int addr) : m_i2c(sda, scl), m_addr(addr)
maclobdell 5:c43505b5bc31 43 {
maclobdell 6:2b68086a26ff 44 //To-do: need to clear registers before writing because they only get cleared on a power cycle
maclobdell 5:c43505b5bc31 45
maclobdell 5:c43505b5bc31 46 modeStandby(); // Must be in standby to change registers
maclobdell 5:c43505b5bc31 47
maclobdell 5:c43505b5bc31 48 /* pc.printf("++++++++++++++++++\n\r");
maclobdell 5:c43505b5bc31 49 uint8_t myRegs = 0;
maclobdell 5:c43505b5bc31 50 for(uint8_t i = 0; i<0x31;i++)
maclobdell 5:c43505b5bc31 51 {
maclobdell 5:c43505b5bc31 52 myRegs = readRegister(i);
maclobdell 5:c43505b5bc31 53 pc.printf("%x: %x\n\r",i,myRegs);
maclobdell 5:c43505b5bc31 54 }
maclobdell 5:c43505b5bc31 55 pc.printf("+==+==+==++===+=+\n\r");
maclobdell 5:c43505b5bc31 56 */
maclobdell 5:c43505b5bc31 57
maclobdell 5:c43505b5bc31 58 // Set up the full scale range to 2, 4, or 8g.
maclobdell 5:c43505b5bc31 59 //if ((fsr==2)||(fsr==4)||(fsr==8))
maclobdell 5:c43505b5bc31 60 writeRegister(0x0E, 0); //SCALE >> 2);
maclobdell 5:c43505b5bc31 61 //else
maclobdell 5:c43505b5bc31 62 // writeRegister(0x0E, 0);
maclobdell 5:c43505b5bc31 63
maclobdell 5:c43505b5bc31 64 // Setup the 3 data rate bits, from 0 to 7
maclobdell 5:c43505b5bc31 65 writeRegister(0x2A, readRegister(0x2A) & ~(0x38));
maclobdell 5:c43505b5bc31 66 //if (DATARATE <= 7)
maclobdell 5:c43505b5bc31 67 // writeRegister(0x2A, readRegister(0x2A) | (DATARATE << 3));
maclobdell 5:c43505b5bc31 68
maclobdell 5:c43505b5bc31 69 // Set up portrait/landscap registers - 4 steps:
maclobdell 5:c43505b5bc31 70 // 1. Enable P/L
maclobdell 5:c43505b5bc31 71 // 2. Set the back/front angle trigger points (z-lock)
maclobdell 5:c43505b5bc31 72 // 3. Set the threshold/hysteresis angle
maclobdell 5:c43505b5bc31 73 // 4. Set the debouce rate
maclobdell 5:c43505b5bc31 74 // For more info check out this app note: http://cache.freescale.com/files/sensors/doc/app_note/AN4068.pdf
maclobdell 5:c43505b5bc31 75 if(MMA8451Q_ENABLE_ORIENTATION)
maclobdell 5:c43505b5bc31 76 {
maclobdell 5:c43505b5bc31 77 pc.printf("setting orientation configuraiton \n\r");
maclobdell 5:c43505b5bc31 78
maclobdell 5:c43505b5bc31 79 writeRegister(0x11, 0x40); // 1. Enable P/L
maclobdell 5:c43505b5bc31 80 writeRegister(0x13, 0x44); // 2. 29deg z-lock (don't think this register is actually writable)
maclobdell 5:c43505b5bc31 81 writeRegister(0x14, 0x84); // 3. 45deg thresh, 14deg hyst (don't think this register is writable either)
maclobdell 5:c43505b5bc31 82 writeRegister(0x12, 0x50); // 4. debounce counter at 100ms (at 800 hz)
maclobdell 5:c43505b5bc31 83 }
maclobdell 5:c43505b5bc31 84
maclobdell 5:c43505b5bc31 85 /* Set up single and double tap - 5 steps:
maclobdell 5:c43505b5bc31 86 1. Set up single and/or double tap detection on each axis individually.
maclobdell 5:c43505b5bc31 87 2. Set the threshold - minimum required acceleration to cause a tap.
maclobdell 5:c43505b5bc31 88 3. Set the time limit - the maximum time that a tap can be above the threshold
maclobdell 5:c43505b5bc31 89 4. Set the pulse latency - the minimum required time between one pulse and the next
maclobdell 5:c43505b5bc31 90 5. Set the second pulse window - maximum allowed time between end of latency and start of second pulse
maclobdell 5:c43505b5bc31 91 for more info check out this app note: http://cache.freescale.com/files/sensors/doc/app_note/AN4072.pdf */
maclobdell 5:c43505b5bc31 92 if( MMA8451Q_ENABLE_DOUBLE_Z_TAP | MMA8451Q_ENABLE_SINGLE_Z_TAP)
maclobdell 5:c43505b5bc31 93 {
maclobdell 5:c43505b5bc31 94 //writeRegister(0x21, 0x7F); // 1. enable single/double taps on all axes
maclobdell 5:c43505b5bc31 95 // writeRegister(0x21, 0x55); // 1. single taps only on all axes
maclobdell 5:c43505b5bc31 96 // writeRegister(0x21, 0x6A); // 1. double taps only on all axes
maclobdell 5:c43505b5bc31 97 pc.printf("setting tap configuraiton \n\r");
maclobdell 5:c43505b5bc31 98
maclobdell 5:c43505b5bc31 99
maclobdell 5:c43505b5bc31 100 if(MMA8451Q_ENABLE_DOUBLE_Z_TAP)
maclobdell 5:c43505b5bc31 101 writeRegister(0x21, readRegister(0x21) | 0x60); // 1. enable double taps on Z axes
maclobdell 5:c43505b5bc31 102 if(MMA8451Q_ENABLE_SINGLE_Z_TAP)
maclobdell 5:c43505b5bc31 103 writeRegister(0x21, readRegister(0x21) | 0x50); // 1. enable single taps on Z axes
maclobdell 5:c43505b5bc31 104
maclobdell 5:c43505b5bc31 105
maclobdell 5:c43505b5bc31 106 /* set up the Tap threshold and timing */
maclobdell 5:c43505b5bc31 107 //not doing x,y taps
maclobdell 5:c43505b5bc31 108 // writeRegister(0x23, 0x20); // 2. x thresh at 2g, multiply the value by 0.0625g/LSB to get the threshold
maclobdell 5:c43505b5bc31 109 // writeRegister(0x24, 0x20); // 2. y thresh at 2g, multiply the value by 0.0625g/LSB to get the threshold
maclobdell 5:c43505b5bc31 110 // writeRegister(0x25, 0x08); // 2. z thresh at .5g, multiply the value by 0.0625g/LSB to get the threshold
maclobdell 5:c43505b5bc31 111 writeRegister(0x25, 0x04); // 2. z thresh at ?g, multiply the value by 0.0625g/LSB to get the threshold
maclobdell 5:c43505b5bc31 112 writeRegister(0x26, 0x30); // 3. 30ms time limit at 800Hz odr, this is very dependent on data rate, see the app note
maclobdell 5:c43505b5bc31 113 writeRegister(0x27, 0xA0); // 4. 200ms (at 800Hz odr) between taps min, this also depends on the data rate
maclobdell 5:c43505b5bc31 114 writeRegister(0x28, 0xFF); // 5. 318ms (max value) between taps max
maclobdell 5:c43505b5bc31 115 }
maclobdell 5:c43505b5bc31 116
maclobdell 5:c43505b5bc31 117 if( MMA8451Q_ENABLE_DOUBLE_Z_TAP | MMA8451Q_ENABLE_SINGLE_Z_TAP | MMA8451Q_ENABLE_DATAREADY | MMA8451Q_ENABLE_ORIENTATION)
maclobdell 5:c43505b5bc31 118 {
maclobdell 5:c43505b5bc31 119 pc.printf("setting up interrupts \n\r");
maclobdell 5:c43505b5bc31 120
maclobdell 5:c43505b5bc31 121 // Set up interrupt 1 and 2
maclobdell 5:c43505b5bc31 122
maclobdell 5:c43505b5bc31 123 // writeRegister(0x2C, 0x02); // Active high, push-pull interrupts
maclobdell 5:c43505b5bc31 124 writeRegister(0x2C, 0x01); // Active low, push-pull interrupts
maclobdell 5:c43505b5bc31 125
maclobdell 5:c43505b5bc31 126 //writeRegister(0x2D, 0x19); // DRDY, P/L and tap ints enabled
maclobdell 5:c43505b5bc31 127 // writeRegister(0x2D, 0x9); // DRDY, tap ints enabled
maclobdell 5:c43505b5bc31 128
maclobdell 5:c43505b5bc31 129 if( MMA8451Q_ENABLE_DATAREADY)
maclobdell 5:c43505b5bc31 130 {//enable data ready interrupts
maclobdell 5:c43505b5bc31 131 writeRegister(0x2D, readRegister(0x2D)| 0x1); // DRDY ints enabled
maclobdell 5:c43505b5bc31 132 }
maclobdell 5:c43505b5bc31 133 if( MMA8451Q_ENABLE_DOUBLE_Z_TAP | MMA8451Q_ENABLE_SINGLE_Z_TAP)
maclobdell 5:c43505b5bc31 134 {//enable tap interrupts
maclobdell 5:c43505b5bc31 135 writeRegister(0x2D, readRegister(0x2D)| 0x8); // taps ints enabled
maclobdell 5:c43505b5bc31 136 }
maclobdell 5:c43505b5bc31 137 if( MMA8451Q_ENABLE_ORIENTATION)
maclobdell 5:c43505b5bc31 138 {//enable orientation interrupts
maclobdell 5:c43505b5bc31 139 writeRegister(0x2D, readRegister(0x2D)| 0x10); // orientation ints enabled
maclobdell 5:c43505b5bc31 140 }
maclobdell 5:c43505b5bc31 141
maclobdell 5:c43505b5bc31 142 writeRegister(0x2E, 0x01); // DRDY on INT1, P/L and taps on INT2
maclobdell 5:c43505b5bc31 143
maclobdell 5:c43505b5bc31 144 }
maclobdell 5:c43505b5bc31 145
maclobdell 5:c43505b5bc31 146 modeActive(); // Set to active to start reading
maclobdell 5:c43505b5bc31 147
maclobdell 5:c43505b5bc31 148 /*
maclobdell 5:c43505b5bc31 149 pc.printf("Print Registers\n\r");
maclobdell 5:c43505b5bc31 150 pc.printf("---------------\n\r");
maclobdell 5:c43505b5bc31 151 myRegs = 0;
maclobdell 5:c43505b5bc31 152 for(uint8_t i = 0; i<0x31;i++)
maclobdell 5:c43505b5bc31 153 {
maclobdell 5:c43505b5bc31 154 myRegs = readRegister(i);
maclobdell 5:c43505b5bc31 155 pc.printf("%x: %x\n\r",i,myRegs);
maclobdell 5:c43505b5bc31 156 }
maclobdell 5:c43505b5bc31 157 pc.printf("================\n\r");
maclobdell 5:c43505b5bc31 158 */
maclobdell 5:c43505b5bc31 159
emilmont 0:6149091f755d 160 }
emilmont 0:6149091f755d 161
emilmont 0:6149091f755d 162 MMA8451Q::~MMA8451Q() { }
emilmont 0:6149091f755d 163
maclobdell 5:c43505b5bc31 164 uint8_t MMA8451Q::getWhoAmI()
maclobdell 5:c43505b5bc31 165 {
emilmont 0:6149091f755d 166 uint8_t who_am_i = 0;
samux 1:d2630136d51e 167 readRegs(REG_WHO_AM_I, &who_am_i, 1);
emilmont 0:6149091f755d 168 return who_am_i;
emilmont 0:6149091f755d 169 }
emilmont 0:6149091f755d 170
maclobdell 5:c43505b5bc31 171 float MMA8451Q::getAccX()
maclobdell 5:c43505b5bc31 172 {
chris 3:db7126dbd63f 173 return (float(getAccAxis(REG_OUT_X_MSB))/4096.0);
emilmont 0:6149091f755d 174 }
emilmont 0:6149091f755d 175
maclobdell 5:c43505b5bc31 176 float MMA8451Q::getAccY()
maclobdell 5:c43505b5bc31 177 {
chris 3:db7126dbd63f 178 return (float(getAccAxis(REG_OUT_Y_MSB))/4096.0);
emilmont 0:6149091f755d 179 }
emilmont 0:6149091f755d 180
maclobdell 5:c43505b5bc31 181 float MMA8451Q::getAccZ()
maclobdell 5:c43505b5bc31 182 {
chris 3:db7126dbd63f 183 return (float(getAccAxis(REG_OUT_Z_MSB))/4096.0);
emilmont 0:6149091f755d 184 }
emilmont 0:6149091f755d 185
maclobdell 5:c43505b5bc31 186 void MMA8451Q::getAccAllAxis(float * res)
maclobdell 5:c43505b5bc31 187 {
emilmont 0:6149091f755d 188 res[0] = getAccX();
emilmont 0:6149091f755d 189 res[1] = getAccY();
emilmont 0:6149091f755d 190 res[2] = getAccZ();
emilmont 0:6149091f755d 191 }
emilmont 0:6149091f755d 192
maclobdell 5:c43505b5bc31 193 int16_t MMA8451Q::getAccAxis(uint8_t addr)
maclobdell 5:c43505b5bc31 194 {
emilmont 0:6149091f755d 195 int16_t acc;
emilmont 0:6149091f755d 196 uint8_t res[2];
samux 1:d2630136d51e 197 readRegs(addr, res, 2);
emilmont 0:6149091f755d 198
emilmont 0:6149091f755d 199 acc = (res[0] << 6) | (res[1] >> 2);
emilmont 0:6149091f755d 200 if (acc > UINT14_MAX/2)
emilmont 0:6149091f755d 201 acc -= UINT14_MAX;
emilmont 0:6149091f755d 202
emilmont 0:6149091f755d 203 return acc;
emilmont 0:6149091f755d 204 }
emilmont 0:6149091f755d 205
maclobdell 5:c43505b5bc31 206 void MMA8451Q::readRegs(int addr, uint8_t * data, int len)
maclobdell 5:c43505b5bc31 207 {
emilmont 0:6149091f755d 208 char t[1] = {addr};
emilmont 0:6149091f755d 209 m_i2c.write(m_addr, t, 1, true);
emilmont 0:6149091f755d 210 m_i2c.read(m_addr, (char *)data, len);
emilmont 0:6149091f755d 211 }
emilmont 0:6149091f755d 212
maclobdell 5:c43505b5bc31 213 void MMA8451Q::writeRegs(uint8_t * data, int len)
maclobdell 5:c43505b5bc31 214 {
emilmont 0:6149091f755d 215 m_i2c.write(m_addr, (char *)data, len);
emilmont 0:6149091f755d 216 }
maclobdell 5:c43505b5bc31 217
maclobdell 5:c43505b5bc31 218 void MMA8451Q::writeRegister(uint8_t reg, uint8_t data)
maclobdell 5:c43505b5bc31 219 { //write to single register
maclobdell 5:c43505b5bc31 220 uint8_t wdata[2] = {reg, data};
maclobdell 5:c43505b5bc31 221 m_i2c.write(m_addr, (char *)wdata, 2);
maclobdell 5:c43505b5bc31 222
maclobdell 5:c43505b5bc31 223 }
maclobdell 5:c43505b5bc31 224 uint8_t MMA8451Q::readRegister(uint8_t reg)
maclobdell 5:c43505b5bc31 225 { //read single register
maclobdell 5:c43505b5bc31 226
maclobdell 5:c43505b5bc31 227 uint8_t data;
maclobdell 5:c43505b5bc31 228 readRegs(reg, &data, 1);
maclobdell 5:c43505b5bc31 229
maclobdell 5:c43505b5bc31 230 return data;
maclobdell 5:c43505b5bc31 231 }
maclobdell 5:c43505b5bc31 232
maclobdell 5:c43505b5bc31 233 // Sets the MMA8452 to standby mode.
maclobdell 5:c43505b5bc31 234 // It must be in standby to change most register settings
maclobdell 5:c43505b5bc31 235 void MMA8451Q::modeStandby(void)
maclobdell 5:c43505b5bc31 236 {
maclobdell 5:c43505b5bc31 237 uint8_t c = readRegister(0x2A);
maclobdell 5:c43505b5bc31 238 writeRegister(0x2A, c & ~(0x01));
maclobdell 5:c43505b5bc31 239 }
maclobdell 5:c43505b5bc31 240
maclobdell 5:c43505b5bc31 241 // Sets the MMA8452 to active mode.
maclobdell 5:c43505b5bc31 242 // Needs to be in this mode to output data
maclobdell 5:c43505b5bc31 243 void MMA8451Q::modeActive(void)
maclobdell 5:c43505b5bc31 244 {
maclobdell 5:c43505b5bc31 245 int8_t c = readRegister(0x2A);
maclobdell 5:c43505b5bc31 246 writeRegister(0x2A, c | 0x01);
maclobdell 5:c43505b5bc31 247 }
maclobdell 5:c43505b5bc31 248
maclobdell 5:c43505b5bc31 249 uint8_t MMA8451Q::direction(void)
maclobdell 5:c43505b5bc31 250 {
maclobdell 5:c43505b5bc31 251 uint8_t pl = readRegister(0x10); // Reads the PL_STATUS register
maclobdell 5:c43505b5bc31 252 return pl;
maclobdell 5:c43505b5bc31 253
maclobdell 5:c43505b5bc31 254 }
maclobdell 5:c43505b5bc31 255 uint8_t MMA8451Q::tapSource(void)
maclobdell 5:c43505b5bc31 256 {
maclobdell 5:c43505b5bc31 257 uint8_t source = readRegister(0x22); // Reads the PULSE_SRC register
maclobdell 5:c43505b5bc31 258 return source;
maclobdell 5:c43505b5bc31 259 }
maclobdell 5:c43505b5bc31 260 uint8_t MMA8451Q::intSource(void)
maclobdell 5:c43505b5bc31 261 {
maclobdell 5:c43505b5bc31 262 uint8_t source = readRegister(0x0C); // Read the interrupt source reg.
maclobdell 5:c43505b5bc31 263 return source;
maclobdell 5:c43505b5bc31 264 }