Added code to manage Orientation, FreeFall and Motion Detection. Data is also available via IRQ.

Dependents:   Test_FRDM_MMA8451Q AccelTest FRDM-KL46-Template KL25Z_Demo ... more

Fork of MMA8451Q by Emilio Monti

Committer:
clemente
Date:
Tue May 28 04:39:42 2013 +0000
Revision:
5:695063448f2a
Parent:
3:db7126dbd63f
Child:
6:c52175d13e0a
Code for Motion and FreeFall detection.

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
clemente 5:695063448f2a 23 #define REG_CTRL_REG_4 0x2D
clemente 5:695063448f2a 24 #define REG_CTRL_REG_5 0x2E
clemente 5:695063448f2a 25 #define REG_INT_SRC 0x0C
clemente 5:695063448f2a 26 #define REG_FF_MT_CFG 0x15
clemente 5:695063448f2a 27 #define REG_FF_MT_SRC 0x16
clemente 5:695063448f2a 28 #define REG_FF_MT_THS 0x17
clemente 5:695063448f2a 29 #define REG_FF_MT_CNT 0x18
clemente 5:695063448f2a 30 //
emilmont 0:6149091f755d 31 #define REG_OUT_X_MSB 0x01
emilmont 0:6149091f755d 32 #define REG_OUT_Y_MSB 0x03
emilmont 0:6149091f755d 33 #define REG_OUT_Z_MSB 0x05
emilmont 0:6149091f755d 34
samux 1:d2630136d51e 35 #define UINT14_MAX 16383
emilmont 0:6149091f755d 36
clemente 5:695063448f2a 37 void (*fall_fptr)(void);
clemente 5:695063448f2a 38 void (*motion_fptr)(void);
clemente 5:695063448f2a 39
clemente 5:695063448f2a 40 //
clemente 5:695063448f2a 41 InterruptIn MMA8451Q_Int1( PTA14);
clemente 5:695063448f2a 42 InterruptIn MMA8451Q_Int2( PTA15);
clemente 5:695063448f2a 43
emilmont 0:6149091f755d 44 MMA8451Q::MMA8451Q(PinName sda, PinName scl, int addr) : m_i2c(sda, scl), m_addr(addr) {
emilmont 0:6149091f755d 45 // activate the peripheral
emilmont 0:6149091f755d 46 uint8_t data[2] = {REG_CTRL_REG_1, 0x01};
samux 1:d2630136d51e 47 writeRegs(data, 2);
emilmont 0:6149091f755d 48 }
emilmont 0:6149091f755d 49
clemente 5:695063448f2a 50 MMA8451Q::~MMA8451Q()
clemente 5:695063448f2a 51 {
clemente 5:695063448f2a 52 MMA8451Q_Int1.fall( NULL);
clemente 5:695063448f2a 53 MMA8451Q_Int2.fall( NULL);
clemente 5:695063448f2a 54 fall_fptr = NULL;
clemente 5:695063448f2a 55 motion_fptr = NULL;
clemente 5:695063448f2a 56 }
clemente 5:695063448f2a 57
clemente 5:695063448f2a 58 void MMA8451Q::FreFallDetection( void(*fptr)(void))
clemente 5:695063448f2a 59 {
clemente 5:695063448f2a 60 // Example Steps for Configuring Linear Freefall Detection
clemente 5:695063448f2a 61 // X AND Y AND Z < 0.2g using MFF Function, 50 Hz ODR
clemente 5:695063448f2a 62 // Step 1: Put the device in Standby Mode: Register 0x2A CTRL_REG1
clemente 5:695063448f2a 63 unsigned char data[2] = {REG_CTRL_REG_1, 0x20};
clemente 5:695063448f2a 64 writeRegs(data, 2);
clemente 5:695063448f2a 65
clemente 5:695063448f2a 66 // Step 2: Configuration Register set for Freefall Detection enabling “AND” condition, OAE = 0, Enabling X,
clemente 5:695063448f2a 67 // Y, Z and the Latch
clemente 5:695063448f2a 68 data[0] = REG_FF_MT_CFG;
clemente 5:695063448f2a 69 data[1] = 0x01;
clemente 5:695063448f2a 70 writeRegs(data, 2);
clemente 5:695063448f2a 71
clemente 5:695063448f2a 72 // Step 3: Threshold Setting Value for the resulting acceleration < 0.2g
clemente 5:695063448f2a 73 // Note: The step count is 0.063g/count
clemente 5:695063448f2a 74 // • 0.2g/0.063g = 3.17 counts //Round to 3 counts
clemente 5:695063448f2a 75 data[0] = REG_FF_MT_THS;
clemente 5:695063448f2a 76 data[1] = 0x03;
clemente 5:695063448f2a 77 writeRegs(data, 2);
clemente 5:695063448f2a 78
clemente 5:695063448f2a 79 // Step 4: Set the debounce counter to eliminate false positive readings for 50Hz sample rate with a
clemente 5:695063448f2a 80 // requirement of 120 ms timer, assuming Normal Mode.
clemente 5:695063448f2a 81 // Note: 120 ms/20 ms (steps) = 6 counts
clemente 5:695063448f2a 82 data[0] = REG_FF_MT_CNT;
clemente 5:695063448f2a 83 data[1] = 0x06;
clemente 5:695063448f2a 84 writeRegs(data, 2);
clemente 5:695063448f2a 85
clemente 5:695063448f2a 86 // Step 5: Enable Motion/Freefall Interrupt Function in the System (CTRL_REG4)
clemente 5:695063448f2a 87 data[0] = REG_CTRL_REG_4;
clemente 5:695063448f2a 88 data[1] = 0x04;
clemente 5:695063448f2a 89 writeRegs(data, 2);
clemente 5:695063448f2a 90
clemente 5:695063448f2a 91 // Step 6: Route the Motion/Freefall Interrupt Function to INT2 hardware pin (CTRL_REG5)
clemente 5:695063448f2a 92 data[0] = REG_CTRL_REG_5;
clemente 5:695063448f2a 93 data[1] = 0x00;
clemente 5:695063448f2a 94 writeRegs(data, 2);
clemente 5:695063448f2a 95
clemente 5:695063448f2a 96 // Step 7: Put the device in Active Mode, 50 Hz
clemente 5:695063448f2a 97 data[0] = REG_CTRL_REG_1;
clemente 5:695063448f2a 98 data[1] = 0x21;
clemente 5:695063448f2a 99 writeRegs(data, 2);
clemente 5:695063448f2a 100
clemente 5:695063448f2a 101 fall_fptr = fptr;
clemente 5:695063448f2a 102 MMA8451Q_Int2.fall( this, &MMA8451Q::Fall_IRQ);
clemente 5:695063448f2a 103 }
clemente 5:695063448f2a 104
clemente 5:695063448f2a 105 void MMA8451Q::Fall_IRQ( void)
clemente 5:695063448f2a 106 {
clemente 5:695063448f2a 107 unsigned char t;
clemente 5:695063448f2a 108
clemente 5:695063448f2a 109 // Determine source of the interrupt by first reading the system interrupt
clemente 5:695063448f2a 110 readRegs( REG_INT_SRC, &t, 1);
clemente 5:695063448f2a 111 //
clemente 5:695063448f2a 112 if ( (t & 0x04) == 0x04) {
clemente 5:695063448f2a 113 // Read the Motion/Freefall Function to clear the interrupt
clemente 5:695063448f2a 114 readRegs( REG_FF_MT_SRC, &t, 1);
clemente 5:695063448f2a 115 // Run the user supplied function
clemente 5:695063448f2a 116 fall_fptr();
clemente 5:695063448f2a 117 }
clemente 5:695063448f2a 118 }
clemente 5:695063448f2a 119
clemente 5:695063448f2a 120 void MMA8451Q::MotionDetection( void(*fptr)(void))
clemente 5:695063448f2a 121 {
clemente 5:695063448f2a 122
clemente 5:695063448f2a 123 // 6.1 Example Steps for Configuring Motion Detection
clemente 5:695063448f2a 124 // X or Y > 3g using MFF Function 4g, 100 Hz ODR, Normal Mode
clemente 5:695063448f2a 125 // Step 1: Put the device into Standby Mode: Register 0x2A CTRL_REG1
clemente 5:695063448f2a 126 unsigned char data[2] = {REG_CTRL_REG_1, 0x18}; // Set the device in 100 Hz ODR, Standby
clemente 5:695063448f2a 127 writeRegs(data, 2);
clemente 5:695063448f2a 128
clemente 5:695063448f2a 129
clemente 5:695063448f2a 130 // Step 2: Set Configuration Register for Motion Detection by setting the “OR” condition OAE = 1, enabling
clemente 5:695063448f2a 131 // X, Y, and the latch
clemente 5:695063448f2a 132 data[0] = REG_FF_MT_CFG;
clemente 5:695063448f2a 133 data[1] = 0xD8;
clemente 5:695063448f2a 134 writeRegs(data, 2);
clemente 5:695063448f2a 135
clemente 5:695063448f2a 136 // Step 3: Threshold Setting Value for the Motion detection of > 2g
clemente 5:695063448f2a 137 // Note: The step count is 0.063g/ count
clemente 5:695063448f2a 138 // • 2g/0.063g = 31.7; //Round up to 32
clemente 5:695063448f2a 139 data[0] = REG_FF_MT_THS;
clemente 5:695063448f2a 140 data[1] = 0x20;
clemente 5:695063448f2a 141 writeRegs(data, 2);
clemente 5:695063448f2a 142
clemente 5:695063448f2a 143 // Step 4: Set the debounce counter to eliminate false readings for 100 Hz sample rate with a requirement
clemente 5:695063448f2a 144 // of 100 ms timer.
clemente 5:695063448f2a 145 // Note: 100 ms/10 ms (steps) = 10 counts
clemente 5:695063448f2a 146 data[0] = REG_FF_MT_CNT;
clemente 5:695063448f2a 147 data[1] = 0x0A;
clemente 5:695063448f2a 148 writeRegs(data, 2);
clemente 5:695063448f2a 149
clemente 5:695063448f2a 150 // Step 5: Enable Motion/Freefall Interrupt Function in the System (CTRL_REG4)
clemente 5:695063448f2a 151 data[0] = REG_CTRL_REG_4;
clemente 5:695063448f2a 152 data[1] = 0x04;
clemente 5:695063448f2a 153 writeRegs(data, 2);
clemente 5:695063448f2a 154
clemente 5:695063448f2a 155 // Step 6: Route the Motion/Freefall Interrupt Function to INT1 hardware pin (CTRL_REG5)
clemente 5:695063448f2a 156 data[0] = REG_CTRL_REG_5;
clemente 5:695063448f2a 157 data[1] = 0x04;
clemente 5:695063448f2a 158 writeRegs(data, 2);
clemente 5:695063448f2a 159
clemente 5:695063448f2a 160 // Step 7: Put the device in Active Mode
clemente 5:695063448f2a 161 data[0] = REG_CTRL_REG_1;
clemente 5:695063448f2a 162 data[1] = 0x19;
clemente 5:695063448f2a 163 writeRegs(data, 2);
clemente 5:695063448f2a 164
clemente 5:695063448f2a 165 motion_fptr = fptr;
clemente 5:695063448f2a 166 MMA8451Q_Int1.fall( this, &MMA8451Q::Motion_IRQ);
clemente 5:695063448f2a 167
clemente 5:695063448f2a 168 }
clemente 5:695063448f2a 169
clemente 5:695063448f2a 170 void MMA8451Q::Motion_IRQ( void)
clemente 5:695063448f2a 171 {
clemente 5:695063448f2a 172 unsigned char t;
clemente 5:695063448f2a 173
clemente 5:695063448f2a 174 // Determine source of the interrupt by first reading the system interrupt
clemente 5:695063448f2a 175 readRegs( REG_INT_SRC, &t, 1);
clemente 5:695063448f2a 176 //
clemente 5:695063448f2a 177 if ( (t & 0x04) == 0x04) {
clemente 5:695063448f2a 178 // Read the Motion/Freefall Function to clear the interrupt
clemente 5:695063448f2a 179 readRegs( REG_FF_MT_SRC, &t, 1);
clemente 5:695063448f2a 180 // Run the user supplied function
clemente 5:695063448f2a 181 motion_fptr();
clemente 5:695063448f2a 182 }
clemente 5:695063448f2a 183 }
clemente 5:695063448f2a 184
clemente 5:695063448f2a 185 void MMA8451Q::Active( void)
clemente 5:695063448f2a 186 {
clemente 5:695063448f2a 187 unsigned char t;
clemente 5:695063448f2a 188
clemente 5:695063448f2a 189 // Activate the peripheral
clemente 5:695063448f2a 190 readRegs(REG_CTRL_REG_1, &t, 1);
clemente 5:695063448f2a 191 unsigned char data[2] = {REG_CTRL_REG_1, t|0x01};
clemente 5:695063448f2a 192 writeRegs(data, 2);
clemente 5:695063448f2a 193 }
clemente 5:695063448f2a 194
clemente 5:695063448f2a 195 void MMA8451Q::Standby( void)
clemente 5:695063448f2a 196 {
clemente 5:695063448f2a 197 unsigned char t;
clemente 5:695063448f2a 198
clemente 5:695063448f2a 199 // Standby
clemente 5:695063448f2a 200 readRegs(REG_CTRL_REG_1, &t, 1);
clemente 5:695063448f2a 201 unsigned char data[2] = {REG_CTRL_REG_1, t&0xFE};
clemente 5:695063448f2a 202 writeRegs(data, 2);
clemente 5:695063448f2a 203 }
emilmont 0:6149091f755d 204
emilmont 0:6149091f755d 205 uint8_t MMA8451Q::getWhoAmI() {
emilmont 0:6149091f755d 206 uint8_t who_am_i = 0;
samux 1:d2630136d51e 207 readRegs(REG_WHO_AM_I, &who_am_i, 1);
emilmont 0:6149091f755d 208 return who_am_i;
emilmont 0:6149091f755d 209 }
emilmont 0:6149091f755d 210
chris 3:db7126dbd63f 211 float MMA8451Q::getAccX() {
chris 3:db7126dbd63f 212 return (float(getAccAxis(REG_OUT_X_MSB))/4096.0);
emilmont 0:6149091f755d 213 }
emilmont 0:6149091f755d 214
chris 3:db7126dbd63f 215 float MMA8451Q::getAccY() {
chris 3:db7126dbd63f 216 return (float(getAccAxis(REG_OUT_Y_MSB))/4096.0);
emilmont 0:6149091f755d 217 }
emilmont 0:6149091f755d 218
chris 3:db7126dbd63f 219 float MMA8451Q::getAccZ() {
chris 3:db7126dbd63f 220 return (float(getAccAxis(REG_OUT_Z_MSB))/4096.0);
emilmont 0:6149091f755d 221 }
emilmont 0:6149091f755d 222
chris 3:db7126dbd63f 223 void MMA8451Q::getAccAllAxis(float * res) {
emilmont 0:6149091f755d 224 res[0] = getAccX();
emilmont 0:6149091f755d 225 res[1] = getAccY();
emilmont 0:6149091f755d 226 res[2] = getAccZ();
emilmont 0:6149091f755d 227 }
emilmont 0:6149091f755d 228
emilmont 0:6149091f755d 229 int16_t MMA8451Q::getAccAxis(uint8_t addr) {
emilmont 0:6149091f755d 230 int16_t acc;
emilmont 0:6149091f755d 231 uint8_t res[2];
samux 1:d2630136d51e 232 readRegs(addr, res, 2);
emilmont 0:6149091f755d 233
emilmont 0:6149091f755d 234 acc = (res[0] << 6) | (res[1] >> 2);
emilmont 0:6149091f755d 235 if (acc > UINT14_MAX/2)
emilmont 0:6149091f755d 236 acc -= UINT14_MAX;
emilmont 0:6149091f755d 237
emilmont 0:6149091f755d 238 return acc;
emilmont 0:6149091f755d 239 }
emilmont 0:6149091f755d 240
samux 1:d2630136d51e 241 void MMA8451Q::readRegs(int addr, uint8_t * data, int len) {
emilmont 0:6149091f755d 242 char t[1] = {addr};
emilmont 0:6149091f755d 243 m_i2c.write(m_addr, t, 1, true);
emilmont 0:6149091f755d 244 m_i2c.read(m_addr, (char *)data, len);
emilmont 0:6149091f755d 245 }
emilmont 0:6149091f755d 246
samux 1:d2630136d51e 247 void MMA8451Q::writeRegs(uint8_t * data, int len) {
emilmont 0:6149091f755d 248 m_i2c.write(m_addr, (char *)data, len);
emilmont 0:6149091f755d 249 }