BMD-200 Evaluation board using the on-board accelerometer (Freescale MMA8653FC). There a couple operating modes (streaming ADC data out the USB COM, moving board in a single axis causes an interrupt, others). Work in progress.

Dependencies:   PinDetect mbed-src-bmd-200

Revision:
0:6f07db1b8cdc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MMA845x.cpp	Wed Jul 15 21:25:42 2015 +0000
@@ -0,0 +1,379 @@
+/**
+ * @file    MMA845x.cpp
+ * @brief   Device driver - MMA845X 3-axis accelerometer IC
+ * @author  sam grove
+ * @version 1.0
+ * @see     http://cache.freescale.com/files/sensors/doc/data_sheet/MMA8451Q.pdf
+ * @see     http://cache.freescale.com/files/sensors/doc/data_sheet/MMA8452Q.pdf
+ * @see     http://cache.freescale.com/files/sensors/doc/data_sheet/MMA8453Q.pdf
+ *
+ * Copyright (c) 2013
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#include "MMA845x.h"
+#include "mbed.h"
+ 
+
+void MMA845x::disable(void)
+{
+    uint8_t reg_val = 0;
+    // Reset all registers to POR values
+    MMA845x::writeRegister(CTRL_REG2, 0xF0);        //REG 0x2B
+    wait(0.05);
+    do{
+        // wait for the reset bit to clear
+        reg_val = MMA845x::readRegister(CTRL_REG2) & 0x40;
+    }while(reg_val);
+    MMA845x::writeRegister(CTRL_REG1, 0x00);        //REG 0x2A 0x98 = ASLP_RATE: 6.25hz Data Rate: 50hz
+}
+
+void MMA845x::setIntMode(int intMode)
+{
+    _intMode = intMode;
+}
+
+void MMA845x::interrupt_1(void)
+{
+    //_int1_waiting = true;
+    
+    uint8_t reg_int_sts;
+    uint8_t reg_sts;
+    uint8_t reg_pulse_sts;
+    uint8_t reg_motion_sts;
+    char reg_data[3][2] = { 0 };
+    int16_t values[3] = { 0 };
+    float g_values[3] = { 0 };
+    reg_int_sts = MMA845x::readRegister(INT_SOURCE);    //REG 0x0C
+    if((reg_int_sts & 0x01)) //Mask register read with SRC_DRDY bit
+    {
+        printf("Int1:");
+        printf(" Data Ready");
+        reg_sts = MMA845x::readRegister(STATUS);    //REG 0x00
+        
+        reg_pulse_sts = MMA845x::readRegister(PULSE_SRC);    //REG 0x22
+        
+        reg_data[0][0] = MMA845x::readRegister(OUT_X_MSB);    //REG 0x01
+        reg_data[0][1] = MMA845x::readRegister(OUT_X_LSB);    //REG 0x02
+        reg_data[1][0] = MMA845x::readRegister(OUT_Y_MSB);    //REG 0x03
+        reg_data[1][1] = MMA845x::readRegister(OUT_Y_LSB);    //REG 0x04
+        reg_data[2][0] = MMA845x::readRegister(OUT_Z_MSB);    //REG 0x05
+        reg_data[2][1] = MMA845x::readRegister(OUT_Z_LSB);    //REG 0x06
+        //printf(" STATUS: 0x%02X X: %d %d Y: %d %d Z: %d %d\n\r", reg_sts, reg_data[0][0], reg_data[0][1], reg_data[1][0], reg_data[1][1], reg_data[2][0], reg_data[2][1]);
+            
+        values[0] = ((reg_data[0][0] * 256) + ((unsigned short) reg_data[0][1]));
+        values[1] = ((reg_data[1][0] * 256) + ((unsigned short) reg_data[1][1]));
+        values[2] = ((reg_data[2][0] * 256) + ((unsigned short) reg_data[2][1]));
+    
+        g_values[0] = ((float) values[0]) / 16384.0;
+        g_values[1] = ((float) values[1]) / 16384.0;
+        g_values[2] = ((float) values[2]) / 16384.0;
+            
+        //printf(" STATUS: 0x%02X X: %d Y: %d Z: %d\n\r", reg_sts, values[0], values[1], values[2]); 
+        
+        if (_intMode == 1)
+        {
+            printf(" STATUS: 0x%02X X: %.3f Y: %.3f Z: %.3f", reg_sts, g_values[0], g_values[1], g_values[2]);
+        }
+        else
+        {
+            int bars = abs( values[0] / 512 );
+            printf(" X: ");
+            for( int i = 0; i < bars; i++ )
+            {
+                printf(">");
+            }
+        }
+        
+        if (reg_pulse_sts & 0x10)
+        {
+            printf(" ***********************************************");
+            _callbackZAxisPulse.call();
+            if (reg_pulse_sts & 0x01)
+            {
+                printf("--------------");    
+            }
+        }
+        printf("\n\r");
+    }
+    if (reg_int_sts & 0x08) //Pulse interrupt
+    {
+        
+        reg_pulse_sts = MMA845x::readRegister(PULSE_SRC);    //REG 0x22
+        if (reg_pulse_sts & 0x40) //Z-axis event
+        {
+            
+            if (reg_pulse_sts & 0x08) //Pulse event was double pulse
+            {
+                
+                
+            }
+            if (reg_pulse_sts & 0x04)//Z-axis pulse direction
+            {
+                
+            }
+            _callbackZAxisPulse.call();
+            
+        }
+    }
+    if (reg_int_sts & 0x04) //Motion interrupt
+    {
+        
+        reg_motion_sts = MMA845x::readRegister(FF_MT_SRC);    //REG 0x16
+        if (reg_motion_sts & 0x02) //
+        {
+            /*
+            if (reg_motion_sts & 0x08) //
+            {
+                
+                
+            }
+            if (reg_motion_sts & 0x04)//
+            {
+                
+            }
+            */
+            _callbackZAxisPulse.call();
+            
+        }
+    }
+}
+
+     /* Call this function when a Z-axis pulse detected
+     *  @param function A C function pointer
+     */
+void MMA845x::attachZAxisPulse( void (*function)(void) )
+{
+    _callbackZAxisPulse.attach( function );
+}
+    
+void MMA845x::interrupt_handler(void)
+{
+    
+    uint8_t reg_int_sts;
+    uint8_t reg_sts;
+    int reg_data[3] = { 0x00, 0x00, 0x00 };
+    printf("Int1:");
+    reg_int_sts = MMA845x::readRegister(INT_SOURCE);    //REG 0x0C
+    if((reg_int_sts & 0x01)) //Mask register read with SRC_DRDY bit
+    {
+        printf(" Data Ready");
+        reg_sts = MMA845x::readRegister(STATUS);    //REG 0x00
+        reg_data[0] = MMA845x::readRegister(OUT_X_MSB);    //REG 0x01
+        reg_data[1] = MMA845x::readRegister(OUT_Y_MSB);    //REG 0x03
+        reg_data[2] = MMA845x::readRegister(OUT_Z_MSB);    //REG 0x05
+        printf(" STATUS: 0x%02X X: %d Y: %d Z: %d\n\r", reg_sts, reg_data[0], reg_data[1], reg_data[2]);
+    }
+}
+
+void MMA845x::init(void) const
+{
+    uint8_t reg_val = 0;
+    
+    _i2c->frequency(400000);
+    
+    // Reset all registers to POR values
+    MMA845x::writeRegister(CTRL_REG2, 0x40);        //REG 0x2B
+    do{
+        // wait for the reset bit to clear
+        reg_val = MMA845x::readRegister(CTRL_REG2) & 0x40;
+    }while(reg_val);
+    
+    // setup the registers that are common among modes
+    MMA845x::writeRegister(CTRL_REG1, 0xA0);        //REG 0x2A 0x98 = ASLP_RATE: 6.25hz Data Rate: 50hz
+    MMA845x::writeRegister(CTRL_REG2, 0x18);        //REG 0x2B Setup for low-power, no auto-sleep
+    MMA845x::writeRegister(CTRL_REG3, 0x00);        //REG 0x2C No interrupts wake device, active low int, push-pull
+    MMA845x::writeRegister(CTRL_REG4, 0x00);        //REG 0x2D
+    MMA845x::writeRegister(CTRL_REG5, 0xFD);        //REG 0x2E All interrupt sources to INT1
+    
+    MMA845x::writeRegister(XYZ_DATA_CFG, 0x11);      //REG 0x0E HPF / scale +/-2,4,8g
+    MMA845x::writeRegister(HP_FILTER_CUTOFF, 0x00);  //REG 0x0F HPF settings
+    
+    return;
+}
+
+void MMA845x::enableDataReadyMode(void) const
+{
+    MMA845x::init();
+    //MMA845x::writeRegister(SYSMOD, 0x01);        //REG 0x0B This register is read only
+    //MMA845x::writeRegister(INT_SOURCE, 0x01);    //REG 0x0C This register is read only
+    MMA845x::writeRegister(CTRL_REG4, 0x09);        //REG 0x2D Enable data ready interrupt
+    
+    
+    
+    //MMA845x::writeRegister(CTRL_REG1, 0xA3);        //REG 0x2A 0xA3 = ASLP_RATE: 6.25hz Data Rate: 50hz, Fast Read, Active mode
+    
+    MMA845x::writeRegister(XYZ_DATA_CFG, 0x11);      //REG 0x0E HPF / scale +/-2,4,8g - Enable HPF
+    MMA845x::writeRegister(HP_FILTER_CUTOFF, 0x10);  //REG 0x0F HPF settings - HPF for pulse on, 0.25Hz cutoff for 12.5rate
+    
+    
+    MMA845x::writeRegister(PULSE_CFG, 0x41);        //REG 0x21 Setup single pulse in x axis
+    MMA845x::writeRegister(PULSE_THSX, 0x09);        //REG 0x21 Setup pulse threshold in x axis
+    MMA845x::writeRegister(PULSE_TMLT, 0x14);        //REG 0x21 Setup single pulse in x axis
+    MMA845x::writeRegister(PULSE_LTCY, 0x04);        //REG 0x21 Setup single latency in x axis
+    
+    
+    MMA845x::writeRegister(CTRL_REG1, 0xA1);        //REG 0x2A 0x98 = ASLP_RATE: 6.25hz Data Rate: 12.5hz, Normal Read, Active mode
+    
+}
+
+void MMA845x::enableMotionMode(void) const
+{
+    MMA845x::init();
+    
+    MMA845x::writeRegister(CTRL_REG4, 0x04);        //REG 0x2D Enable pulse interrupt
+        
+    MMA845x::writeRegister(XYZ_DATA_CFG, 0xF1);      //REG 0x0E HPF / scale +/-4g, Enable HPF for output data
+    MMA845x::writeRegister(HP_FILTER_CUTOFF, 0x00);  //REG 0x0F HPF settings - HPF for pulse on, 4Hz cutoff for 100Hz rate
+    
+    MMA845x::writeRegister(FF_MT_CFG, 0xC8);        //REG 0x21 Setup 
+    MMA845x::writeRegister(FF_MT_THS, 0x01);        //REG 0x21 Setup 
+    MMA845x::writeRegister(FF_MT_COUNT, 0x5);        //REG 0x21 Setup 
+    
+    MMA845x::writeRegister(CTRL_REG2, 0x03);        //REG 0x2B Setup for low power mode, no auto-sleep
+    MMA845x::writeRegister(CTRL_REG1, 0xA1);        //REG 0x2A 0x98 = ASLP_RATE: 6.25hz Data Rate: 12.5Hz, Normal Read, Active mode
+    
+}
+
+void MMA845x::enablePulseMode(void) const
+{
+    MMA845x::init();
+    
+    MMA845x::writeRegister(CTRL_REG4, 0x08);        //REG 0x2D Enable pulse interrupt
+        
+    MMA845x::writeRegister(XYZ_DATA_CFG, 0xF1);      //REG 0x0E HPF / scale +/-2,4,8g - Enable HPF
+    MMA845x::writeRegister(HP_FILTER_CUTOFF, 0x00);  //REG 0x0F HPF settings - HPF for pulse on, 4Hz cutoff for 100Hz rate
+    
+    MMA845x::writeRegister(PULSE_CFG, 0x50);        //REG 0x21 Setup single pulse in z axis
+    MMA845x::writeRegister(PULSE_THSX, 0x06);        //REG 0x21 Setup pulse threshold in x axis
+    MMA845x::writeRegister(PULSE_THSZ, 0x2F);        //REG 0x21 Setup pulse threshold in z axis
+    MMA845x::writeRegister(PULSE_TMLT, 0x28);        //REG 0x21 Setup single pulse
+    MMA845x::writeRegister(PULSE_LTCY, 0x0D);        //REG 0x21 Setup single latency
+    MMA845x::writeRegister(PULSE_WIND, 0x2D);        //REG 0x21 Setup double pulse window
+    
+    MMA845x::writeRegister(CTRL_REG2, 0x00);        //REG 0x2B Setup for normal power mode, no auto-sleep
+    MMA845x::writeRegister(CTRL_REG1, 0x99);        //REG 0x2A 0x98 = ASLP_RATE: 6.25hz Data Rate: 100Hz, Normal Read, Active mode
+    
+}
+
+void MMA845x::enableOrientationMode(void) const
+{
+    uint16_t who_am_i = MMA845x::readRegister(WHO_AM_I);
+    if(who_am_i != MMA8451)
+    {
+        error("%s %d: Feature not compatible with the connected device.\n", __FILE__, __LINE__);
+    }
+    
+    return;
+}
+
+void MMA845x::enableTransitMode(void) const{}
+void MMA845x::enableAutoSleepMode(void) const{}
+
+void MMA845x::enableFIFOMode(void) const
+{
+    uint16_t who_am_i = MMA845x::readRegister(WHO_AM_I);
+    if(who_am_i != MMA8451)
+    {
+        error("%s %d: Feature not compatible with the connected device.\n", __FILE__, __LINE__);
+    }
+    
+    //MMA845x::writeRegister(
+    
+    return;
+}
+
+uint16_t MMA845x::getX(void) const
+{
+    return _data._x;
+}
+    
+uint16_t MMA845x::getY(void) const
+{
+    return _data._y;
+}
+
+uint16_t MMA845x::getZ(void) const
+{
+    return _data._z;
+}
+    
+MMA845x_DATA MMA845x::getXYZ(void) const
+{
+    return _data;
+}
+
+void MMA845x::writeRegister(uint8_t const reg, uint8_t const data) const
+{
+    char buf[2] = {reg, data};
+    uint8_t result = 0;
+    
+    /*
+    __disable_irq(); // Tickers and other timebase events can jack up the I2C bus for some devices
+    result = _i2c->write(_i2c_addr, buf, 2);
+    __enable_irq();  // Just need to block during the transaction
+    */
+
+    result = _i2c->write(_i2c_addr, (const char *)&buf, 2, false);
+    
+    if(0 != result)
+    {
+        error("%s %d: I2c write failed\n", __FILE__, __LINE__);
+    }
+    
+    return;
+}
+
+uint8_t MMA845x::readRegister(uint8_t const reg) const
+{
+    uint8_t result = 1, data = 0;
+    /*
+    __disable_irq(); // Tickers and other timebase events can jack up the I2C bus
+    _i2c->start();
+    result &= _i2c->write(_i2c_addr);
+    result &= _i2c->write(reg);
+    // issue a repeated start...
+    _i2c->start();
+    result &= _i2c->write(_i2c_addr | 0x01);
+    // read with nak
+    data = _i2c->read(0);
+    _i2c->stop();
+    __enable_irq();  // Just need to block during the transaction
+    */
+    
+    result &= _i2c->write(_i2c_addr, (const char *)&reg, 1, true);
+    result &= _i2c->read(_i2c_addr, (char *)&data, 1);
+    
+    if(1 != result)
+    {
+        //error("%s %d: I2C read failed\n", __FILE__, __LINE__);
+    }
+    
+    return data;
+}
+
+void MMA845x::registerDump(void) const
+{
+    uint8_t reg_val = 0;
+    printf("Starting register dump...\n\r");
+    
+    for(int i=0; i<0x31; i++)
+    {
+        reg_val = MMA845x::readRegister(i);
+        printf("Reg 0x%02x: 0x%02x \n\r", i, reg_val);
+    }
+    
+    return;
+}
+