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 *)®, 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; }