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:
Wed Feb 27 04:13:31 2013 +0000
Revision:
7:e71c4d6398ea
Parent:
6:2b68086a26ff
Child:
8:018aea85c0db
update to license notes

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