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
Diff: MMA8451Q.cpp
- Revision:
- 5:c43505b5bc31
- Parent:
- 3:db7126dbd63f
- Child:
- 6:2b68086a26ff
--- a/MMA8451Q.cpp Fri Oct 12 11:35:07 2012 +0000 +++ b/MMA8451Q.cpp Wed Feb 27 03:58:53 2013 +0000 @@ -26,39 +26,167 @@ #define UINT14_MAX 16383 -MMA8451Q::MMA8451Q(PinName sda, PinName scl, int addr) : m_i2c(sda, scl), m_addr(addr) { - // activate the peripheral - uint8_t data[2] = {REG_CTRL_REG_1, 0x01}; - writeRegs(data, 2); +// Set the scale below either 2, 4 or 8 +#define SCALE 2; // Sets full-scale range to +/-2, 4, or 8g. Used to calc real g values. +// Set the output data rate below. Value should be between 0 and 7 +#define DATARATE = 0; // 0=800Hz, 1=400, 2=200, 3=100, 4=50, 5=12.5, 6=6.25, 7=1.56 + +extern Serial pc; + +MMA8451Q::MMA8451Q(PinName sda, PinName scl, int addr) : m_i2c(sda, scl), m_addr(addr) +{ + //need to clear registers before writing because they only get cleared on a power cycle + //need to implement that + + modeStandby(); // Must be in standby to change registers + +/* pc.printf("++++++++++++++++++\n\r"); + uint8_t myRegs = 0; + for(uint8_t i = 0; i<0x31;i++) + { + myRegs = readRegister(i); + pc.printf("%x: %x\n\r",i,myRegs); + } + pc.printf("+==+==+==++===+=+\n\r"); +*/ + + // Set up the full scale range to 2, 4, or 8g. + //if ((fsr==2)||(fsr==4)||(fsr==8)) + writeRegister(0x0E, 0); //SCALE >> 2); + //else + // writeRegister(0x0E, 0); + + // Setup the 3 data rate bits, from 0 to 7 + writeRegister(0x2A, readRegister(0x2A) & ~(0x38)); + //if (DATARATE <= 7) + // writeRegister(0x2A, readRegister(0x2A) | (DATARATE << 3)); + + // Set up portrait/landscap registers - 4 steps: + // 1. Enable P/L + // 2. Set the back/front angle trigger points (z-lock) + // 3. Set the threshold/hysteresis angle + // 4. Set the debouce rate + // For more info check out this app note: http://cache.freescale.com/files/sensors/doc/app_note/AN4068.pdf +if(MMA8451Q_ENABLE_ORIENTATION) +{ +pc.printf("setting orientation configuraiton \n\r"); + + writeRegister(0x11, 0x40); // 1. Enable P/L + writeRegister(0x13, 0x44); // 2. 29deg z-lock (don't think this register is actually writable) + writeRegister(0x14, 0x84); // 3. 45deg thresh, 14deg hyst (don't think this register is writable either) + writeRegister(0x12, 0x50); // 4. debounce counter at 100ms (at 800 hz) +} + + /* Set up single and double tap - 5 steps: + 1. Set up single and/or double tap detection on each axis individually. + 2. Set the threshold - minimum required acceleration to cause a tap. + 3. Set the time limit - the maximum time that a tap can be above the threshold + 4. Set the pulse latency - the minimum required time between one pulse and the next + 5. Set the second pulse window - maximum allowed time between end of latency and start of second pulse + for more info check out this app note: http://cache.freescale.com/files/sensors/doc/app_note/AN4072.pdf */ +if( MMA8451Q_ENABLE_DOUBLE_Z_TAP | MMA8451Q_ENABLE_SINGLE_Z_TAP) +{ + //writeRegister(0x21, 0x7F); // 1. enable single/double taps on all axes + // writeRegister(0x21, 0x55); // 1. single taps only on all axes + // writeRegister(0x21, 0x6A); // 1. double taps only on all axes + pc.printf("setting tap configuraiton \n\r"); + + + if(MMA8451Q_ENABLE_DOUBLE_Z_TAP) + writeRegister(0x21, readRegister(0x21) | 0x60); // 1. enable double taps on Z axes + if(MMA8451Q_ENABLE_SINGLE_Z_TAP) + writeRegister(0x21, readRegister(0x21) | 0x50); // 1. enable single taps on Z axes + + + /* set up the Tap threshold and timing */ + //not doing x,y taps +// writeRegister(0x23, 0x20); // 2. x thresh at 2g, multiply the value by 0.0625g/LSB to get the threshold +// writeRegister(0x24, 0x20); // 2. y thresh at 2g, multiply the value by 0.0625g/LSB to get the threshold +// writeRegister(0x25, 0x08); // 2. z thresh at .5g, multiply the value by 0.0625g/LSB to get the threshold + writeRegister(0x25, 0x04); // 2. z thresh at ?g, multiply the value by 0.0625g/LSB to get the threshold + writeRegister(0x26, 0x30); // 3. 30ms time limit at 800Hz odr, this is very dependent on data rate, see the app note + writeRegister(0x27, 0xA0); // 4. 200ms (at 800Hz odr) between taps min, this also depends on the data rate + writeRegister(0x28, 0xFF); // 5. 318ms (max value) between taps max +} + +if( MMA8451Q_ENABLE_DOUBLE_Z_TAP | MMA8451Q_ENABLE_SINGLE_Z_TAP | MMA8451Q_ENABLE_DATAREADY | MMA8451Q_ENABLE_ORIENTATION) +{ + pc.printf("setting up interrupts \n\r"); + + // Set up interrupt 1 and 2 + + // writeRegister(0x2C, 0x02); // Active high, push-pull interrupts + writeRegister(0x2C, 0x01); // Active low, push-pull interrupts + + //writeRegister(0x2D, 0x19); // DRDY, P/L and tap ints enabled +// writeRegister(0x2D, 0x9); // DRDY, tap ints enabled + +if( MMA8451Q_ENABLE_DATAREADY) +{//enable data ready interrupts + writeRegister(0x2D, readRegister(0x2D)| 0x1); // DRDY ints enabled +} +if( MMA8451Q_ENABLE_DOUBLE_Z_TAP | MMA8451Q_ENABLE_SINGLE_Z_TAP) +{//enable tap interrupts + writeRegister(0x2D, readRegister(0x2D)| 0x8); // taps ints enabled +} +if( MMA8451Q_ENABLE_ORIENTATION) +{//enable orientation interrupts + writeRegister(0x2D, readRegister(0x2D)| 0x10); // orientation ints enabled +} + + writeRegister(0x2E, 0x01); // DRDY on INT1, P/L and taps on INT2 + +} + + modeActive(); // Set to active to start reading + +/* + pc.printf("Print Registers\n\r"); + pc.printf("---------------\n\r"); + myRegs = 0; + for(uint8_t i = 0; i<0x31;i++) + { + myRegs = readRegister(i); + pc.printf("%x: %x\n\r",i,myRegs); + } + pc.printf("================\n\r"); +*/ + } MMA8451Q::~MMA8451Q() { } -uint8_t MMA8451Q::getWhoAmI() { +uint8_t MMA8451Q::getWhoAmI() +{ uint8_t who_am_i = 0; readRegs(REG_WHO_AM_I, &who_am_i, 1); return who_am_i; } -float MMA8451Q::getAccX() { +float MMA8451Q::getAccX() +{ return (float(getAccAxis(REG_OUT_X_MSB))/4096.0); } -float MMA8451Q::getAccY() { +float MMA8451Q::getAccY() +{ return (float(getAccAxis(REG_OUT_Y_MSB))/4096.0); } -float MMA8451Q::getAccZ() { +float MMA8451Q::getAccZ() +{ return (float(getAccAxis(REG_OUT_Z_MSB))/4096.0); } -void MMA8451Q::getAccAllAxis(float * res) { +void MMA8451Q::getAccAllAxis(float * res) +{ res[0] = getAccX(); res[1] = getAccY(); res[2] = getAccZ(); } -int16_t MMA8451Q::getAccAxis(uint8_t addr) { +int16_t MMA8451Q::getAccAxis(uint8_t addr) +{ int16_t acc; uint8_t res[2]; readRegs(addr, res, 2); @@ -70,12 +198,62 @@ return acc; } -void MMA8451Q::readRegs(int addr, uint8_t * data, int len) { +void MMA8451Q::readRegs(int addr, uint8_t * data, int len) +{ char t[1] = {addr}; m_i2c.write(m_addr, t, 1, true); m_i2c.read(m_addr, (char *)data, len); } -void MMA8451Q::writeRegs(uint8_t * data, int len) { +void MMA8451Q::writeRegs(uint8_t * data, int len) +{ m_i2c.write(m_addr, (char *)data, len); } + +void MMA8451Q::writeRegister(uint8_t reg, uint8_t data) +{ //write to single register + uint8_t wdata[2] = {reg, data}; + m_i2c.write(m_addr, (char *)wdata, 2); + +} +uint8_t MMA8451Q::readRegister(uint8_t reg) +{ //read single register + + uint8_t data; + readRegs(reg, &data, 1); + + return data; +} + +// Sets the MMA8452 to standby mode. +// It must be in standby to change most register settings +void MMA8451Q::modeStandby(void) +{ + uint8_t c = readRegister(0x2A); + writeRegister(0x2A, c & ~(0x01)); +} + +// Sets the MMA8452 to active mode. +// Needs to be in this mode to output data +void MMA8451Q::modeActive(void) +{ + int8_t c = readRegister(0x2A); + writeRegister(0x2A, c | 0x01); +} + +uint8_t MMA8451Q::direction(void) +{ + uint8_t pl = readRegister(0x10); // Reads the PL_STATUS register + return pl; + +} +uint8_t MMA8451Q::tapSource(void) +{ + uint8_t source = readRegister(0x22); // Reads the PULSE_SRC register + return source; +} +uint8_t MMA8451Q::intSource(void) +{ + uint8_t source = readRegister(0x0C); // Read the interrupt source reg. + return source; +}