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

MMA845x.cpp

Committer:
dcnichols
Date:
2015-07-15
Revision:
0:6f07db1b8cdc

File content as of revision 0:6f07db1b8cdc:

/**
 * @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;
}