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
Diff: MMA845x.cpp
- Revision:
- 0:6f07db1b8cdc
diff -r 000000000000 -r 6f07db1b8cdc MMA845x.cpp --- /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 *)®, 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; +} +