mbed.org local branch of microbit-dal. The real version lives in git at https://github.com/lancaster-university/microbit-dal

Dependencies:   BLE_API nRF51822 mbed-dev-bin

Dependents:   microbit Microbit IoTChallenge1 microbit ... more

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->impulseSigma = 0;
00193     this->lastGesture = MICROBIT_ACCELEROMETER_EVT_NONE;
00194     this->currentGesture = MICROBIT_ACCELEROMETER_EVT_NONE;
00195     this->shake.x = 0;
00196     this->shake.y = 0;
00197     this->shake.z = 0;
00198     this->shake.count = 0;
00199     this->shake.timer = 0;
00200     this->shake.impulse_3 = 1;
00201     this->shake.impulse_6 = 1;
00202     this->shake.impulse_8 = 1;
00203 
00204     // Configure and enable the accelerometer.
00205     if (this->configure() == MICROBIT_OK)
00206         status |= MICROBIT_COMPONENT_RUNNING;
00207 }
00208 
00209 /**
00210   * Attempts to read the 8 bit ID from the accelerometer, this can be used for
00211   * validation purposes.
00212   *
00213   * @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
00214   *
00215   * @code
00216   * accelerometer.whoAmI();
00217   * @endcode
00218   */
00219 int MicroBitAccelerometer::whoAmI()
00220 {
00221     uint8_t data;
00222     int result;
00223 
00224     result = readCommand(MMA8653_WHOAMI, &data, 1);
00225     if (result !=0)
00226         return MICROBIT_I2C_ERROR;
00227 
00228     return (int)data;
00229 }
00230 
00231 /**
00232   * Reads the acceleration data from the accelerometer, and stores it in our buffer.
00233   * This only happens if the accelerometer indicates that it has new data via int1.
00234   *
00235   * On first use, this member function will attempt to add this component to the
00236   * list of fiber components in order to constantly update the values stored
00237   * by this object.
00238   *
00239   * This technique is called lazy instantiation, and it means that we do not
00240   * obtain the overhead from non-chalantly adding this component to fiber components.
00241   *
00242   * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the read request fails.
00243   */
00244 int MicroBitAccelerometer::updateSample()
00245 {
00246     if(!(status & MICROBIT_ACCEL_ADDED_TO_IDLE))
00247     {
00248         fiber_add_idle_component(this);
00249         status |= MICROBIT_ACCEL_ADDED_TO_IDLE;
00250     }
00251 
00252     // Poll interrupt line from accelerometer.
00253     // n.b. Default is Active LO. Interrupt is cleared in data read.
00254     if(!int1)
00255     {
00256         int8_t data[6];
00257         int result;
00258 
00259         result = readCommand(MMA8653_OUT_X_MSB, (uint8_t *)data, 6);
00260         if (result !=0)
00261             return MICROBIT_I2C_ERROR;
00262 
00263         // read MSB values...
00264         sample.x = data[0];
00265         sample.y = data[2];
00266         sample.z = data[4];
00267 
00268         // Normalize the data in the 0..1024 range.
00269         sample.x *= 8;
00270         sample.y *= 8;
00271         sample.z *= 8;
00272 
00273 #if CONFIG_ENABLED(USE_ACCEL_LSB)
00274         // Add in LSB values.
00275         sample.x += (data[1] / 64);
00276         sample.y += (data[3] / 64);
00277         sample.z += (data[5] / 64);
00278 #endif
00279 
00280         // Scale into millig (approx!)
00281         sample.x *= this->sampleRange;
00282         sample.y *= this->sampleRange;
00283         sample.z *= this->sampleRange;
00284 
00285         // Indicate that pitch and roll data is now stale, and needs to be recalculated if needed.
00286         status &= ~MICROBIT_ACCEL_PITCH_ROLL_VALID;
00287 
00288         // Update gesture tracking
00289         updateGesture();
00290 
00291         // Indicate that a new sample is available
00292         MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE);
00293     }
00294 
00295     return MICROBIT_OK;
00296 };
00297 
00298 /**
00299   * A service function.
00300   * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2).
00301   * It does not, however, square root the result, as this is a relatively high cost operation.
00302   *
00303   * This is left to application code should it be needed.
00304   *
00305   * @return the sum of the square of the acceleration of the device across all axes.
00306   */
00307 int MicroBitAccelerometer::instantaneousAccelerationSquared()
00308 {
00309     updateSample();
00310 
00311     // Use pythagoras theorem to determine the combined force acting on the device.
00312     return (int)sample.x*(int)sample.x + (int)sample.y*(int)sample.y + (int)sample.z*(int)sample.z;
00313 }
00314 
00315 /**
00316  * Service function.
00317  * Determines a 'best guess' posture of the device based on instantaneous data.
00318  *
00319  * This makes no use of historic data, and forms the input to the filter implemented in updateGesture().
00320  *
00321  * @return A 'best guess' of the current posture of the device, based on instanataneous data.
00322  */
00323 uint16_t MicroBitAccelerometer::instantaneousPosture()
00324 {
00325     bool shakeDetected = false;
00326 
00327     // Test for shake events.
00328     // 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
00329     // a strong acceleration to the right, then we can infer a shake. Similarly, we can do this for each axis (left/right, up/down, in/out).
00330     //
00331     // If we see enough zero crossings in succession (MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the device
00332     // has been shaken.
00333     if ((getX() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || (getX() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.x))
00334     {
00335         shakeDetected = true;
00336         shake.x = !shake.x;
00337     }
00338 
00339     if ((getY() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.y) || (getY() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.y))
00340     {
00341         shakeDetected = true;
00342         shake.y = !shake.y;
00343     }
00344 
00345     if ((getZ() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.z) || (getZ() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.z))
00346     {
00347         shakeDetected = true;
00348         shake.z = !shake.z;
00349     }
00350 
00351     // If we detected a zero crossing in this sample period, count this.
00352     if (shakeDetected && shake.count < MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD)
00353     {
00354         shake.count++;
00355   
00356         if (shake.count == 1)
00357             shake.timer = 0;
00358 
00359         if (shake.count == MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD)
00360         {
00361             shake.shaken = 1;
00362             shake.timer = 0;
00363             return MICROBIT_ACCELEROMETER_EVT_SHAKE;
00364         }
00365     }
00366 
00367     // measure how long we have been detecting a SHAKE event.
00368     if (shake.count > 0)
00369     {
00370         shake.timer++;
00371 
00372         // If we've issued a SHAKE event already, and sufficient time has assed, allow another SHAKE event to be issued.
00373         if (shake.shaken && shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_RTX)
00374         {
00375             shake.shaken = 0;
00376             shake.timer = 0;
00377             shake.count = 0;
00378         }
00379 
00380         // Decay our count of zero crossings over time. We don't want them to accumulate if the user performs slow moving motions.
00381         else if (!shake.shaken && shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_DAMPING)
00382         {
00383             shake.timer = 0;
00384             if (shake.count > 0)
00385                 shake.count--;
00386         }
00387     }
00388 
00389     if (instantaneousAccelerationSquared() < MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD)
00390         return MICROBIT_ACCELEROMETER_EVT_FREEFALL;
00391 
00392     // Determine our posture.
00393     if (getX() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00394         return MICROBIT_ACCELEROMETER_EVT_TILT_LEFT;
00395 
00396     if (getX() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00397         return MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT;
00398 
00399     if (getY() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00400         return MICROBIT_ACCELEROMETER_EVT_TILT_DOWN;
00401 
00402     if (getY() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00403         return MICROBIT_ACCELEROMETER_EVT_TILT_UP;
00404 
00405     if (getZ() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00406         return MICROBIT_ACCELEROMETER_EVT_FACE_UP;
00407 
00408     if (getZ() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
00409         return MICROBIT_ACCELEROMETER_EVT_FACE_DOWN;
00410 
00411     return MICROBIT_ACCELEROMETER_EVT_NONE;
00412 }
00413 
00414 /**
00415   * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote
00416   * stability.
00417   */
00418 void MicroBitAccelerometer::updateGesture()
00419 {
00420     // Check for High/Low G force events - typically impulses, impacts etc.
00421     // Again, during such spikes, these event take priority of the posture of the device.
00422     // For these events, we don't perform any low pass filtering.
00423     int force = instantaneousAccelerationSquared();
00424 
00425     if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD)
00426     {
00427         if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD && !shake.impulse_3)
00428         {
00429             MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_3G);
00430             shake.impulse_3 = 1;
00431         }
00432         if (force > MICROBIT_ACCELEROMETER_6G_THRESHOLD && !shake.impulse_6)
00433         {
00434             MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_6G);
00435             shake.impulse_6 = 1;
00436         }
00437         if (force > MICROBIT_ACCELEROMETER_8G_THRESHOLD && !shake.impulse_8)
00438         {
00439             MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_8G);
00440             shake.impulse_8 = 1;
00441         }
00442 
00443         impulseSigma = 0;
00444     }
00445 
00446     // Reset the impulse event onve the acceleration has subsided.
00447     if (impulseSigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
00448         impulseSigma++;
00449     else
00450         shake.impulse_3 = shake.impulse_6 = shake.impulse_8 = 0;
00451 
00452 
00453     // Determine what it looks like we're doing based on the latest sample...
00454     uint16_t g = instantaneousPosture();
00455 
00456     if (g == MICROBIT_ACCELEROMETER_EVT_SHAKE)
00457     {
00458         MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_SHAKE);
00459         return;
00460     }
00461 
00462     // Perform some low pass filtering to reduce jitter from any detected effects
00463     if (g == currentGesture)
00464     {
00465         if (sigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
00466             sigma++;
00467     }
00468     else
00469     {
00470         currentGesture = g;
00471         sigma = 0;
00472     }
00473 
00474     // If we've reached threshold, update our record and raise the relevant event...
00475     if (currentGesture != lastGesture && sigma >= MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
00476     {
00477         lastGesture = currentGesture;
00478         MicroBitEvent e(MICROBIT_ID_GESTURE, lastGesture);
00479     }
00480 }
00481 
00482 /**
00483   * Attempts to set the sample rate of the accelerometer to the specified value (in ms).
00484   *
00485   * @param period the requested time between samples, in milliseconds.
00486   *
00487   * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
00488   *
00489   * @code
00490   * // sample rate is now 20 ms.
00491   * accelerometer.setPeriod(20);
00492   * @endcode
00493   *
00494   * @note The requested rate may not be possible on the hardware. In this case, the
00495   * nearest lower rate is chosen.
00496   */
00497 int MicroBitAccelerometer::setPeriod(int period)
00498 {
00499     this->samplePeriod = period;
00500     return this->configure();
00501 }
00502 
00503 /**
00504   * Reads the currently configured sample rate of the accelerometer.
00505   *
00506   * @return The time between samples, in milliseconds.
00507   */
00508 int MicroBitAccelerometer::getPeriod()
00509 {
00510     return (int)samplePeriod;
00511 }
00512 
00513 /**
00514   * Attempts to set the sample range of the accelerometer to the specified value (in g).
00515   *
00516   * @param range The requested sample range of samples, in g.
00517   *
00518   * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
00519   *
00520   * @code
00521   * // the sample range of the accelerometer is now 8G.
00522   * accelerometer.setRange(8);
00523   * @endcode
00524   *
00525   * @note The requested range may not be possible on the hardware. In this case, the
00526   * nearest lower range is chosen.
00527   */
00528 int MicroBitAccelerometer::setRange(int range)
00529 {
00530     this->sampleRange = range;
00531     return this->configure();
00532 }
00533 
00534 /**
00535   * Reads the currently configured sample range of the accelerometer.
00536   *
00537   * @return The sample range, in g.
00538   */
00539 int MicroBitAccelerometer::getRange()
00540 {
00541     return (int)sampleRange;
00542 }
00543 
00544 /**
00545   * Reads the value of the X axis from the latest update retrieved from the accelerometer.
00546   *
00547   * @param system The coordinate system to use. By default, a simple cartesian system is provided.
00548   *
00549   * @return The force measured in the X axis, in milli-g.
00550   *
00551   * @code
00552   * accelerometer.getX();
00553   * @endcode
00554   */
00555 int MicroBitAccelerometer::getX(MicroBitCoordinateSystem system)
00556 {
00557     updateSample();
00558 
00559     switch (system)
00560     {
00561         case SIMPLE_CARTESIAN:
00562             return -sample.x;
00563 
00564         case NORTH_EAST_DOWN:
00565             return sample.y;
00566 
00567         case RAW:
00568         default:
00569             return sample.x;
00570     }
00571 }
00572 
00573 /**
00574   * Reads the value of the Y axis from the latest update retrieved from the accelerometer.
00575   *
00576   * @return The force measured in the Y axis, in milli-g.
00577   *
00578   * @code
00579   * accelerometer.getY();
00580   * @endcode
00581   */
00582 int MicroBitAccelerometer::getY(MicroBitCoordinateSystem system)
00583 {
00584     updateSample();
00585 
00586     switch (system)
00587     {
00588         case SIMPLE_CARTESIAN:
00589             return -sample.y;
00590 
00591         case NORTH_EAST_DOWN:
00592             return -sample.x;
00593 
00594         case RAW:
00595         default:
00596             return sample.y;
00597     }
00598 }
00599 
00600 /**
00601   * Reads the value of the Z axis from the latest update retrieved from the accelerometer.
00602   *
00603   * @return The force measured in the Z axis, in milli-g.
00604   *
00605   * @code
00606   * accelerometer.getZ();
00607   * @endcode
00608   */
00609 int MicroBitAccelerometer::getZ(MicroBitCoordinateSystem system)
00610 {
00611     updateSample();
00612 
00613     switch (system)
00614     {
00615         case NORTH_EAST_DOWN:
00616             return -sample.z;
00617 
00618         case SIMPLE_CARTESIAN:
00619         case RAW:
00620         default:
00621             return sample.z;
00622     }
00623 }
00624 
00625 /**
00626   * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
00627   *
00628   * @return The pitch of the device, in degrees.
00629   *
00630   * @code
00631   * accelerometer.getPitch();
00632   * @endcode
00633   */
00634 int MicroBitAccelerometer::getPitch()
00635 {
00636     return (int) ((360*getPitchRadians()) / (2*PI));
00637 }
00638 
00639 /**
00640   * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
00641   *
00642   * @return The pitch of the device, in radians.
00643   *
00644   * @code
00645   * accelerometer.getPitchRadians();
00646   * @endcode
00647   */
00648 float MicroBitAccelerometer::getPitchRadians()
00649 {
00650     if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
00651         recalculatePitchRoll();
00652 
00653     return pitch;
00654 }
00655 
00656 /**
00657   * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
00658   *
00659   * @return The roll of the device, in degrees.
00660   *
00661   * @code
00662   * accelerometer.getRoll();
00663   * @endcode
00664   */
00665 int MicroBitAccelerometer::getRoll()
00666 {
00667     return (int) ((360*getRollRadians()) / (2*PI));
00668 }
00669 
00670 /**
00671   * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
00672   *
00673   * @return The roll of the device, in radians.
00674   *
00675   * @code
00676   * accelerometer.getRollRadians();
00677   * @endcode
00678   */
00679 float MicroBitAccelerometer::getRollRadians()
00680 {
00681     if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
00682         recalculatePitchRoll();
00683 
00684     return roll;
00685 }
00686 
00687 /**
00688   * Recalculate roll and pitch values for the current sample.
00689   *
00690   * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather
00691   *       heavyweight for a CPU without a floating point unit.
00692   */
00693 void MicroBitAccelerometer::recalculatePitchRoll()
00694 {
00695     double x = (double) getX(NORTH_EAST_DOWN);
00696     double y = (double) getY(NORTH_EAST_DOWN);
00697     double z = (double) getZ(NORTH_EAST_DOWN);
00698 
00699     roll = atan2(y, z);
00700     pitch = atan(-x / (y*sin(roll) + z*cos(roll)));
00701 
00702     status |= MICROBIT_ACCEL_PITCH_ROLL_VALID;
00703 }
00704 
00705 /**
00706   * Retrieves the last recorded gesture.
00707   *
00708   * @return The last gesture that was detected.
00709   *
00710   * Example:
00711   * @code
00712   * MicroBitDisplay display;
00713   *
00714   * if (accelerometer.getGesture() == SHAKE)
00715   *     display.scroll("SHAKE!");
00716   * @endcode
00717   */
00718 uint16_t MicroBitAccelerometer::getGesture()
00719 {
00720     return lastGesture;
00721 }
00722 
00723 /**
00724   * A periodic callback invoked by the fiber scheduler idle thread.
00725   *
00726   * Internally calls updateSample().
00727   */
00728 void MicroBitAccelerometer::idleTick()
00729 {
00730     updateSample();
00731 }
00732 
00733 /**
00734   * Destructor for MicroBitAccelerometer, where we deregister from the array of fiber components.
00735   */
00736 MicroBitAccelerometer::~MicroBitAccelerometer()
00737 {
00738     fiber_remove_idle_component(this);
00739 }
00740 
00741 const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = {
00742     {2, 0},
00743     {4, 1},
00744     {8, 2}
00745 };
00746 
00747 const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = {
00748     {1250,      0x00},
00749     {2500,      0x08},
00750     {5000,      0x10},
00751     {10000,     0x18},
00752     {20000,     0x20},
00753     {80000,     0x28},
00754     {160000,    0x30},
00755     {640000,    0x38}
00756 };