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
MMA8451Q.cpp
- Committer:
- maclobdell
- Date:
- 2013-02-27
- Revision:
- 5:c43505b5bc31
- Parent:
- 3:db7126dbd63f
- Child:
- 6:2b68086a26ff
File content as of revision 5:c43505b5bc31:
/* Copyright (c) 2010-2011 mbed.org, MIT License * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "MMA8451Q.h" #define REG_WHO_AM_I 0x0D #define REG_CTRL_REG_1 0x2A #define REG_OUT_X_MSB 0x01 #define REG_OUT_Y_MSB 0x03 #define REG_OUT_Z_MSB 0x05 #define UINT14_MAX 16383 // 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 who_am_i = 0; readRegs(REG_WHO_AM_I, &who_am_i, 1); return who_am_i; } float MMA8451Q::getAccX() { return (float(getAccAxis(REG_OUT_X_MSB))/4096.0); } float MMA8451Q::getAccY() { return (float(getAccAxis(REG_OUT_Y_MSB))/4096.0); } float MMA8451Q::getAccZ() { return (float(getAccAxis(REG_OUT_Z_MSB))/4096.0); } void MMA8451Q::getAccAllAxis(float * res) { res[0] = getAccX(); res[1] = getAccY(); res[2] = getAccZ(); } int16_t MMA8451Q::getAccAxis(uint8_t addr) { int16_t acc; uint8_t res[2]; readRegs(addr, res, 2); acc = (res[0] << 6) | (res[1] >> 2); if (acc > UINT14_MAX/2) acc -= UINT14_MAX; return acc; } 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) { 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; }