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 Emilio Monti

Files at this revision

API Documentation at this revision

Comitter:
maclobdell
Date:
Wed Feb 27 03:58:53 2013 +0000
Parent:
4:c4d879a39775
Child:
6:2b68086a26ff
Commit message:
1st working version

Changed in this revision

MMA8451Q.cpp Show annotated file Show diff for this revision Revisions of this file
MMA8451Q.h Show annotated file Show diff for this revision Revisions of this file
--- 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;
+}
--- a/MMA8451Q.h	Fri Oct 12 11:35:07 2012 +0000
+++ b/MMA8451Q.h	Wed Feb 27 03:58:53 2013 +0000
@@ -21,6 +21,12 @@
 
 #include "mbed.h"
 
+//just supporting Z taps in the code, not X, Y yet
+#define MMA8451Q_ENABLE_DOUBLE_Z_TAP  0
+#define MMA8451Q_ENABLE_SINGLE_Z_TAP  1
+#define MMA8451Q_ENABLE_ORIENTATION   0
+#define MMA8451Q_ENABLE_DATAREADY     0
+
 /**
 * MMA8451Q accelerometer example
 *
@@ -98,13 +104,19 @@
    */
   void getAccAllAxis(float * res);
 
+  uint8_t direction(void);
+  uint8_t tapSource(void);
+  uint8_t intSource(void);
+  
 private:
   I2C m_i2c;
   int m_addr;
   void readRegs(int addr, uint8_t * data, int len);
   void writeRegs(uint8_t * data, int len);
   int16_t getAccAxis(uint8_t addr);
-
+  void writeRegister(uint8_t reg, uint8_t data);
+  uint8_t readRegister(uint8_t reg);
+  void modeStandby(void);
+  void modeActive(void);
 };
-
 #endif