Engduino v1.0
EngduinoAccelerometer.cpp
Go to the documentation of this file.
00001 /**
00002 * \addtogroup EngduinoAccelerometer
00003 *
00004 * This is the driver code for Accelerometer on the Engduino
00005 * In v1.0 this accelerometer is a freescale MMA8652
00006 *
00007 * @{
00008 */
00009 
00010 /**
00011 * \file 
00012 *               Engduino accelerometer driver
00013 * \author
00014 *               Engduino team: support@engduino.org
00015 */
00016 
00017 #include "pins_arduino.h"
00018 #include "../Wire/Wire.h"
00019 #include "EngduinoAccelerometer.h"
00020 
00021 /*---------------------------------------------------------------------------*/
00022 /**
00023 * \brief Constructor
00024 * 
00025 * C++ constructor for this class. Empty.
00026 */
00027 EngduinoAccelerometerClass::EngduinoAccelerometerClass()
00028 {
00029 }
00030 
00031 /*---------------------------------------------------------------------------*/
00032 /**
00033 * \brief begin function - must be called before using other functions
00034 *
00035 * This function enables the accelerometer.
00036 * The accelerometer is an I2C device so we initialise the I2C communications,
00037 * make contact with the accelerometer, and check that it's what we think it is.
00038 *
00039 * We set the accelerometer to its 2G range, and don't use a FIFO. Other options
00040 * are possible, but will need to be implemented in this driver.
00041 * 
00042 */
00043 void EngduinoAccelerometerClass::begin() 
00044 {       uint8_t reg;
00045 
00046         // Join I2C bus as master
00047         //
00048         Wire.begin();
00049         
00050         // Check to see that the device is there
00051         //
00052         Wire.beginTransmission(MMA865x_IIC_ADDRESS);
00053         int error = Wire.endTransmission();  
00054         if (error != 0) {
00055                 Serial.println("Error: I2C device not found");
00056                 return;
00057         }
00058         
00059         // Check that it's the device we think it is
00060         //
00061         readReg(MMA865x_WHO_AM_I, &reg);
00062         if (reg != 0x5A)  {
00063                 Serial.println("Error: Not an MMA8652");
00064                 return;
00065         }
00066         
00067         // Set up the parameters we'd like to have
00068         // +-2g and 50Hz
00069         //
00070         standby();              // Stop the accelerometer
00071 
00072         // Set to 2g
00073         readReg(MMA865x_XYZ_DATA_CFG, &reg);
00074         reg &= ~FS_MASK;
00075         reg |= FULL_SCALE_2G;
00076         writeReg(MMA865x_XYZ_DATA_CFG, &reg);
00077         
00078         // And 50Hz data rate
00079         readReg(MMA865x_CTRL_REG1, &reg);
00080         reg &= ~DR_MASK;
00081         reg |= DATA_RATE_50HZ;
00082         writeReg(MMA865x_CTRL_REG1, &reg);
00083         
00084         activate();             // And start it again
00085 }
00086 
00087 /*---------------------------------------------------------------------------*/
00088 /**
00089 * \brief end function - switch off the button
00090 *
00091 * Send the accelerometer to sleep
00092 *
00093 */
00094 void EngduinoAccelerometerClass::end() 
00095 {
00096         standby();              // Stop the accelerometer
00097 }
00098 
00099 
00100 /*---------------------------------------------------------------------------*/
00101 /**
00102 * \brief Read the xyz values in g from the accelerometer
00103 * \param buf A buffer of floats to put the accelerometer values in g into
00104 *
00105 * Get the instantaneous accelerometer values for the xyz axes. Convert the
00106 * 12 bit digital value to a float value that is expressed in g. 
00107 *
00108 */
00109 void EngduinoAccelerometerClass::xyz(float buf[3])
00110 {       uint8_t reg[6];
00111         
00112         // Check to see if XYZ data is ready to read
00113         readReg(MMA865x_STATUS_00, reg);
00114         if (reg[0] & ZYXDR_MASK != 0)  {
00115                 
00116                 // Do a multiple read starting with X_MSB
00117                 // because this is the first numbered
00118                 // Read all the MSBs and LSBs = 6 registers
00119                 //
00120                 readReg(MMA865x_OUT_X_MSB, reg, 6);
00121                 
00122                 // Now convert the value to g.
00123                 // At 2g full scale, 1g = 1024 counts
00124                 // The most significant 8 bits are stored
00125                 // in the MSB register, the other 4 bits
00126                 // are in the top of the LSB register, making
00127                 // the number a factor of 16 too big. The
00128                 // complete 12 bit number is stored as
00129                 // 2's complement
00130                 // 
00131                 for (int i = 0; i < 3; i++) {
00132                         float f = (reg[2*i] << 8) + reg[2*i+1];
00133                         f = f / (16 * 1024);    // Put the number into the right range
00134                         buf[i] = f;
00135                 }
00136                 
00137                 // TODO: Could take the cailbration (offset)
00138                 // registers into account
00139                 //
00140         }
00141 }
00142 
00143 /*---------------------------------------------------------------------------*/
00144 /**
00145 * \brief Read the raw xyz values from the accelerometer
00146 * \param buf A buffer of uint16s to hold the 12 bit raw accelerometer values
00147 *
00148 * Get the instantaneous accelerometer values for the xyz axes. We return the
00149 * raw values without converting them into g. To convert to g, if we are using
00150 * a 2G scale, then simply divide by 16384
00151 *
00152 */
00153 void EngduinoAccelerometerClass::xyzRaw(uint16_t buf[3])
00154 {       uint8_t reg[6];
00155         
00156         // Check to see if XYZ data is ready to read
00157         readReg(MMA865x_STATUS_00, reg);
00158         if (reg[0] & ZYXDR_MASK != 0)  {
00159                 
00160                 // Do a multiple read starting with X_MSB
00161                 // because this is the first numbered
00162                 // Read all the MSBs and LSBs = 6 registers
00163                 //
00164                 readReg(MMA865x_OUT_X_MSB, reg, 6);
00165                 
00166                 // Just return raw values
00167                 //
00168                 for (int i = 0; i < 3; i++)
00169                         buf[i] = (reg[2*i] << 8) + reg[2*i+1];
00170                 
00171                 // TODO: Could take the cailbration (offset)
00172                 // registers into account
00173                 //
00174         }
00175 }
00176 
00177 /*---------------------------------------------------------------------------*/
00178 /**
00179 * \brief Activate the sensor
00180 *
00181 * Set the Active bit in System Control Register 1
00182 *
00183 */
00184 void EngduinoAccelerometerClass::activate()
00185 {       uint8_t reg;
00186 
00187         readReg(MMA865x_CTRL_REG1,      &reg);
00188         reg |= ACTIVE_MASK;
00189         writeReg(MMA865x_CTRL_REG1, &reg);
00190 }
00191 
00192 
00193 /*---------------------------------------------------------------------------*/
00194 /**
00195 * \brief Put sensor into standby mode
00196 *
00197 * Clear the Active bit in System Control Register 1
00198 *
00199 */
00200 void EngduinoAccelerometerClass::standby()
00201 {       uint8_t reg;
00202 
00203         readReg(MMA865x_CTRL_REG1,      &reg);
00204         reg &= ~ACTIVE_MASK;
00205         writeReg(MMA865x_CTRL_REG1, &reg);
00206 }
00207 
00208 
00209 /*---------------------------------------------------------------------------*/
00210 /**
00211 * \brief Internal routine to write accelerometer registers
00212 * \param firstReg The first register to write
00213 * \param buf      The buffer containing things to write to the registers
00214 * \param nRegs    Optional: The number of registers to write - defaults to 1 
00215 *
00216 * Do a multiple register write of the MMA8652 over the I2C bus - where the
00217 * number of registers written might only be one (as it is if the optional
00218 * nRegs parameter is omitted).
00219 *
00220 */
00221 void EngduinoAccelerometerClass::writeReg(int firstReg, const uint8_t *buf, uint8_t nRegs)
00222 {
00223         // Write out the address of the first register, then the set of values
00224         // for that and all subsequent registers. Release the I2C bus when we're done
00225         //
00226         Wire.beginTransmission(MMA865x_IIC_ADDRESS);
00227         Wire.write(firstReg);
00228         Wire.write(buf, nRegs);
00229         Wire.endTransmission();
00230 }
00231 
00232 /*---------------------------------------------------------------------------*/
00233 /**
00234 * \brief Internal routine to read accelerometer registers
00235 * \param firstReg The first register to read
00236 * \param buf      The buffer to which to read from the registers
00237 * \param nRegs    Optional: The number of registers to read - defaults to 1 
00238 *
00239 * Do a multiple register read of the MMA8652 over the I2C bus - where the
00240 * number of registers read might only be one (as it is if the optional
00241 * nRegs parameter is omitted).
00242 *
00243 */
00244 void EngduinoAccelerometerClass::readReg(int firstReg, uint8_t *buf, uint8_t nRegs)
00245 {
00246         // Write out the register we'd like to start with reading
00247         // Hold the I2C bus since we're going to read values back
00248         //
00249         Wire.beginTransmission(MMA865x_IIC_ADDRESS);
00250         Wire.write(firstReg);
00251         Wire.endTransmission(false); 
00252 
00253         // Read all the registers we're interested in,
00254         // but release the I2C bus when we're done.
00255         // This is determined by the default third
00256         // parameter to requestFrom
00257         //
00258         Wire.requestFrom((uint8_t)MMA865x_IIC_ADDRESS, nRegs);
00259 
00260         int i = 0;
00261         while (Wire.available() && i < nRegs)
00262                 buf[i++] = Wire.read();
00263 }
00264 
00265 
00266 /*---------------------------------------------------------------------------*/
00267 /*
00268  * Preinstantiate Objects
00269  */ 
00270 EngduinoAccelerometerClass EngduinoAccelerometer = EngduinoAccelerometerClass();
00271 
00272 /** @} */