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 03:58:53 2013 +0000
Revision:
5:c43505b5bc31
Parent:
3:db7126dbd63f
Child:
6:2b68086a26ff
1st working version

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