mma8451q driver with a few minor modifications
Fork of lib_mma8451q by
Diff: mma8451q.cpp.orig
- Revision:
- 6:828b08201d8b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mma8451q.cpp.orig Fri Aug 12 14:13:17 2016 +0000 @@ -0,0 +1,312 @@ +#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; +}