fork

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit

Fork of microbit-dal by Lancaster University

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MicroBitAccelerometer.cpp Source File

MicroBitAccelerometer.cpp

00001 /*
00002 The MIT License (MIT)
00003 
00004 Copyright (c) 2016 British Broadcasting Corporation.
00005 This software is provided by Lancaster University by arrangement with the BBC.
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a
00008 copy of this software and associated documentation files (the "Software"),
00009 to deal in the Software without restriction, including without limitation
00010 the rights to use, copy, modify, merge, publish, distribute, sublicense,
00011 and/or sell copies of the Software, and to permit persons to whom the
00012 Software is furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00020 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00022 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00023 DEALINGS IN THE SOFTWARE.
00024 */
00025 
00026 /**
00027  * Class definition for MicroBit Accelerometer.
00028  *
00029  * Represents an implementation of the Freescale MMA8653 3 axis accelerometer
00030  * Also includes basic data caching and on demand activation.
00031  */
00032 #include "MicroBitConfig.h"
00033 #include "MicroBitAccelerometer.h"
00034 #include "ErrorNo.h"
00035 #include "MicroBitConfig.h"
00036 #include "MicroBitEvent.h"
00037 #include "MicroBitCompat.h"
00038 #include "MicroBitFiber.h"
00039 
00040 /**
00041   * Configures the accelerometer for G range and sample rate defined
00042   * in this object. The nearest values are chosen to those defined
00043   * that are supported by the hardware. The instance variables are then
00044   * updated to reflect reality.
00045   *
00046   * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the accelerometer could not be configured.
00047   */
00048 int MicroBitAccelerometer::configure()
00049 {
00050     const MMA8653SampleRangeConfig  *actualSampleRange;
00051     const MMA8653SampleRateConfig  *actualSampleRate;
00052     int result;
00053 
00054     // First find the nearest sample rate to that specified.
00055     actualSampleRate = &MMA8653SampleRate[MMA8653_SAMPLE_RATES-1];
00056     for (int i=MMA8653_SAMPLE_RATES-1; i>=0; i--)
00057     {
00058         if(MMA8653SampleRate[i].sample_period < this->samplePeriod * 1000)
00059             break;
00060 
00061         actualSampleRate = &MMA8653SampleRate[i];
00062     }
00063 
00064     // Now find the nearest sample range to that specified.
00065     actualSampleRange = &MMA8653SampleRange[MMA8653_SAMPLE_RANGES-1];
00066     for (int i=MMA8653_SAMPLE_RANGES-1; i>=0; i--)
00067     {
00068         if(MMA8653SampleRange[i].sample_range < this->sampleRange)
00069             break;
00070 
00071         actualSampleRange = &MMA8653SampleRange[i];
00072     }
00073 
00074     // OK, we have the correct data. Update our local state.
00075     this->samplePeriod = actualSampleRate->sample_period / 1000;
00076     this->sampleRange = actualSampleRange->sample_range;
00077 
00078     // Now configure the accelerometer accordingly.
00079     // First place the device into standby mode, so it can be configured.
00080     result = writeCommand(MMA8653_CTRL_REG1, 0x00);
00081     if (result != 0)
00082         return MICROBIT_I2C_ERROR;
00083 
00084     // Enable high precisiosn mode. This consumes a bit more power, but still only 184 uA!
00085     result = writeCommand(MMA8653_CTRL_REG2, 0x10);
00086     if (result != 0)
00087         return MICROBIT_I2C_ERROR;
00088 
00089     // Enable the INT1 interrupt pin.
00090     result = writeCommand(MMA8653_CTRL_REG4, 0x01);
00091     if (result != 0)
00092         return MICROBIT_I2C_ERROR;
00093 
00094     // Select the DATA_READY event source to be routed to INT1
00095     result = writeCommand(MMA8653_CTRL_REG5, 0x01);
00096     if (result != 0)
00097         return MICROBIT_I2C_ERROR;
00098 
00099     // Configure for the selected g range.
00100     result = writeCommand(MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg);
00101     if (result != 0)
00102         return MICROBIT_I2C_ERROR;
00103 
00104     // Bring the device back online, with 10bit wide samples at the requested frequency.
00105     result = writeCommand(MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
00106     if (result != 0)
00107         return MICROBIT_I2C_ERROR;
00108 
00109     return MICROBIT_OK;
00110 }
00111 
00112 /**
00113   * Issues a standard, 2 byte I2C command write to the accelerometer.
00114   *
00115   * Blocks the calling thread until complete.
00116   *
00117   * @param reg The address of the register to write to.
00118   *
00119   * @param value The value to write.
00120   *
00121   * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
00122   */
00123 int MicroBitAccelerometer::writeCommand(uint8_t reg, uint8_t value)
00124 {
00125     uint8_t command[2];
00126     command[0] = reg;
00127     command[1] = value;
00128 
00129     return i2c.write(address, (const char *)command, 2);
00130 }
00131 
00132 /**
00133   * Issues a read command, copying data into the specified buffer.
00134   *
00135   * Blocks the calling thread until complete.
00136   *
00137   * @param reg The address of the register to access.
00138   *
00139   * @param buffer Memory area to read the data into.
00140   *
00141   * @param length The number of bytes to read.
00142   *
00143   * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
00144   */
00145 int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length)
00146 {
00147     int result;
00148 
00149     if (buffer == NULL || length <= 0 )
00150         return MICROBIT_INVALID_PARAMETER;
00151 
00152     result = i2c.write(address, (const char *)&reg, 1, true);
00153     if (result !=0)
00154         return MICROBIT_I2C_ERROR;
00155 
00156     result = i2c.read(address, (char *)buffer, length);
00157     if (result !=0)
00158         return MICROBIT_I2C_ERROR;
00159 
00160     return MICROBIT_OK;
00161 }
00162 
00163 /**
00164   * Constructor.
00165   * Create a software abstraction of an accelerometer.
00166   *
00167   * @param _i2c an instance of MicroBitI2C used to communicate with the onboard accelerometer.
00168   *
00169   * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR.
00170   *
00171   * @param id the unique EventModel id of this component. Defaults to: MICROBIT_ID_ACCELEROMETER
00172   *
00173   * @code
00174   * MicroBitI2C i2c = MicroBitI2C(I2C_SDA0, I2C_SCL0);
00175   *
00176   * MicroBitAccelerometer accelerometer = MicroBitAccelerometer(i2c);
00177   * @endcode
00178  */
00179 MicroBitAccelerometer::MicroBitAccelerometer(MicroBitI2C& _i2c, uint16_t address, uint16_t id) : sample(), int1(MICROBIT_PIN_ACCEL_DATA_READY), i2c(_i2c)
00180 {
00181     // Store our identifiers.
00182     this->id = id;
00183     this->status = 0;
00184     this->address = address;
00185 
00186     // Update our internal state for 50Hz at +/- 2g (50Hz has a period af 20ms).
00187     this->samplePeriod = 20;
00188     this->sampleRange = 2;
00189 
00190     // Initialise gesture history
00191     this->sigma = 0;
00192     this->lastGesture = GESTURE_NONE;
00193     this->currentGesture = GESTURE_NONE;
00194     this->shake.x = 0;
00195     this->shake.y = 0;
00196     this->shake.z = 0;
00197     this->shake.count = 0;
00198     this->shake.timer = 0;
00199 
00200     // Configure and enable the accelerometer.
00201     if (this->configure() == MICROBIT_OK)
00202         status |= MICROBIT_COMPONENT_RUNNING;
00203 }
00204 
00205 /**
00206   * Attempts to read the 8 bit ID from the accelerometer, this can be used for
00207   * validation purposes.
00208   *
00209   * @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
00210   *
00211   * @code
00212   * accelerometer.whoAmI();
00213   * @endcode
00214   */
00215 int MicroBitAccelerometer::whoAmI()
00216 {
00217     uint8_t data;
00218     int result;
00219 
00220     result = readCommand(MMA8653_WHOAMI, &data, 1);
00221     if (result !=0)
00222         return MICROBIT_I2C_ERROR;
00223 
00224     return (int)data;
00225 }
00226 
00227 /**
00228   * Reads the acceleration data from the accelerometer, and stores it in our buffer.
00229   * This only happens if the accelerometer indicates that it has new data via int1.
00230   *
00231   * On first use, this member function will attempt to add this component to the
00232   * list of fiber components in order to constantly update the values stored
00233   * by this object.
00234   *
00235   * This technique is called lazy instantiation, and it means that we do not
00236   * obtain the overhead from non-chalantly adding this component to fiber components.
00237   *
00238   * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the read request fails.
00239   */
00240 int MicroBitAccelerometer::updateSample()
00241 {
00242     if(!(status & MICROBIT_ACCEL_ADDED_TO_IDLE))
00243     {
00244         fiber_add_idle_component(this);
00245         status |= MICROBIT_ACCEL_ADDED_TO_IDLE;
00246     }
00247 
00248     // Poll interrupt line from accelerometer.
00249     // n.b. Default is Active LO. Interrupt is cleared in data read.
00250     if(!int1)
00251     {
00252         int8_t data[6];
00253         int result;
00254 
00255         result = readCommand(MMA8653_OUT_X_MSB, (uint8_t *)data, 6);
00256         if (result !=0)
00257             return MICROBIT_I2C_ERROR;
00258 
00259         // read MSB values...
00260         sample.x = data[0];
00261         sample.y = data[2];
00262         sample.z = data[4];
00263 
00264         // Normalize the data in the 0..1024 range.
00265         sample.x *= 8;
00266         sample.y *= 8;
00267         sample.z *= 8;
00268 
00269 #if CONFIG_ENABLED(USE_ACCEL_LSB)
00270         // Add in LSB values.
00271         sample.x += (data[1] / 64);
00272         sample.y += (data[3] / 64);
00273         sample.z += (data[5] / 64);
00274 #endif
00275 
00276         // Scale into millig (approx!)
00277         sample.x *= this->sampleRange;
00278         sample.y *= this->sampleRange;
00279         sample.z *= this->sampleRange;
00280 
00281         // Indicate that pitch and roll data is now stale, and needs to be recalculated if needed.
00282         status &= ~MICROBIT_ACCEL_PITCH_ROLL_VALID;
00283 
00284         // Update gesture tracking
00285         updateGesture();
00286 
00287         // Indicate that a new sample is available
00288         MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE);
00289     }
00290 
00291     return MICROBIT_OK;
00292 };
00293 
00294 /**
00295   * A service function.
00296   * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2).
00297   * It does not, however, square root the result, as this is a relatively high cost operation.
00298   *
00299   * This is left to application code should it be needed.
00300   *
00301   * @return the sum of the square of the acceleration of the device across all axes.
00302   */
00303 int MicroBitAccelerometer::instantaneousAccelerationSquared()
00304 {
00305     updateSample();
00306 
00307     // Use pythagoras theorem to determine the combined force acting on the device.
00308     return (int)sample.x*(int)sample.x + (int)sample.y*(int)sample.y + (int)sample.z*(int)sample.z;
00309 }
00310 
00311 /**
00312  * Service function.
00313  * Determines a 'best guess' posture of the device based on instantaneous data.
00314  *
00315  * This makes no use of historic data, and forms this input to the filter implemented in updateGesture().
00316  *
00317  * @return A 'best guess' of the current posture of the device, based on instanataneous data.
00318  */
00319 BasicGesture MicroBitAccelerometer::instantaneousPosture()
00320 {
00321     int force = instantaneousAccelerationSquared();
00322     bool shakeDetected = false;
00323 
00324     // Test for shake events.
00325     // We detect a shake by measuring zero crossings in each axis. In other words, if we see a strong acceleration to the left followed by
00326     // a string acceleration to the right, then we can infer a shake. Similarly, we can do this for each acxis (left/right, up/down, in/out).
00327     //
00328     // If we see enough zero crossings in succession (MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the device
00329     // has been shaken.
00330     if ((getX() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || (getX() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.x))
00331     {
00332         shakeDetected = true;
00333         shake.x = !shake.x;
00334     }
00335 
00336     if ((getY() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.y) || (getY() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.y))
00337     {
00338         shakeDetected = true;
00339         shake.y = !shake.y;
00340     }
00341 
00342     if ((getZ() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.z) || (getZ() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.z))
00343     {
00344         shakeDetected = true;
00345         shake.z = !shake.z;
00346     }
00347 
00348     if (shakeDetected && shake.count < MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD && ++shake.count == MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD)
00349         shake.shaken = 1;
00350 
00351     if (++shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_DAMPING)
00352     {
00353         shake.timer = 0;
00354         if (shake.count > 0)
00355         {
00356             if(--shake.count == 0)
00357                 shake.shaken = 0;
00358         }
00359     }
00360 
00361     if (shake.shaken)
00362         return GESTURE_SHAKE;
00363 
00364     if (force < MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD)
00365         return GESTURE_FREEFALL;
00366 
00367     if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD)
00368         return GESTURE_3G;
00369 
00370     if (force > MICROBIT_ACCELEROMETER_6G_THRESHOLD)
00371         return GESTURE_6G;
00372 
00373     if (force > MICROBIT_ACCELEROMETER_8G_THRESHOLD)
00374         return GESTURE_8G;
00375 
00376     // Determine our posture.
00377     if (getX() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00378         return GESTURE_LEFT;
00379 
00380     if (getX() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00381         return GESTURE_RIGHT;
00382 
00383     if (getY() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00384         return GESTURE_DOWN;
00385 
00386     if (getY() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00387         return GESTURE_UP;
00388 
00389     if (getZ() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00390         return GESTURE_FACE_UP;
00391 
00392     if (getZ() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00393         return GESTURE_FACE_DOWN;
00394 
00395     return GESTURE_NONE;
00396 }
00397 
00398 /**
00399   * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote
00400   * stability.
00401   */
00402 void MicroBitAccelerometer::updateGesture()
00403 {
00404     // Determine what it looks like we're doing based on the latest sample...
00405     BasicGesture g = instantaneousPosture();
00406 
00407     // Perform some low pass filtering to reduce jitter from any detected effects
00408     if (g == currentGesture)
00409     {
00410         if (sigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
00411             sigma++;
00412     }
00413     else
00414     {
00415         currentGesture = g;
00416         sigma = 0;
00417     }
00418 
00419     // If we've reached threshold, update our record and raise the relevant event...
00420     if (currentGesture != lastGesture && sigma >= MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
00421     {
00422         lastGesture = currentGesture;
00423         MicroBitEvent e(MICROBIT_ID_GESTURE, lastGesture);
00424     }
00425 }
00426 
00427 /**
00428   * Attempts to set the sample rate of the accelerometer to the specified value (in ms).
00429   *
00430   * @param period the requested time between samples, in milliseconds.
00431   *
00432   * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
00433   *
00434   * @code
00435   * // sample rate is now 20 ms.
00436   * accelerometer.setPeriod(20);
00437   * @endcode
00438   *
00439   * @note The requested rate may not be possible on the hardware. In this case, the
00440   * nearest lower rate is chosen.
00441   */
00442 int MicroBitAccelerometer::setPeriod(int period)
00443 {
00444     this->samplePeriod = period;
00445     return this->configure();
00446 }
00447 
00448 /**
00449   * Reads the currently configured sample rate of the accelerometer.
00450   *
00451   * @return The time between samples, in milliseconds.
00452   */
00453 int MicroBitAccelerometer::getPeriod()
00454 {
00455     return (int)samplePeriod;
00456 }
00457 
00458 /**
00459   * Attempts to set the sample range of the accelerometer to the specified value (in g).
00460   *
00461   * @param range The requested sample range of samples, in g.
00462   *
00463   * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
00464   *
00465   * @code
00466   * // the sample range of the accelerometer is now 8G.
00467   * accelerometer.setRange(8);
00468   * @endcode
00469   *
00470   * @note The requested range may not be possible on the hardware. In this case, the
00471   * nearest lower range is chosen.
00472   */
00473 int MicroBitAccelerometer::setRange(int range)
00474 {
00475     this->sampleRange = range;
00476     return this->configure();
00477 }
00478 
00479 /**
00480   * Reads the currently configured sample range of the accelerometer.
00481   *
00482   * @return The sample range, in g.
00483   */
00484 int MicroBitAccelerometer::getRange()
00485 {
00486     return (int)sampleRange;
00487 }
00488 
00489 /**
00490   * Reads the value of the X axis from the latest update retrieved from the accelerometer.
00491   *
00492   * @param system The coordinate system to use. By default, a simple cartesian system is provided.
00493   *
00494   * @return The force measured in the X axis, in milli-g.
00495   *
00496   * @code
00497   * accelerometer.getX();
00498   * @endcode
00499   */
00500 int MicroBitAccelerometer::getX(MicroBitCoordinateSystem system)
00501 {
00502     updateSample();
00503 
00504     switch (system)
00505     {
00506         case SIMPLE_CARTESIAN:
00507             return -sample.x;
00508 
00509         case NORTH_EAST_DOWN:
00510             return sample.y;
00511 
00512         case RAW:
00513         default:
00514             return sample.x;
00515     }
00516 }
00517 
00518 /**
00519   * Reads the value of the Y axis from the latest update retrieved from the accelerometer.
00520   *
00521   * @return The force measured in the Y axis, in milli-g.
00522   *
00523   * @code
00524   * accelerometer.getY();
00525   * @endcode
00526   */
00527 int MicroBitAccelerometer::getY(MicroBitCoordinateSystem system)
00528 {
00529     updateSample();
00530 
00531     switch (system)
00532     {
00533         case SIMPLE_CARTESIAN:
00534             return -sample.y;
00535 
00536         case NORTH_EAST_DOWN:
00537             return -sample.x;
00538 
00539         case RAW:
00540         default:
00541             return sample.y;
00542     }
00543 }
00544 
00545 /**
00546   * Reads the value of the Z axis from the latest update retrieved from the accelerometer.
00547   *
00548   * @return The force measured in the Z axis, in milli-g.
00549   *
00550   * @code
00551   * accelerometer.getZ();
00552   * @endcode
00553   */
00554 int MicroBitAccelerometer::getZ(MicroBitCoordinateSystem system)
00555 {
00556     updateSample();
00557 
00558     switch (system)
00559     {
00560         case NORTH_EAST_DOWN:
00561             return -sample.z;
00562 
00563         case SIMPLE_CARTESIAN:
00564         case RAW:
00565         default:
00566             return sample.z;
00567     }
00568 }
00569 
00570 /**
00571   * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
00572   *
00573   * @return The pitch of the device, in degrees.
00574   *
00575   * @code
00576   * accelerometer.getPitch();
00577   * @endcode
00578   */
00579 int MicroBitAccelerometer::getPitch()
00580 {
00581     return (int) ((360*getPitchRadians()) / (2*PI));
00582 }
00583 
00584 /**
00585   * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
00586   *
00587   * @return The pitch of the device, in radians.
00588   *
00589   * @code
00590   * accelerometer.getPitchRadians();
00591   * @endcode
00592   */
00593 float MicroBitAccelerometer::getPitchRadians()
00594 {
00595     if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
00596         recalculatePitchRoll();
00597 
00598     return pitch;
00599 }
00600 
00601 /**
00602   * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
00603   *
00604   * @return The roll of the device, in degrees.
00605   *
00606   * @code
00607   * accelerometer.getRoll();
00608   * @endcode
00609   */
00610 int MicroBitAccelerometer::getRoll()
00611 {
00612     return (int) ((360*getRollRadians()) / (2*PI));
00613 }
00614 
00615 /**
00616   * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
00617   *
00618   * @return The roll of the device, in radians.
00619   *
00620   * @code
00621   * accelerometer.getRollRadians();
00622   * @endcode
00623   */
00624 float MicroBitAccelerometer::getRollRadians()
00625 {
00626     if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
00627         recalculatePitchRoll();
00628 
00629     return roll;
00630 }
00631 
00632 /**
00633   * Recalculate roll and pitch values for the current sample.
00634   *
00635   * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather
00636   *       heavyweight for a CPU without a floating point unit.
00637   */
00638 void MicroBitAccelerometer::recalculatePitchRoll()
00639 {
00640     float x = (float) getX(NORTH_EAST_DOWN);
00641     float y = (float) getY(NORTH_EAST_DOWN);
00642     float z = (float) getZ(NORTH_EAST_DOWN);
00643 
00644     roll = atan2((double)getY(NORTH_EAST_DOWN), (double)getZ(NORTH_EAST_DOWN));
00645 
00646     pitch = atan(-x / (y*sin(roll) + z*cos(roll)));
00647     status |= MICROBIT_ACCEL_PITCH_ROLL_VALID;
00648 }
00649 
00650 /**
00651   * Retrieves the last recorded gesture.
00652   *
00653   * @return The last gesture that was detected.
00654   *
00655   * Example:
00656   * @code
00657   * MicroBitDisplay display;
00658   *
00659   * if (accelerometer.getGesture() == SHAKE)
00660   *     display.scroll("SHAKE!");
00661   * @endcode
00662   */
00663 BasicGesture MicroBitAccelerometer::getGesture()
00664 {
00665     return lastGesture;
00666 }
00667 
00668 /**
00669   * A periodic callback invoked by the fiber scheduler idle thread.
00670   *
00671   * Internally calls updateSample().
00672   */
00673 void MicroBitAccelerometer::idleTick()
00674 {
00675     updateSample();
00676 }
00677 
00678 /**
00679   * Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
00680   *
00681   * We check if any data is ready for reading by checking the interrupt flag on the accelerometer.
00682   */
00683 int MicroBitAccelerometer::isIdleCallbackNeeded()
00684 {
00685     return !int1;
00686 }
00687 
00688 /**
00689   * Destructor for MicroBitAccelerometer, where we deregister from the array of fiber components.
00690   */
00691 MicroBitAccelerometer::~MicroBitAccelerometer()
00692 {
00693     fiber_remove_idle_component(this);
00694 }
00695 
00696 const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = {
00697     {2, 0},
00698     {4, 1},
00699     {8, 2}
00700 };
00701 
00702 const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = {
00703     {1250,      0x00},
00704     {2500,      0x08},
00705     {5000,      0x10},
00706     {10000,     0x18},
00707     {20000,     0x20},
00708     {80000,     0x28},
00709     {160000,    0x30},
00710     {640000,    0x38}
00711 };