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