mma8451q driver

Dependents:   nRF51822_DataLogger_PowerImpulseCounter scpi_sx127x NAMote72_Utility

Committer:
dudmuck
Date:
Tue Sep 01 00:27:13 2015 +0000
Revision:
2:4bc96749141e
Parent:
1:778b685c3ad0
added orientation detection mode

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 0:cb0046a629c1 1 #include "mma8451q.h"
dudmuck 0:cb0046a629c1 2 /* turn on: CTRL_REG1 active_bit = 1
dudmuck 0:cb0046a629c1 3 * back to standby: CTRL_REG1 active_bit = 0
dudmuck 0:cb0046a629c1 4 */
dudmuck 0:cb0046a629c1 5
dudmuck 0:cb0046a629c1 6 /* STANDBY: SYSMOD = 00 */
dudmuck 0:cb0046a629c1 7
dudmuck 0:cb0046a629c1 8 /*
dudmuck 0:cb0046a629c1 9 * MMA8451 I2C address
dudmuck 0:cb0046a629c1 10 */
dudmuck 0:cb0046a629c1 11 #define MMA8451_I2C_ADDRESS 0x38 //0x1C
dudmuck 0:cb0046a629c1 12
dudmuck 0:cb0046a629c1 13
dudmuck 1:778b685c3ad0 14 MMA8451Q::MMA8451Q(I2C& r, DigitalIn& int_pin) : m_i2c(r), m_int_pin(int_pin)
dudmuck 0:cb0046a629c1 15 {
dudmuck 1:778b685c3ad0 16 /* INT pins on this chip default to push-pull output */
dudmuck 1:778b685c3ad0 17 write(MMA8451_CTRL_REG3, 0x01); // set PP_OD
dudmuck 1:778b685c3ad0 18 /* INT1 and INT2 are tied together */
dudmuck 0:cb0046a629c1 19
dudmuck 0:cb0046a629c1 20 }
dudmuck 0:cb0046a629c1 21
dudmuck 0:cb0046a629c1 22 MMA8451Q::~MMA8451Q()
dudmuck 0:cb0046a629c1 23 {
dudmuck 0:cb0046a629c1 24 }
dudmuck 0:cb0046a629c1 25
dudmuck 0:cb0046a629c1 26 void MMA8451Q::read(uint8_t addr, uint8_t *dst_buf, int length)
dudmuck 0:cb0046a629c1 27 {
dudmuck 0:cb0046a629c1 28 char cmd[2];
dudmuck 0:cb0046a629c1 29
dudmuck 0:cb0046a629c1 30 cmd[0] = addr;
dudmuck 0:cb0046a629c1 31 if (m_i2c.write(MMA8451_I2C_ADDRESS, cmd, 1, true))
dudmuck 1:778b685c3ad0 32 printf("MMA write-fail %02x\n", addr);
dudmuck 0:cb0046a629c1 33 if (m_i2c.read(MMA8451_I2C_ADDRESS, (char *)dst_buf, length))
dudmuck 1:778b685c3ad0 34 printf("MMA read-fail\n");
dudmuck 0:cb0046a629c1 35 }
dudmuck 0:cb0046a629c1 36
dudmuck 0:cb0046a629c1 37 uint8_t MMA8451Q::read_single(uint8_t addr)
dudmuck 0:cb0046a629c1 38 {
dudmuck 0:cb0046a629c1 39 char cmd[2];
dudmuck 0:cb0046a629c1 40
dudmuck 0:cb0046a629c1 41 cmd[0] = addr;
dudmuck 0:cb0046a629c1 42 if (m_i2c.write(MMA8451_I2C_ADDRESS, cmd, 1, true))
dudmuck 1:778b685c3ad0 43 printf("MMA write-fail %02x\n", addr);
dudmuck 0:cb0046a629c1 44 if (m_i2c.read(MMA8451_I2C_ADDRESS, cmd, 1))
dudmuck 1:778b685c3ad0 45 printf("MMA read-fail\n");
dudmuck 0:cb0046a629c1 46
dudmuck 0:cb0046a629c1 47 return cmd[0];
dudmuck 0:cb0046a629c1 48 }
dudmuck 0:cb0046a629c1 49
dudmuck 0:cb0046a629c1 50 void MMA8451Q::print_regs()
dudmuck 0:cb0046a629c1 51 {
dudmuck 1:778b685c3ad0 52 printf("ID: %02x\n", read_single(MMA8451_ID));
dudmuck 1:778b685c3ad0 53 printf("sysmod:%02x\n", read_single(MMA8451_SYSMOD));
dudmuck 0:cb0046a629c1 54 ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1);
dudmuck 1:778b685c3ad0 55 printf("ctrl_reg1:%02x\n", ctrl_reg1.octet);
dudmuck 1:778b685c3ad0 56 printf("ctrl_reg2:%02x\n", read_single(MMA8451_CTRL_REG2));
dudmuck 1:778b685c3ad0 57 printf("ctrl_reg3:%02x\n", read_single(MMA8451_CTRL_REG3)); /* TODO: PP_OD is bit 0 (1=open drain) */
dudmuck 1:778b685c3ad0 58 printf("(int en) ctrl_reg4:%02x\n", read_single(MMA8451_CTRL_REG4));
dudmuck 1:778b685c3ad0 59 printf("(int cfg) ctrl_reg5:%02x\n", read_single(MMA8451_CTRL_REG5));
dudmuck 1:778b685c3ad0 60 printf("status:%02x\n", read_single(MMA8451_STATUS));
dudmuck 1:778b685c3ad0 61 /* (interrupt status) int src at 0x0c (MMA8451_INT_SOURCE): data ready, motion/freefall, pulse, orientation, transient, auto sleep */
dudmuck 1:778b685c3ad0 62 printf("INT_SOURCE:%02x\n", read_single(MMA8451_INT_SOURCE));
dudmuck 0:cb0046a629c1 63 }
dudmuck 0:cb0046a629c1 64
dudmuck 0:cb0046a629c1 65 void MMA8451Q::write(uint8_t addr, uint8_t data)
dudmuck 0:cb0046a629c1 66 {
dudmuck 0:cb0046a629c1 67 uint8_t cmd[2];
dudmuck 0:cb0046a629c1 68
dudmuck 0:cb0046a629c1 69 cmd[0] = addr;
dudmuck 0:cb0046a629c1 70 cmd[1] = data;
dudmuck 0:cb0046a629c1 71
dudmuck 0:cb0046a629c1 72 if (m_i2c.write(MMA8451_I2C_ADDRESS, (char *)cmd, 2))
dudmuck 1:778b685c3ad0 73 printf("MMA write-fail %02x\n", addr);
dudmuck 0:cb0046a629c1 74 }
dudmuck 0:cb0046a629c1 75
dudmuck 0:cb0046a629c1 76 void MMA8451Q::set_active(char arg)
dudmuck 0:cb0046a629c1 77 {
dudmuck 0:cb0046a629c1 78 char cmd[2];
dudmuck 0:cb0046a629c1 79
dudmuck 0:cb0046a629c1 80 cmd[0] = MMA8451_CTRL_REG1;
dudmuck 0:cb0046a629c1 81 cmd[1] = arg;
dudmuck 0:cb0046a629c1 82
dudmuck 0:cb0046a629c1 83 if (m_i2c.write(MMA8451_I2C_ADDRESS, cmd, 2))
dudmuck 1:778b685c3ad0 84 printf("MMA write-fail %02x\n", cmd[0]);
dudmuck 0:cb0046a629c1 85 }
dudmuck 0:cb0046a629c1 86
dudmuck 1:778b685c3ad0 87 bool MMA8451Q::get_active(void)
dudmuck 0:cb0046a629c1 88 {
dudmuck 0:cb0046a629c1 89 uint8_t ret = read_single(MMA8451_CTRL_REG1);
dudmuck 1:778b685c3ad0 90 //printf("CTRL_REG1: %x\n", ret);
dudmuck 1:778b685c3ad0 91 if (ret & 1)
dudmuck 1:778b685c3ad0 92 return true;
dudmuck 1:778b685c3ad0 93 else
dudmuck 1:778b685c3ad0 94 return false;
dudmuck 0:cb0046a629c1 95 }
dudmuck 0:cb0046a629c1 96
dudmuck 2:4bc96749141e 97 void MMA8451Q::orient_detect()
dudmuck 2:4bc96749141e 98 {
dudmuck 2:4bc96749141e 99 uint8_t v;
dudmuck 2:4bc96749141e 100
dudmuck 2:4bc96749141e 101 ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1);
dudmuck 2:4bc96749141e 102 /* AN4068 Sensors Freescale Semiconductor, Inc.
dudmuck 2:4bc96749141e 103 * 4.1 Example Steps for Implementing the Embedded Orientation Detection */
dudmuck 2:4bc96749141e 104
dudmuck 2:4bc96749141e 105 /* Step 1: Put the part into Standby Mode */
dudmuck 2:4bc96749141e 106 ctrl_reg1.bits.ACTIVE = 0;
dudmuck 2:4bc96749141e 107 write(MMA8451_CTRL_REG1, ctrl_reg1.octet);
dudmuck 2:4bc96749141e 108
dudmuck 2:4bc96749141e 109 /* Step 2: Set the data rate to 50 Hz (for example, but can choose any sample rate). */
dudmuck 2:4bc96749141e 110 ctrl_reg1.bits.DR = 4;
dudmuck 2:4bc96749141e 111 write(MMA8451_CTRL_REG1, ctrl_reg1.octet);
dudmuck 2:4bc96749141e 112
dudmuck 2:4bc96749141e 113 /* Step 3: Set the PL_EN bit in Register 0x11 PL_CFG. This will enable the orientation detection. */
dudmuck 2:4bc96749141e 114 v = read_single(MMA8451_PL_CFG);
dudmuck 2:4bc96749141e 115 v |= 0x40;
dudmuck 2:4bc96749141e 116 write(MMA8451_PL_CFG, v);
dudmuck 2:4bc96749141e 117
dudmuck 2:4bc96749141e 118 /* Step 4: Set the Back/Front Angle trip points in register 0x13 following the table in the data sheet. */
dudmuck 2:4bc96749141e 119 v = read_single(MMA8451_PL_BF_ZCOMP);
dudmuck 2:4bc96749141e 120 /*v &= 0x3f;
dudmuck 2:4bc96749141e 121 v |= 0xX0;
dudmuck 2:4bc96749141e 122 write(MMA8451_PL_BF_ZCOMP, v);*/
dudmuck 2:4bc96749141e 123
dudmuck 2:4bc96749141e 124 /* Step 5: Set the Z-Lockout angle trip point in register 0x13 following the table in the data sheet. */
dudmuck 2:4bc96749141e 125 /* v &= 0xf8;
dudmuck 2:4bc96749141e 126 v |= 0x0X;
dudmuck 2:4bc96749141e 127 */
dudmuck 2:4bc96749141e 128
dudmuck 2:4bc96749141e 129 /* Step 6: Set the Trip Threshold Angle */
dudmuck 2:4bc96749141e 130 v = read_single(MMA8451_PL_THS_REG);
dudmuck 2:4bc96749141e 131 /*v &= 0x07;
dudmuck 2:4bc96749141e 132 v |= 0x0X << 3;
dudmuck 2:4bc96749141e 133 write(MMA8451_PL_THS_REG. v);*/
dudmuck 2:4bc96749141e 134
dudmuck 2:4bc96749141e 135 /* Step 7: Set the Hysteresis Angle */
dudmuck 2:4bc96749141e 136 v = read_single(MMA8451_PL_THS_REG);
dudmuck 2:4bc96749141e 137 /*v &= 0xf8;
dudmuck 2:4bc96749141e 138 v |= 0x0X;
dudmuck 2:4bc96749141e 139 write(MMA8451_PL_THS_REG. v);*/
dudmuck 2:4bc96749141e 140
dudmuck 2:4bc96749141e 141 /* Step 8: Register 0x2D, Control Register 4 configures all embedded features for interrupt */
dudmuck 2:4bc96749141e 142 ctrl_reg4.octet = 0;
dudmuck 2:4bc96749141e 143 ctrl_reg4.bits.INT_EN_LNDPRT = 1;
dudmuck 2:4bc96749141e 144 write(MMA8451_CTRL_REG4, ctrl_reg4.octet);
dudmuck 2:4bc96749141e 145
dudmuck 2:4bc96749141e 146 /* Step 9: Register 0x2E is Control Register 5 which gives the option of routing the interrupt to either INT1 or INT2 */
dudmuck 2:4bc96749141e 147 ctrl_reg5.octet = 0;
dudmuck 2:4bc96749141e 148 ctrl_reg5.bits.INT_CFG_LNDPRT = 1;
dudmuck 2:4bc96749141e 149 write(MMA8451_CTRL_REG5, ctrl_reg5.octet);
dudmuck 2:4bc96749141e 150
dudmuck 2:4bc96749141e 151 /* Step 10: Set the debounce counter in register 0x12 */
dudmuck 2:4bc96749141e 152 write(MMA8451_PL_COUNT, 5); // 5: debounce to 100ms at 50hz
dudmuck 2:4bc96749141e 153
dudmuck 2:4bc96749141e 154 /* Step 11: Put the device in Active Mode */
dudmuck 2:4bc96749141e 155 ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1);
dudmuck 2:4bc96749141e 156 ctrl_reg1.bits.ACTIVE = 1;
dudmuck 2:4bc96749141e 157 write(MMA8451_CTRL_REG1, ctrl_reg1.octet);
dudmuck 2:4bc96749141e 158
dudmuck 2:4bc96749141e 159 /* Step 12: in service() function */
dudmuck 2:4bc96749141e 160 }
dudmuck 2:4bc96749141e 161
dudmuck 0:cb0046a629c1 162
dudmuck 0:cb0046a629c1 163 void MMA8451Q::transient_detect()
dudmuck 0:cb0046a629c1 164 {
dudmuck 0:cb0046a629c1 165 ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1);
dudmuck 0:cb0046a629c1 166 /* AN4071 Sensors Freescale Semiconductor, Inc.
dudmuck 0:cb0046a629c1 167 * 7.1 Example Steps for Configuring Transient Detection
dudmuck 0:cb0046a629c1 168 * Change in X or Y > 0.5g for 50 ms at 100 Hz ODR, Normal mode */
dudmuck 0:cb0046a629c1 169
dudmuck 0:cb0046a629c1 170 /* Step 1: Put the device in Standby Mode: Register 0x2A CTRL_REG1 */
dudmuck 0:cb0046a629c1 171 ctrl_reg1.bits.ACTIVE = 0;
dudmuck 0:cb0046a629c1 172 write(MMA8451_CTRL_REG1, ctrl_reg1.octet);
dudmuck 0:cb0046a629c1 173 ctrl_reg1.bits.DR = 3; //Set device in 100 Hz ODR, Standby
dudmuck 0:cb0046a629c1 174 write(MMA8451_CTRL_REG1, ctrl_reg1.octet);
dudmuck 0:cb0046a629c1 175
dudmuck 0:cb0046a629c1 176 /* Step 2: Enable X and Y Axes and enable the latch: Register 0x1D Configuration Register */
dudmuck 0:cb0046a629c1 177 transient_cfg.octet = 0;
dudmuck 0:cb0046a629c1 178 transient_cfg.bits.ELE = 1; // enable latch
dudmuck 0:cb0046a629c1 179 transient_cfg.bits.YTEFE = 1; // enable Y
dudmuck 0:cb0046a629c1 180 transient_cfg.bits.XTEFE = 1; // enable X
dudmuck 0:cb0046a629c1 181 transient_cfg.bits.ZTEFE = 1; // enable Z
dudmuck 0:cb0046a629c1 182 write(MMA8451_TRANSIENT_CFG, transient_cfg.octet);
dudmuck 0:cb0046a629c1 183
dudmuck 0:cb0046a629c1 184 /* Step 3: Set the Threshold: Register 0x1F
dudmuck 0:cb0046a629c1 185 * Note: Step count is 0.063g per count, 0.5g / 0.063g = 7.93.
dudmuck 0:cb0046a629c1 186 * Therefore set the threshold to 8 counts */
dudmuck 0:cb0046a629c1 187 write(MMA8451_TRANSIENT_THS, 8);
dudmuck 0:cb0046a629c1 188
dudmuck 0:cb0046a629c1 189 /* Step 4: Set the Debounce Counter for 50 ms: Register 0x20
dudmuck 0:cb0046a629c1 190 * Note: 100 Hz ODR, therefore 10 ms step sizes */
dudmuck 0:cb0046a629c1 191 write(MMA8451_TRANSIENT_COUNT, 5);
dudmuck 0:cb0046a629c1 192
dudmuck 0:cb0046a629c1 193 /* Step 5: Enable Transient Detection Interrupt in the System (CTRL_REG4) */
dudmuck 0:cb0046a629c1 194 ctrl_reg4.octet = 0;
dudmuck 0:cb0046a629c1 195 ctrl_reg4.bits.INT_EN_TRANS = 1;
dudmuck 0:cb0046a629c1 196 write(MMA8451_CTRL_REG4, ctrl_reg4.octet);
dudmuck 0:cb0046a629c1 197
dudmuck 0:cb0046a629c1 198 /* Step 6: Route the Transient Interrupt to INT 1 hardware pin (CTRL_REG5) */
dudmuck 0:cb0046a629c1 199 ctrl_reg5.octet = 0;
dudmuck 0:cb0046a629c1 200 ctrl_reg5.bits.INT_CFG_TRANS = 1;
dudmuck 0:cb0046a629c1 201 write(MMA8451_CTRL_REG5, ctrl_reg5.octet);
dudmuck 0:cb0046a629c1 202
dudmuck 0:cb0046a629c1 203 /* Step 7: Put the device in Active Mode: Register 0x2A CTRL_REG1 */
dudmuck 0:cb0046a629c1 204 ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1);
dudmuck 0:cb0046a629c1 205 ctrl_reg1.bits.ACTIVE = 1;
dudmuck 0:cb0046a629c1 206 write(MMA8451_CTRL_REG1, ctrl_reg1.octet);
dudmuck 0:cb0046a629c1 207
dudmuck 0:cb0046a629c1 208 /* Step 8: Write Interrupt Service Routine Reading the
dudmuck 0:cb0046a629c1 209 * System Interrupt Status and the Transient Status */
dudmuck 0:cb0046a629c1 210 }
dudmuck 0:cb0046a629c1 211
dudmuck 2:4bc96749141e 212 uint8_t MMA8451Q::service()
dudmuck 1:778b685c3ad0 213 {
dudmuck 1:778b685c3ad0 214 mma_int_source_t int_src;
dudmuck 1:778b685c3ad0 215 if (m_int_pin)
dudmuck 2:4bc96749141e 216 return 0; // no interrupt
dudmuck 1:778b685c3ad0 217
dudmuck 1:778b685c3ad0 218 int_src.octet = read_single(MMA8451_INT_SOURCE);
dudmuck 1:778b685c3ad0 219
dudmuck 1:778b685c3ad0 220 if (int_src.bits.SRC_DRDY) {
dudmuck 1:778b685c3ad0 221 read(MMA8451_OUT_X_MSB, out.octets, 6);
dudmuck 1:778b685c3ad0 222 }
dudmuck 1:778b685c3ad0 223 if (int_src.bits.SRC_FF_MT) {
dudmuck 1:778b685c3ad0 224 read_single(MMA8451_FF_MT_SRC);
dudmuck 1:778b685c3ad0 225 }
dudmuck 1:778b685c3ad0 226 if (int_src.bits.SRC_PULSE) {
dudmuck 1:778b685c3ad0 227 read_single(MMA8451_PULSE_SRC);
dudmuck 1:778b685c3ad0 228 }
dudmuck 1:778b685c3ad0 229 if (int_src.bits.SRC_LNDPRT) {
dudmuck 2:4bc96749141e 230 mma_pl_status_t pl_status;
dudmuck 2:4bc96749141e 231 /*AN4068 Step 12: Write a Service Routine to Service the Interrupt */
dudmuck 2:4bc96749141e 232 pl_status.octet = read_single(MMA8451_PL_STATUS);
dudmuck 2:4bc96749141e 233 if (verbose) {
dudmuck 2:4bc96749141e 234 printf("PL_STATUS: ");
dudmuck 2:4bc96749141e 235 if (pl_status.bits.NEWLP) {
dudmuck 2:4bc96749141e 236 if (pl_status.bits.LO)
dudmuck 2:4bc96749141e 237 printf("Z-tilt-LO ");
dudmuck 2:4bc96749141e 238
dudmuck 2:4bc96749141e 239 if (pl_status.bits.LAPO == 0)
dudmuck 2:4bc96749141e 240 printf("up ");
dudmuck 2:4bc96749141e 241 else if (pl_status.bits.LAPO == 1)
dudmuck 2:4bc96749141e 242 printf("down ");
dudmuck 2:4bc96749141e 243 else if (pl_status.bits.LAPO == 2)
dudmuck 2:4bc96749141e 244 printf("left ");
dudmuck 2:4bc96749141e 245 else if (pl_status.bits.LAPO == 3)
dudmuck 2:4bc96749141e 246 printf("right ");
dudmuck 2:4bc96749141e 247
dudmuck 2:4bc96749141e 248 if (pl_status.bits.BAFRO)
dudmuck 2:4bc96749141e 249 printf("back ");
dudmuck 2:4bc96749141e 250 else
dudmuck 2:4bc96749141e 251 printf("front ");
dudmuck 2:4bc96749141e 252 }
dudmuck 2:4bc96749141e 253 printf("\r\n");
dudmuck 2:4bc96749141e 254 }
dudmuck 2:4bc96749141e 255 } // ...int_src.bits.SRC_LNDPRT
dudmuck 2:4bc96749141e 256
dudmuck 1:778b685c3ad0 257 if (int_src.bits.SRC_TRANS) {
dudmuck 1:778b685c3ad0 258 transient_src_t t_src;
dudmuck 1:778b685c3ad0 259 t_src.octet = read_single(MMA8451_TRANSIENT_SRC);
dudmuck 2:4bc96749141e 260 if (verbose) {
dudmuck 2:4bc96749141e 261 printf("transient src:%x ", t_src.octet);
dudmuck 2:4bc96749141e 262 if (t_src.bits.XTRANSE)
dudmuck 2:4bc96749141e 263 printf("X_Pol:%d ", t_src.bits.X_Trans_Pol);
dudmuck 2:4bc96749141e 264 if (t_src.bits.YTRANSE)
dudmuck 2:4bc96749141e 265 printf("Y_Pol:%d ", t_src.bits.Y_Trans_Pol);
dudmuck 2:4bc96749141e 266 if (t_src.bits.ZTRANSE)
dudmuck 2:4bc96749141e 267 printf("Z_Pol:%d ", t_src.bits.Z_Trans_Pol);
dudmuck 2:4bc96749141e 268 printf("\r\n");
dudmuck 2:4bc96749141e 269 }
dudmuck 2:4bc96749141e 270 } // ...int_src.bits.SRC_TRANS
dudmuck 1:778b685c3ad0 271
dudmuck 1:778b685c3ad0 272 if (int_src.bits.SRC_ASLP) {
dudmuck 1:778b685c3ad0 273 read_single(MMA8451_SYSMOD);
dudmuck 1:778b685c3ad0 274 }
dudmuck 1:778b685c3ad0 275
dudmuck 2:4bc96749141e 276 return int_src.octet;
dudmuck 1:778b685c3ad0 277 }