mma8451q driver with a few minor modifications
Fork of lib_mma8451q by
mma8451q.cpp
- Committer:
- shaunkrnelson
- Date:
- 2016-08-12
- Revision:
- 5:7bcda574c0fa
- Parent:
- 3:96faac0d688e
- Child:
- 6:828b08201d8b
File content as of revision 5:7bcda574c0fa:
#include "mma8451q.h" /* turn on: CTRL_REG1 active_bit = 1 * back to standby: CTRL_REG1 active_bit = 0 */ /* STANDBY: SYSMOD = 00 */ /* * MMA8451 I2C address */ #define MMA8451_I2C_ADDRESS 0x38 //0x1C MMA8451Q::MMA8451Q(I2C& r, DigitalIn& int_pin) : m_i2c(r), m_int_pin(int_pin) { /* INT pins on this chip default to push-pull output */ write(MMA8451_CTRL_REG3, 0x01); // set PP_OD /* INT1 and INT2 are tied together */ } MMA8451Q::~MMA8451Q() { } void MMA8451Q::read(uint8_t addr, uint8_t *dst_buf, int length) { char cmd[2]; cmd[0] = addr; if (m_i2c.write(MMA8451_I2C_ADDRESS, cmd, 1, true)) printf("MMA write-fail %02x\n", addr); if (m_i2c.read(MMA8451_I2C_ADDRESS, (char *)dst_buf, length)) printf("MMA read-fail\n"); } uint8_t MMA8451Q::read_single(uint8_t addr) { char cmd[2]; cmd[0] = addr; if (m_i2c.write(MMA8451_I2C_ADDRESS, cmd, 1, true)) printf("MMA write-fail %02x\n", addr); if (m_i2c.read(MMA8451_I2C_ADDRESS, cmd, 1)) printf("MMA read-fail\n"); return cmd[0]; } void MMA8451Q::print_regs() { printf("ID: %02x\r\n", read_single(MMA8451_ID)); printf("sysmod:%02x\r\n", read_single(MMA8451_SYSMOD)); ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1); printf("ctrl_reg1:%02x\r\n", ctrl_reg1.octet); printf("ctrl_reg2:%02x\r\n", read_single(MMA8451_CTRL_REG2)); printf("ctrl_reg3:%02x\r\n", read_single(MMA8451_CTRL_REG3)); /* TODO: PP_OD is bit 0 (1=open drain) */ printf("(int en) ctrl_reg4:%02x\r\n", read_single(MMA8451_CTRL_REG4)); printf("(int cfg) ctrl_reg5:%02x\r\n", read_single(MMA8451_CTRL_REG5)); printf("status:%02x\r\n", read_single(MMA8451_STATUS)); /* (interrupt status) int src at 0x0c (MMA8451_INT_SOURCE): data ready, motion/freefall, pulse, orientation, transient, auto sleep */ printf("INT_SOURCE:%02x\r\n", read_single(MMA8451_INT_SOURCE)); } void MMA8451Q::write(uint8_t addr, uint8_t data) { uint8_t cmd[2]; cmd[0] = addr; cmd[1] = data; if (m_i2c.write(MMA8451_I2C_ADDRESS, (char *)cmd, 2)) printf("MMA write-fail %02x\n", addr); } void MMA8451Q::set_active(char arg) { char cmd[2]; cmd[0] = MMA8451_CTRL_REG1; cmd[1] = arg; if (m_i2c.write(MMA8451_I2C_ADDRESS, cmd, 2)) printf("MMA write-fail %02x\n", cmd[0]); } bool MMA8451Q::get_active(void) { uint8_t ret = read_single(MMA8451_CTRL_REG1); //printf("CTRL_REG1: %x\n", ret); if (ret & 1) return true; else return false; } void MMA8451Q::orient_detect() { uint8_t v; ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1); /* AN4068 Sensors Freescale Semiconductor, Inc. * 4.1 Example Steps for Implementing the Embedded Orientation Detection */ /* Step 1: Put the part into Standby Mode */ ctrl_reg1.bits.ACTIVE = 0; write(MMA8451_CTRL_REG1, ctrl_reg1.octet); /* Step 2: Set the data rate to 50 Hz (for example, but can choose any sample rate). */ ctrl_reg1.bits.DR = 4; write(MMA8451_CTRL_REG1, ctrl_reg1.octet); /* Step 3: Set the PL_EN bit in Register 0x11 PL_CFG. This will enable the orientation detection. */ v = read_single(MMA8451_PL_CFG); v |= 0x40; write(MMA8451_PL_CFG, v); /* Step 4: Set the Back/Front Angle trip points in register 0x13 following the table in the data sheet. */ v = read_single(MMA8451_PL_BF_ZCOMP); /*v &= 0x3f; v |= 0xX0; write(MMA8451_PL_BF_ZCOMP, v);*/ /* Step 5: Set the Z-Lockout angle trip point in register 0x13 following the table in the data sheet. */ /* v &= 0xf8; v |= 0x0X; */ /* Step 6: Set the Trip Threshold Angle */ v = read_single(MMA8451_PL_THS_REG); /*v &= 0x07; v |= 0x0X << 3; write(MMA8451_PL_THS_REG. v);*/ /* Step 7: Set the Hysteresis Angle */ v = read_single(MMA8451_PL_THS_REG); /*v &= 0xf8; v |= 0x0X; write(MMA8451_PL_THS_REG. v);*/ /* Step 8: Register 0x2D, Control Register 4 configures all embedded features for interrupt */ ctrl_reg4.octet = 0; ctrl_reg4.bits.INT_EN_LNDPRT = 1; write(MMA8451_CTRL_REG4, ctrl_reg4.octet); /* Step 9: Register 0x2E is Control Register 5 which gives the option of routing the interrupt to either INT1 or INT2 */ ctrl_reg5.octet = 0; ctrl_reg5.bits.INT_CFG_LNDPRT = 1; write(MMA8451_CTRL_REG5, ctrl_reg5.octet); /* Step 10: Set the debounce counter in register 0x12 */ write(MMA8451_PL_COUNT, 5); // 5: debounce to 100ms at 50hz /* Step 11: Put the device in Active Mode */ ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1); ctrl_reg1.bits.ACTIVE = 1; write(MMA8451_CTRL_REG1, ctrl_reg1.octet); /* Step 12: in service() function */ } void MMA8451Q::transient_detect() { ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1); /* AN4071 Sensors Freescale Semiconductor, Inc. * 7.1 Example Steps for Configuring Transient Detection * Change in X or Y > 0.5g for 50 ms at 100 Hz ODR, Normal mode */ /* Step 1: Put the device in Standby Mode: Register 0x2A CTRL_REG1 */ ctrl_reg1.bits.ACTIVE = 0; write(MMA8451_CTRL_REG1, ctrl_reg1.octet); ctrl_reg1.bits.DR = 3; //Set device in 100 Hz ODR, Standby write(MMA8451_CTRL_REG1, ctrl_reg1.octet); /* Step 2: Enable X and Y Axes and enable the latch: Register 0x1D Configuration Register */ transient_cfg.octet = 0; transient_cfg.bits.ELE = 1; // enable latch transient_cfg.bits.YTEFE = 1; // enable Y transient_cfg.bits.XTEFE = 1; // enable X transient_cfg.bits.ZTEFE = 1; // enable Z write(MMA8451_TRANSIENT_CFG, transient_cfg.octet); /* Step 3: Set the Threshold: Register 0x1F * Note: Step count is 0.063g per count, 0.5g / 0.063g = 7.93. * Therefore set the threshold to 8 counts */ write(MMA8451_TRANSIENT_THS, 8); /* Step 4: Set the Debounce Counter for 50 ms: Register 0x20 * Note: 100 Hz ODR, therefore 10 ms step sizes */ write(MMA8451_TRANSIENT_COUNT, 5); /* Step 5: Enable Transient Detection Interrupt in the System (CTRL_REG4) */ ctrl_reg4.octet = 0; ctrl_reg4.bits.INT_EN_TRANS = 1; write(MMA8451_CTRL_REG4, ctrl_reg4.octet); /* Step 6: Route the Transient Interrupt to INT 1 hardware pin (CTRL_REG5) */ ctrl_reg5.octet = 0; ctrl_reg5.bits.INT_CFG_TRANS = 1; write(MMA8451_CTRL_REG5, ctrl_reg5.octet); /* Step 7: Put the device in Active Mode: Register 0x2A CTRL_REG1 */ ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1); ctrl_reg1.bits.ACTIVE = 1; write(MMA8451_CTRL_REG1, ctrl_reg1.octet); /* Step 8: Write Interrupt Service Routine Reading the * System Interrupt Status and the Transient Status */ } uint8_t MMA8451Q::service() { mma_int_source_t int_src; if (m_int_pin) return 0; // no interrupt int_src.octet = read_single(MMA8451_INT_SOURCE); if (int_src.bits.SRC_DRDY) { read(MMA8451_OUT_X_MSB, out.octets, 6); } if (int_src.bits.SRC_FF_MT) { read_single(MMA8451_FF_MT_SRC); } if (int_src.bits.SRC_PULSE) { read_single(MMA8451_PULSE_SRC); } if (int_src.bits.SRC_LNDPRT) { mma_pl_status_t pl_status; /*AN4068 Step 12: Write a Service Routine to Service the Interrupt */ pl_status.octet = read_single(MMA8451_PL_STATUS); if(verbose) printf("PL_STATUS: "); if (pl_status.bits.NEWLP) { orientation.reset(); if (pl_status.bits.LO) { orientation.low = true; if(verbose) printf("Z-tilt-LO "); } if (pl_status.bits.LAPO == 0) { orientation.up = true; if(verbose) printf("up "); } else if (pl_status.bits.LAPO == 1) { orientation.down = true; if(verbose) printf("down "); } else if (pl_status.bits.LAPO == 2) { orientation.right = true; if(verbose) printf("right "); } else if (pl_status.bits.LAPO == 3) { orientation.left = true; if(verbose) printf("left "); } if (pl_status.bits.BAFRO) { orientation.back = true; if(verbose) printf("back "); } else { orientation.front = true; if(verbose) printf("front "); } } if(verbose) printf("\r\n"); } // ...int_src.bits.SRC_LNDPRT if (int_src.bits.SRC_TRANS) { transient_src_t t_src; t_src.octet = read_single(MMA8451_TRANSIENT_SRC); if (verbose) { printf("transient src:%x ", t_src.octet); if (t_src.bits.XTRANSE) printf("X_Pol:%d ", t_src.bits.X_Trans_Pol); if (t_src.bits.YTRANSE) printf("Y_Pol:%d ", t_src.bits.Y_Trans_Pol); if (t_src.bits.ZTRANSE) printf("Z_Pol:%d ", t_src.bits.Z_Trans_Pol); printf("\r\n"); } } // ...int_src.bits.SRC_TRANS if (int_src.bits.SRC_ASLP) { read_single(MMA8451_SYSMOD); } return int_src.octet; }