Forked to avoid changing the publioc repo

Dependencies:   BLE_API mbed-dev-bin nRF51822

Fork of microbit-dal by Lancaster University

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:18:22 2016 +0100
Revision:
42:e2869e0fa366
Parent:
41:da05ec75cd5d
Child:
43:0374ea4d2167
Synchronized with git rev ece079c7
Author: Joe Finney
microbit: FREEFALL gesture event is now damped

After further testing, dmaping is required on FREEFALL event (but not impulse
events) to avoid false positives.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jonathan Austin 1:8aa5cdb4ab67 1 /*
Jonathan Austin 1:8aa5cdb4ab67 2 The MIT License (MIT)
Jonathan Austin 1:8aa5cdb4ab67 3
Jonathan Austin 1:8aa5cdb4ab67 4 Copyright (c) 2016 British Broadcasting Corporation.
Jonathan Austin 1:8aa5cdb4ab67 5 This software is provided by Lancaster University by arrangement with the BBC.
Jonathan Austin 1:8aa5cdb4ab67 6
Jonathan Austin 1:8aa5cdb4ab67 7 Permission is hereby granted, free of charge, to any person obtaining a
Jonathan Austin 1:8aa5cdb4ab67 8 copy of this software and associated documentation files (the "Software"),
Jonathan Austin 1:8aa5cdb4ab67 9 to deal in the Software without restriction, including without limitation
Jonathan Austin 1:8aa5cdb4ab67 10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
Jonathan Austin 1:8aa5cdb4ab67 11 and/or sell copies of the Software, and to permit persons to whom the
Jonathan Austin 1:8aa5cdb4ab67 12 Software is furnished to do so, subject to the following conditions:
Jonathan Austin 1:8aa5cdb4ab67 13
Jonathan Austin 1:8aa5cdb4ab67 14 The above copyright notice and this permission notice shall be included in
Jonathan Austin 1:8aa5cdb4ab67 15 all copies or substantial portions of the Software.
Jonathan Austin 1:8aa5cdb4ab67 16
Jonathan Austin 1:8aa5cdb4ab67 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Jonathan Austin 1:8aa5cdb4ab67 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Jonathan Austin 1:8aa5cdb4ab67 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Jonathan Austin 1:8aa5cdb4ab67 20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Jonathan Austin 1:8aa5cdb4ab67 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Jonathan Austin 1:8aa5cdb4ab67 22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Jonathan Austin 1:8aa5cdb4ab67 23 DEALINGS IN THE SOFTWARE.
Jonathan Austin 1:8aa5cdb4ab67 24 */
Jonathan Austin 1:8aa5cdb4ab67 25
Jonathan Austin 1:8aa5cdb4ab67 26 /**
Jonathan Austin 1:8aa5cdb4ab67 27 * Class definition for MicroBit Accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 28 *
Jonathan Austin 1:8aa5cdb4ab67 29 * Represents an implementation of the Freescale MMA8653 3 axis accelerometer
Jonathan Austin 1:8aa5cdb4ab67 30 * Also includes basic data caching and on demand activation.
Jonathan Austin 1:8aa5cdb4ab67 31 */
Jonathan Austin 1:8aa5cdb4ab67 32 #include "MicroBitConfig.h"
Jonathan Austin 1:8aa5cdb4ab67 33 #include "MicroBitAccelerometer.h"
Jonathan Austin 1:8aa5cdb4ab67 34 #include "ErrorNo.h"
Jonathan Austin 1:8aa5cdb4ab67 35 #include "MicroBitConfig.h"
Jonathan Austin 1:8aa5cdb4ab67 36 #include "MicroBitEvent.h"
Jonathan Austin 1:8aa5cdb4ab67 37 #include "MicroBitCompat.h"
Jonathan Austin 1:8aa5cdb4ab67 38 #include "MicroBitFiber.h"
Jonathan Austin 1:8aa5cdb4ab67 39
Jonathan Austin 1:8aa5cdb4ab67 40 /**
Jonathan Austin 1:8aa5cdb4ab67 41 * Configures the accelerometer for G range and sample rate defined
Jonathan Austin 1:8aa5cdb4ab67 42 * in this object. The nearest values are chosen to those defined
Jonathan Austin 1:8aa5cdb4ab67 43 * that are supported by the hardware. The instance variables are then
Jonathan Austin 1:8aa5cdb4ab67 44 * updated to reflect reality.
Jonathan Austin 1:8aa5cdb4ab67 45 *
Jonathan Austin 1:8aa5cdb4ab67 46 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the accelerometer could not be configured.
Jonathan Austin 1:8aa5cdb4ab67 47 */
Jonathan Austin 1:8aa5cdb4ab67 48 int MicroBitAccelerometer::configure()
Jonathan Austin 1:8aa5cdb4ab67 49 {
Jonathan Austin 1:8aa5cdb4ab67 50 const MMA8653SampleRangeConfig *actualSampleRange;
Jonathan Austin 1:8aa5cdb4ab67 51 const MMA8653SampleRateConfig *actualSampleRate;
Jonathan Austin 1:8aa5cdb4ab67 52 int result;
Jonathan Austin 1:8aa5cdb4ab67 53
Jonathan Austin 1:8aa5cdb4ab67 54 // First find the nearest sample rate to that specified.
Jonathan Austin 1:8aa5cdb4ab67 55 actualSampleRate = &MMA8653SampleRate[MMA8653_SAMPLE_RATES-1];
Jonathan Austin 1:8aa5cdb4ab67 56 for (int i=MMA8653_SAMPLE_RATES-1; i>=0; i--)
Jonathan Austin 1:8aa5cdb4ab67 57 {
Jonathan Austin 1:8aa5cdb4ab67 58 if(MMA8653SampleRate[i].sample_period < this->samplePeriod * 1000)
Jonathan Austin 1:8aa5cdb4ab67 59 break;
Jonathan Austin 1:8aa5cdb4ab67 60
Jonathan Austin 1:8aa5cdb4ab67 61 actualSampleRate = &MMA8653SampleRate[i];
Jonathan Austin 1:8aa5cdb4ab67 62 }
Jonathan Austin 1:8aa5cdb4ab67 63
Jonathan Austin 1:8aa5cdb4ab67 64 // Now find the nearest sample range to that specified.
Jonathan Austin 1:8aa5cdb4ab67 65 actualSampleRange = &MMA8653SampleRange[MMA8653_SAMPLE_RANGES-1];
Jonathan Austin 1:8aa5cdb4ab67 66 for (int i=MMA8653_SAMPLE_RANGES-1; i>=0; i--)
Jonathan Austin 1:8aa5cdb4ab67 67 {
Jonathan Austin 1:8aa5cdb4ab67 68 if(MMA8653SampleRange[i].sample_range < this->sampleRange)
Jonathan Austin 1:8aa5cdb4ab67 69 break;
Jonathan Austin 1:8aa5cdb4ab67 70
Jonathan Austin 1:8aa5cdb4ab67 71 actualSampleRange = &MMA8653SampleRange[i];
Jonathan Austin 1:8aa5cdb4ab67 72 }
Jonathan Austin 1:8aa5cdb4ab67 73
Jonathan Austin 1:8aa5cdb4ab67 74 // OK, we have the correct data. Update our local state.
Jonathan Austin 1:8aa5cdb4ab67 75 this->samplePeriod = actualSampleRate->sample_period / 1000;
Jonathan Austin 1:8aa5cdb4ab67 76 this->sampleRange = actualSampleRange->sample_range;
Jonathan Austin 1:8aa5cdb4ab67 77
Jonathan Austin 1:8aa5cdb4ab67 78 // Now configure the accelerometer accordingly.
Jonathan Austin 1:8aa5cdb4ab67 79 // First place the device into standby mode, so it can be configured.
Jonathan Austin 1:8aa5cdb4ab67 80 result = writeCommand(MMA8653_CTRL_REG1, 0x00);
Jonathan Austin 1:8aa5cdb4ab67 81 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 82 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 83
Jonathan Austin 1:8aa5cdb4ab67 84 // Enable high precisiosn mode. This consumes a bit more power, but still only 184 uA!
Jonathan Austin 1:8aa5cdb4ab67 85 result = writeCommand(MMA8653_CTRL_REG2, 0x10);
Jonathan Austin 1:8aa5cdb4ab67 86 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 87 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 88
Jonathan Austin 1:8aa5cdb4ab67 89 // Enable the INT1 interrupt pin.
Jonathan Austin 1:8aa5cdb4ab67 90 result = writeCommand(MMA8653_CTRL_REG4, 0x01);
Jonathan Austin 1:8aa5cdb4ab67 91 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 92 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 93
Jonathan Austin 1:8aa5cdb4ab67 94 // Select the DATA_READY event source to be routed to INT1
Jonathan Austin 1:8aa5cdb4ab67 95 result = writeCommand(MMA8653_CTRL_REG5, 0x01);
Jonathan Austin 1:8aa5cdb4ab67 96 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 97 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 98
Jonathan Austin 1:8aa5cdb4ab67 99 // Configure for the selected g range.
Jonathan Austin 1:8aa5cdb4ab67 100 result = writeCommand(MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg);
Jonathan Austin 1:8aa5cdb4ab67 101 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 102 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 103
Jonathan Austin 1:8aa5cdb4ab67 104 // Bring the device back online, with 10bit wide samples at the requested frequency.
Jonathan Austin 1:8aa5cdb4ab67 105 result = writeCommand(MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
Jonathan Austin 1:8aa5cdb4ab67 106 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 107 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 108
Jonathan Austin 1:8aa5cdb4ab67 109 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 110 }
Jonathan Austin 1:8aa5cdb4ab67 111
Jonathan Austin 1:8aa5cdb4ab67 112 /**
Jonathan Austin 1:8aa5cdb4ab67 113 * Issues a standard, 2 byte I2C command write to the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 114 *
Jonathan Austin 1:8aa5cdb4ab67 115 * Blocks the calling thread until complete.
Jonathan Austin 1:8aa5cdb4ab67 116 *
Jonathan Austin 1:8aa5cdb4ab67 117 * @param reg The address of the register to write to.
Jonathan Austin 1:8aa5cdb4ab67 118 *
Jonathan Austin 1:8aa5cdb4ab67 119 * @param value The value to write.
Jonathan Austin 1:8aa5cdb4ab67 120 *
Jonathan Austin 1:8aa5cdb4ab67 121 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
Jonathan Austin 1:8aa5cdb4ab67 122 */
Jonathan Austin 1:8aa5cdb4ab67 123 int MicroBitAccelerometer::writeCommand(uint8_t reg, uint8_t value)
Jonathan Austin 1:8aa5cdb4ab67 124 {
Jonathan Austin 1:8aa5cdb4ab67 125 uint8_t command[2];
Jonathan Austin 1:8aa5cdb4ab67 126 command[0] = reg;
Jonathan Austin 1:8aa5cdb4ab67 127 command[1] = value;
Jonathan Austin 1:8aa5cdb4ab67 128
Jonathan Austin 1:8aa5cdb4ab67 129 return i2c.write(address, (const char *)command, 2);
Jonathan Austin 1:8aa5cdb4ab67 130 }
Jonathan Austin 1:8aa5cdb4ab67 131
Jonathan Austin 1:8aa5cdb4ab67 132 /**
Jonathan Austin 1:8aa5cdb4ab67 133 * Issues a read command, copying data into the specified buffer.
Jonathan Austin 1:8aa5cdb4ab67 134 *
Jonathan Austin 1:8aa5cdb4ab67 135 * Blocks the calling thread until complete.
Jonathan Austin 1:8aa5cdb4ab67 136 *
Jonathan Austin 1:8aa5cdb4ab67 137 * @param reg The address of the register to access.
Jonathan Austin 1:8aa5cdb4ab67 138 *
Jonathan Austin 1:8aa5cdb4ab67 139 * @param buffer Memory area to read the data into.
Jonathan Austin 1:8aa5cdb4ab67 140 *
Jonathan Austin 1:8aa5cdb4ab67 141 * @param length The number of bytes to read.
Jonathan Austin 1:8aa5cdb4ab67 142 *
Jonathan Austin 1:8aa5cdb4ab67 143 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
Jonathan Austin 1:8aa5cdb4ab67 144 */
Jonathan Austin 1:8aa5cdb4ab67 145 int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length)
Jonathan Austin 1:8aa5cdb4ab67 146 {
Jonathan Austin 1:8aa5cdb4ab67 147 int result;
Jonathan Austin 1:8aa5cdb4ab67 148
Jonathan Austin 1:8aa5cdb4ab67 149 if (buffer == NULL || length <= 0 )
Jonathan Austin 1:8aa5cdb4ab67 150 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 151
Jonathan Austin 1:8aa5cdb4ab67 152 result = i2c.write(address, (const char *)&reg, 1, true);
Jonathan Austin 1:8aa5cdb4ab67 153 if (result !=0)
Jonathan Austin 1:8aa5cdb4ab67 154 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 155
Jonathan Austin 1:8aa5cdb4ab67 156 result = i2c.read(address, (char *)buffer, length);
Jonathan Austin 1:8aa5cdb4ab67 157 if (result !=0)
Jonathan Austin 1:8aa5cdb4ab67 158 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 159
Jonathan Austin 1:8aa5cdb4ab67 160 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 161 }
Jonathan Austin 1:8aa5cdb4ab67 162
Jonathan Austin 1:8aa5cdb4ab67 163 /**
Jonathan Austin 1:8aa5cdb4ab67 164 * Constructor.
Jonathan Austin 1:8aa5cdb4ab67 165 * Create a software abstraction of an accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 166 *
Jonathan Austin 1:8aa5cdb4ab67 167 * @param _i2c an instance of MicroBitI2C used to communicate with the onboard accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 168 *
Jonathan Austin 1:8aa5cdb4ab67 169 * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR.
Jonathan Austin 1:8aa5cdb4ab67 170 *
Jonathan Austin 1:8aa5cdb4ab67 171 * @param id the unique EventModel id of this component. Defaults to: MICROBIT_ID_ACCELEROMETER
Jonathan Austin 1:8aa5cdb4ab67 172 *
Jonathan Austin 1:8aa5cdb4ab67 173 * @code
Jonathan Austin 1:8aa5cdb4ab67 174 * MicroBitI2C i2c = MicroBitI2C(I2C_SDA0, I2C_SCL0);
Jonathan Austin 1:8aa5cdb4ab67 175 *
Jonathan Austin 1:8aa5cdb4ab67 176 * MicroBitAccelerometer accelerometer = MicroBitAccelerometer(i2c);
Jonathan Austin 1:8aa5cdb4ab67 177 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 178 */
Jonathan Austin 1:8aa5cdb4ab67 179 MicroBitAccelerometer::MicroBitAccelerometer(MicroBitI2C& _i2c, uint16_t address, uint16_t id) : sample(), int1(MICROBIT_PIN_ACCEL_DATA_READY), i2c(_i2c)
Jonathan Austin 1:8aa5cdb4ab67 180 {
Jonathan Austin 1:8aa5cdb4ab67 181 // Store our identifiers.
Jonathan Austin 1:8aa5cdb4ab67 182 this->id = id;
Jonathan Austin 1:8aa5cdb4ab67 183 this->status = 0;
Jonathan Austin 1:8aa5cdb4ab67 184 this->address = address;
Jonathan Austin 1:8aa5cdb4ab67 185
Jonathan Austin 1:8aa5cdb4ab67 186 // Update our internal state for 50Hz at +/- 2g (50Hz has a period af 20ms).
Jonathan Austin 1:8aa5cdb4ab67 187 this->samplePeriod = 20;
Jonathan Austin 1:8aa5cdb4ab67 188 this->sampleRange = 2;
Jonathan Austin 1:8aa5cdb4ab67 189
Jonathan Austin 1:8aa5cdb4ab67 190 // Initialise gesture history
Jonathan Austin 1:8aa5cdb4ab67 191 this->sigma = 0;
LancasterUniversity 38:1a9e8e5e23f2 192 this->impulseSigma = 0;
LancasterUniversity 39:112df23f039f 193 this->lastGesture = MICROBIT_ACCELEROMETER_EVT_NONE;
LancasterUniversity 39:112df23f039f 194 this->currentGesture = MICROBIT_ACCELEROMETER_EVT_NONE;
Jonathan Austin 1:8aa5cdb4ab67 195 this->shake.x = 0;
Jonathan Austin 1:8aa5cdb4ab67 196 this->shake.y = 0;
Jonathan Austin 1:8aa5cdb4ab67 197 this->shake.z = 0;
Jonathan Austin 1:8aa5cdb4ab67 198 this->shake.count = 0;
Jonathan Austin 1:8aa5cdb4ab67 199 this->shake.timer = 0;
LancasterUniversity 38:1a9e8e5e23f2 200 this->shake.impulse_3 = 1;
LancasterUniversity 38:1a9e8e5e23f2 201 this->shake.impulse_6 = 1;
LancasterUniversity 38:1a9e8e5e23f2 202 this->shake.impulse_8 = 1;
Jonathan Austin 1:8aa5cdb4ab67 203
Jonathan Austin 1:8aa5cdb4ab67 204 // Configure and enable the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 205 if (this->configure() == MICROBIT_OK)
Jonathan Austin 1:8aa5cdb4ab67 206 status |= MICROBIT_COMPONENT_RUNNING;
Jonathan Austin 1:8aa5cdb4ab67 207 }
Jonathan Austin 1:8aa5cdb4ab67 208
Jonathan Austin 1:8aa5cdb4ab67 209 /**
Jonathan Austin 1:8aa5cdb4ab67 210 * Attempts to read the 8 bit ID from the accelerometer, this can be used for
Jonathan Austin 1:8aa5cdb4ab67 211 * validation purposes.
Jonathan Austin 1:8aa5cdb4ab67 212 *
Jonathan Austin 1:8aa5cdb4ab67 213 * @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
Jonathan Austin 1:8aa5cdb4ab67 214 *
Jonathan Austin 1:8aa5cdb4ab67 215 * @code
Jonathan Austin 1:8aa5cdb4ab67 216 * accelerometer.whoAmI();
Jonathan Austin 1:8aa5cdb4ab67 217 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 218 */
Jonathan Austin 1:8aa5cdb4ab67 219 int MicroBitAccelerometer::whoAmI()
Jonathan Austin 1:8aa5cdb4ab67 220 {
Jonathan Austin 1:8aa5cdb4ab67 221 uint8_t data;
Jonathan Austin 1:8aa5cdb4ab67 222 int result;
Jonathan Austin 1:8aa5cdb4ab67 223
Jonathan Austin 1:8aa5cdb4ab67 224 result = readCommand(MMA8653_WHOAMI, &data, 1);
Jonathan Austin 1:8aa5cdb4ab67 225 if (result !=0)
Jonathan Austin 1:8aa5cdb4ab67 226 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 227
Jonathan Austin 1:8aa5cdb4ab67 228 return (int)data;
Jonathan Austin 1:8aa5cdb4ab67 229 }
Jonathan Austin 1:8aa5cdb4ab67 230
Jonathan Austin 1:8aa5cdb4ab67 231 /**
Jonathan Austin 1:8aa5cdb4ab67 232 * Reads the acceleration data from the accelerometer, and stores it in our buffer.
Jonathan Austin 1:8aa5cdb4ab67 233 * This only happens if the accelerometer indicates that it has new data via int1.
Jonathan Austin 1:8aa5cdb4ab67 234 *
Jonathan Austin 1:8aa5cdb4ab67 235 * On first use, this member function will attempt to add this component to the
Jonathan Austin 1:8aa5cdb4ab67 236 * list of fiber components in order to constantly update the values stored
Jonathan Austin 1:8aa5cdb4ab67 237 * by this object.
Jonathan Austin 1:8aa5cdb4ab67 238 *
Jonathan Austin 1:8aa5cdb4ab67 239 * This technique is called lazy instantiation, and it means that we do not
Jonathan Austin 1:8aa5cdb4ab67 240 * obtain the overhead from non-chalantly adding this component to fiber components.
Jonathan Austin 1:8aa5cdb4ab67 241 *
Jonathan Austin 1:8aa5cdb4ab67 242 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the read request fails.
Jonathan Austin 1:8aa5cdb4ab67 243 */
Jonathan Austin 1:8aa5cdb4ab67 244 int MicroBitAccelerometer::updateSample()
Jonathan Austin 1:8aa5cdb4ab67 245 {
Jonathan Austin 1:8aa5cdb4ab67 246 if(!(status & MICROBIT_ACCEL_ADDED_TO_IDLE))
Jonathan Austin 1:8aa5cdb4ab67 247 {
Jonathan Austin 1:8aa5cdb4ab67 248 fiber_add_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 249 status |= MICROBIT_ACCEL_ADDED_TO_IDLE;
Jonathan Austin 1:8aa5cdb4ab67 250 }
Jonathan Austin 1:8aa5cdb4ab67 251
Jonathan Austin 1:8aa5cdb4ab67 252 // Poll interrupt line from accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 253 // n.b. Default is Active LO. Interrupt is cleared in data read.
Jonathan Austin 1:8aa5cdb4ab67 254 if(!int1)
Jonathan Austin 1:8aa5cdb4ab67 255 {
Jonathan Austin 1:8aa5cdb4ab67 256 int8_t data[6];
Jonathan Austin 1:8aa5cdb4ab67 257 int result;
Jonathan Austin 1:8aa5cdb4ab67 258
Jonathan Austin 1:8aa5cdb4ab67 259 result = readCommand(MMA8653_OUT_X_MSB, (uint8_t *)data, 6);
Jonathan Austin 1:8aa5cdb4ab67 260 if (result !=0)
Jonathan Austin 1:8aa5cdb4ab67 261 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 262
Jonathan Austin 1:8aa5cdb4ab67 263 // read MSB values...
Jonathan Austin 1:8aa5cdb4ab67 264 sample.x = data[0];
Jonathan Austin 1:8aa5cdb4ab67 265 sample.y = data[2];
Jonathan Austin 1:8aa5cdb4ab67 266 sample.z = data[4];
Jonathan Austin 1:8aa5cdb4ab67 267
Jonathan Austin 1:8aa5cdb4ab67 268 // Normalize the data in the 0..1024 range.
Jonathan Austin 1:8aa5cdb4ab67 269 sample.x *= 8;
Jonathan Austin 1:8aa5cdb4ab67 270 sample.y *= 8;
Jonathan Austin 1:8aa5cdb4ab67 271 sample.z *= 8;
Jonathan Austin 1:8aa5cdb4ab67 272
Jonathan Austin 1:8aa5cdb4ab67 273 #if CONFIG_ENABLED(USE_ACCEL_LSB)
Jonathan Austin 1:8aa5cdb4ab67 274 // Add in LSB values.
Jonathan Austin 1:8aa5cdb4ab67 275 sample.x += (data[1] / 64);
Jonathan Austin 1:8aa5cdb4ab67 276 sample.y += (data[3] / 64);
Jonathan Austin 1:8aa5cdb4ab67 277 sample.z += (data[5] / 64);
Jonathan Austin 1:8aa5cdb4ab67 278 #endif
Jonathan Austin 1:8aa5cdb4ab67 279
Jonathan Austin 1:8aa5cdb4ab67 280 // Scale into millig (approx!)
Jonathan Austin 1:8aa5cdb4ab67 281 sample.x *= this->sampleRange;
Jonathan Austin 1:8aa5cdb4ab67 282 sample.y *= this->sampleRange;
Jonathan Austin 1:8aa5cdb4ab67 283 sample.z *= this->sampleRange;
Jonathan Austin 1:8aa5cdb4ab67 284
Jonathan Austin 1:8aa5cdb4ab67 285 // Indicate that pitch and roll data is now stale, and needs to be recalculated if needed.
Jonathan Austin 1:8aa5cdb4ab67 286 status &= ~MICROBIT_ACCEL_PITCH_ROLL_VALID;
Jonathan Austin 1:8aa5cdb4ab67 287
Jonathan Austin 1:8aa5cdb4ab67 288 // Update gesture tracking
Jonathan Austin 1:8aa5cdb4ab67 289 updateGesture();
Jonathan Austin 1:8aa5cdb4ab67 290
Jonathan Austin 1:8aa5cdb4ab67 291 // Indicate that a new sample is available
Jonathan Austin 1:8aa5cdb4ab67 292 MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE);
Jonathan Austin 1:8aa5cdb4ab67 293 }
Jonathan Austin 1:8aa5cdb4ab67 294
Jonathan Austin 1:8aa5cdb4ab67 295 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 296 };
Jonathan Austin 1:8aa5cdb4ab67 297
Jonathan Austin 1:8aa5cdb4ab67 298 /**
Jonathan Austin 1:8aa5cdb4ab67 299 * A service function.
Jonathan Austin 1:8aa5cdb4ab67 300 * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2).
Jonathan Austin 1:8aa5cdb4ab67 301 * It does not, however, square root the result, as this is a relatively high cost operation.
Jonathan Austin 1:8aa5cdb4ab67 302 *
Jonathan Austin 1:8aa5cdb4ab67 303 * This is left to application code should it be needed.
Jonathan Austin 1:8aa5cdb4ab67 304 *
Jonathan Austin 1:8aa5cdb4ab67 305 * @return the sum of the square of the acceleration of the device across all axes.
Jonathan Austin 1:8aa5cdb4ab67 306 */
Jonathan Austin 1:8aa5cdb4ab67 307 int MicroBitAccelerometer::instantaneousAccelerationSquared()
Jonathan Austin 1:8aa5cdb4ab67 308 {
Jonathan Austin 1:8aa5cdb4ab67 309 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 310
Jonathan Austin 1:8aa5cdb4ab67 311 // Use pythagoras theorem to determine the combined force acting on the device.
Jonathan Austin 1:8aa5cdb4ab67 312 return (int)sample.x*(int)sample.x + (int)sample.y*(int)sample.y + (int)sample.z*(int)sample.z;
Jonathan Austin 1:8aa5cdb4ab67 313 }
Jonathan Austin 1:8aa5cdb4ab67 314
Jonathan Austin 1:8aa5cdb4ab67 315 /**
Jonathan Austin 1:8aa5cdb4ab67 316 * Service function.
Jonathan Austin 1:8aa5cdb4ab67 317 * Determines a 'best guess' posture of the device based on instantaneous data.
Jonathan Austin 1:8aa5cdb4ab67 318 *
LancasterUniversity 37:b624ae5e94a5 319 * This makes no use of historic data, and forms the input to the filter implemented in updateGesture().
Jonathan Austin 1:8aa5cdb4ab67 320 *
Jonathan Austin 1:8aa5cdb4ab67 321 * @return A 'best guess' of the current posture of the device, based on instanataneous data.
Jonathan Austin 1:8aa5cdb4ab67 322 */
LancasterUniversity 39:112df23f039f 323 uint16_t MicroBitAccelerometer::instantaneousPosture()
Jonathan Austin 1:8aa5cdb4ab67 324 {
Jonathan Austin 1:8aa5cdb4ab67 325 bool shakeDetected = false;
Jonathan Austin 1:8aa5cdb4ab67 326
Jonathan Austin 1:8aa5cdb4ab67 327 // Test for shake events.
Jonathan Austin 1:8aa5cdb4ab67 328 // 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
LancasterUniversity 37:b624ae5e94a5 329 // 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).
Jonathan Austin 1:8aa5cdb4ab67 330 //
Jonathan Austin 1:8aa5cdb4ab67 331 // If we see enough zero crossings in succession (MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the device
Jonathan Austin 1:8aa5cdb4ab67 332 // has been shaken.
Jonathan Austin 1:8aa5cdb4ab67 333 if ((getX() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || (getX() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.x))
Jonathan Austin 1:8aa5cdb4ab67 334 {
Jonathan Austin 1:8aa5cdb4ab67 335 shakeDetected = true;
Jonathan Austin 1:8aa5cdb4ab67 336 shake.x = !shake.x;
Jonathan Austin 1:8aa5cdb4ab67 337 }
Jonathan Austin 1:8aa5cdb4ab67 338
Jonathan Austin 1:8aa5cdb4ab67 339 if ((getY() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.y) || (getY() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.y))
Jonathan Austin 1:8aa5cdb4ab67 340 {
Jonathan Austin 1:8aa5cdb4ab67 341 shakeDetected = true;
Jonathan Austin 1:8aa5cdb4ab67 342 shake.y = !shake.y;
Jonathan Austin 1:8aa5cdb4ab67 343 }
Jonathan Austin 1:8aa5cdb4ab67 344
Jonathan Austin 1:8aa5cdb4ab67 345 if ((getZ() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.z) || (getZ() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.z))
Jonathan Austin 1:8aa5cdb4ab67 346 {
Jonathan Austin 1:8aa5cdb4ab67 347 shakeDetected = true;
Jonathan Austin 1:8aa5cdb4ab67 348 shake.z = !shake.z;
Jonathan Austin 1:8aa5cdb4ab67 349 }
Jonathan Austin 1:8aa5cdb4ab67 350
Jonathan Austin 1:8aa5cdb4ab67 351 if (shakeDetected && shake.count < MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD && ++shake.count == MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD)
Jonathan Austin 1:8aa5cdb4ab67 352 shake.shaken = 1;
Jonathan Austin 1:8aa5cdb4ab67 353
Jonathan Austin 1:8aa5cdb4ab67 354 if (++shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_DAMPING)
Jonathan Austin 1:8aa5cdb4ab67 355 {
Jonathan Austin 1:8aa5cdb4ab67 356 shake.timer = 0;
Jonathan Austin 1:8aa5cdb4ab67 357 if (shake.count > 0)
Jonathan Austin 1:8aa5cdb4ab67 358 {
Jonathan Austin 1:8aa5cdb4ab67 359 if(--shake.count == 0)
Jonathan Austin 1:8aa5cdb4ab67 360 shake.shaken = 0;
Jonathan Austin 1:8aa5cdb4ab67 361 }
Jonathan Austin 1:8aa5cdb4ab67 362 }
Jonathan Austin 1:8aa5cdb4ab67 363
LancasterUniversity 38:1a9e8e5e23f2 364 // Shake events take the highest priority, as under high levels of change, other events
LancasterUniversity 38:1a9e8e5e23f2 365 // are likely to be transient.
Jonathan Austin 1:8aa5cdb4ab67 366 if (shake.shaken)
LancasterUniversity 39:112df23f039f 367 return MICROBIT_ACCELEROMETER_EVT_SHAKE;
Jonathan Austin 1:8aa5cdb4ab67 368
LancasterUniversity 42:e2869e0fa366 369 if (instantaneousAccelerationSquared() < MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD)
LancasterUniversity 42:e2869e0fa366 370 return MICROBIT_ACCELEROMETER_EVT_FREEFALL;
LancasterUniversity 42:e2869e0fa366 371
Jonathan Austin 1:8aa5cdb4ab67 372 // Determine our posture.
Jonathan Austin 1:8aa5cdb4ab67 373 if (getX() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 374 return MICROBIT_ACCELEROMETER_EVT_TILT_LEFT;
Jonathan Austin 1:8aa5cdb4ab67 375
Jonathan Austin 1:8aa5cdb4ab67 376 if (getX() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 377 return MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT;
Jonathan Austin 1:8aa5cdb4ab67 378
Jonathan Austin 1:8aa5cdb4ab67 379 if (getY() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 380 return MICROBIT_ACCELEROMETER_EVT_TILT_DOWN;
Jonathan Austin 1:8aa5cdb4ab67 381
Jonathan Austin 1:8aa5cdb4ab67 382 if (getY() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 383 return MICROBIT_ACCELEROMETER_EVT_TILT_UP;
Jonathan Austin 1:8aa5cdb4ab67 384
Jonathan Austin 1:8aa5cdb4ab67 385 if (getZ() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 386 return MICROBIT_ACCELEROMETER_EVT_FACE_UP;
Jonathan Austin 1:8aa5cdb4ab67 387
Jonathan Austin 1:8aa5cdb4ab67 388 if (getZ() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 389 return MICROBIT_ACCELEROMETER_EVT_FACE_DOWN;
Jonathan Austin 1:8aa5cdb4ab67 390
LancasterUniversity 39:112df23f039f 391 return MICROBIT_ACCELEROMETER_EVT_NONE;
Jonathan Austin 1:8aa5cdb4ab67 392 }
Jonathan Austin 1:8aa5cdb4ab67 393
Jonathan Austin 1:8aa5cdb4ab67 394 /**
Jonathan Austin 1:8aa5cdb4ab67 395 * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote
Jonathan Austin 1:8aa5cdb4ab67 396 * stability.
Jonathan Austin 1:8aa5cdb4ab67 397 */
Jonathan Austin 1:8aa5cdb4ab67 398 void MicroBitAccelerometer::updateGesture()
Jonathan Austin 1:8aa5cdb4ab67 399 {
LancasterUniversity 38:1a9e8e5e23f2 400 // Check for High/Low G force events - typically impulses, impacts etc.
LancasterUniversity 38:1a9e8e5e23f2 401 // Again, during such spikes, these event take priority of the posture of the device.
LancasterUniversity 38:1a9e8e5e23f2 402 // For these events, we don't perform any low pass filtering.
LancasterUniversity 38:1a9e8e5e23f2 403 int force = instantaneousAccelerationSquared();
LancasterUniversity 38:1a9e8e5e23f2 404
LancasterUniversity 38:1a9e8e5e23f2 405 if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD)
LancasterUniversity 38:1a9e8e5e23f2 406 {
LancasterUniversity 38:1a9e8e5e23f2 407 if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD && !shake.impulse_3)
LancasterUniversity 38:1a9e8e5e23f2 408 {
LancasterUniversity 39:112df23f039f 409 MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_3G);
LancasterUniversity 38:1a9e8e5e23f2 410 shake.impulse_3 = 1;
LancasterUniversity 38:1a9e8e5e23f2 411 }
LancasterUniversity 38:1a9e8e5e23f2 412 if (force > MICROBIT_ACCELEROMETER_6G_THRESHOLD && !shake.impulse_6)
LancasterUniversity 38:1a9e8e5e23f2 413 {
LancasterUniversity 39:112df23f039f 414 MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_6G);
LancasterUniversity 38:1a9e8e5e23f2 415 shake.impulse_6 = 1;
LancasterUniversity 38:1a9e8e5e23f2 416 }
LancasterUniversity 38:1a9e8e5e23f2 417 if (force > MICROBIT_ACCELEROMETER_8G_THRESHOLD && !shake.impulse_8)
LancasterUniversity 38:1a9e8e5e23f2 418 {
LancasterUniversity 39:112df23f039f 419 MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_8G);
LancasterUniversity 38:1a9e8e5e23f2 420 shake.impulse_8 = 1;
LancasterUniversity 38:1a9e8e5e23f2 421 }
LancasterUniversity 38:1a9e8e5e23f2 422
LancasterUniversity 38:1a9e8e5e23f2 423 impulseSigma = 0;
LancasterUniversity 38:1a9e8e5e23f2 424 }
LancasterUniversity 38:1a9e8e5e23f2 425
LancasterUniversity 38:1a9e8e5e23f2 426 // Reset the impulse event onve the acceleration has subsided.
LancasterUniversity 38:1a9e8e5e23f2 427 if (impulseSigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
LancasterUniversity 38:1a9e8e5e23f2 428 impulseSigma++;
LancasterUniversity 38:1a9e8e5e23f2 429 else
LancasterUniversity 42:e2869e0fa366 430 shake.impulse_3 = shake.impulse_6 = shake.impulse_8 = 0;
LancasterUniversity 38:1a9e8e5e23f2 431
LancasterUniversity 38:1a9e8e5e23f2 432
Jonathan Austin 1:8aa5cdb4ab67 433 // Determine what it looks like we're doing based on the latest sample...
LancasterUniversity 39:112df23f039f 434 uint16_t g = instantaneousPosture();
Jonathan Austin 1:8aa5cdb4ab67 435
Jonathan Austin 1:8aa5cdb4ab67 436 // Perform some low pass filtering to reduce jitter from any detected effects
Jonathan Austin 1:8aa5cdb4ab67 437 if (g == currentGesture)
Jonathan Austin 1:8aa5cdb4ab67 438 {
Jonathan Austin 1:8aa5cdb4ab67 439 if (sigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
Jonathan Austin 1:8aa5cdb4ab67 440 sigma++;
Jonathan Austin 1:8aa5cdb4ab67 441 }
Jonathan Austin 1:8aa5cdb4ab67 442 else
Jonathan Austin 1:8aa5cdb4ab67 443 {
Jonathan Austin 1:8aa5cdb4ab67 444 currentGesture = g;
Jonathan Austin 1:8aa5cdb4ab67 445 sigma = 0;
Jonathan Austin 1:8aa5cdb4ab67 446 }
Jonathan Austin 1:8aa5cdb4ab67 447
Jonathan Austin 1:8aa5cdb4ab67 448 // If we've reached threshold, update our record and raise the relevant event...
Jonathan Austin 1:8aa5cdb4ab67 449 if (currentGesture != lastGesture && sigma >= MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
Jonathan Austin 1:8aa5cdb4ab67 450 {
Jonathan Austin 1:8aa5cdb4ab67 451 lastGesture = currentGesture;
Jonathan Austin 1:8aa5cdb4ab67 452 MicroBitEvent e(MICROBIT_ID_GESTURE, lastGesture);
Jonathan Austin 1:8aa5cdb4ab67 453 }
Jonathan Austin 1:8aa5cdb4ab67 454 }
Jonathan Austin 1:8aa5cdb4ab67 455
Jonathan Austin 1:8aa5cdb4ab67 456 /**
Jonathan Austin 1:8aa5cdb4ab67 457 * Attempts to set the sample rate of the accelerometer to the specified value (in ms).
Jonathan Austin 1:8aa5cdb4ab67 458 *
Jonathan Austin 1:8aa5cdb4ab67 459 * @param period the requested time between samples, in milliseconds.
Jonathan Austin 1:8aa5cdb4ab67 460 *
Jonathan Austin 1:8aa5cdb4ab67 461 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
Jonathan Austin 1:8aa5cdb4ab67 462 *
Jonathan Austin 1:8aa5cdb4ab67 463 * @code
Jonathan Austin 1:8aa5cdb4ab67 464 * // sample rate is now 20 ms.
Jonathan Austin 1:8aa5cdb4ab67 465 * accelerometer.setPeriod(20);
Jonathan Austin 1:8aa5cdb4ab67 466 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 467 *
Jonathan Austin 1:8aa5cdb4ab67 468 * @note The requested rate may not be possible on the hardware. In this case, the
Jonathan Austin 1:8aa5cdb4ab67 469 * nearest lower rate is chosen.
Jonathan Austin 1:8aa5cdb4ab67 470 */
Jonathan Austin 1:8aa5cdb4ab67 471 int MicroBitAccelerometer::setPeriod(int period)
Jonathan Austin 1:8aa5cdb4ab67 472 {
Jonathan Austin 1:8aa5cdb4ab67 473 this->samplePeriod = period;
Jonathan Austin 1:8aa5cdb4ab67 474 return this->configure();
Jonathan Austin 1:8aa5cdb4ab67 475 }
Jonathan Austin 1:8aa5cdb4ab67 476
Jonathan Austin 1:8aa5cdb4ab67 477 /**
Jonathan Austin 1:8aa5cdb4ab67 478 * Reads the currently configured sample rate of the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 479 *
Jonathan Austin 1:8aa5cdb4ab67 480 * @return The time between samples, in milliseconds.
Jonathan Austin 1:8aa5cdb4ab67 481 */
Jonathan Austin 1:8aa5cdb4ab67 482 int MicroBitAccelerometer::getPeriod()
Jonathan Austin 1:8aa5cdb4ab67 483 {
Jonathan Austin 1:8aa5cdb4ab67 484 return (int)samplePeriod;
Jonathan Austin 1:8aa5cdb4ab67 485 }
Jonathan Austin 1:8aa5cdb4ab67 486
Jonathan Austin 1:8aa5cdb4ab67 487 /**
Jonathan Austin 1:8aa5cdb4ab67 488 * Attempts to set the sample range of the accelerometer to the specified value (in g).
Jonathan Austin 1:8aa5cdb4ab67 489 *
Jonathan Austin 1:8aa5cdb4ab67 490 * @param range The requested sample range of samples, in g.
Jonathan Austin 1:8aa5cdb4ab67 491 *
Jonathan Austin 1:8aa5cdb4ab67 492 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
Jonathan Austin 1:8aa5cdb4ab67 493 *
Jonathan Austin 1:8aa5cdb4ab67 494 * @code
Jonathan Austin 1:8aa5cdb4ab67 495 * // the sample range of the accelerometer is now 8G.
Jonathan Austin 1:8aa5cdb4ab67 496 * accelerometer.setRange(8);
Jonathan Austin 1:8aa5cdb4ab67 497 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 498 *
Jonathan Austin 1:8aa5cdb4ab67 499 * @note The requested range may not be possible on the hardware. In this case, the
Jonathan Austin 1:8aa5cdb4ab67 500 * nearest lower range is chosen.
Jonathan Austin 1:8aa5cdb4ab67 501 */
Jonathan Austin 1:8aa5cdb4ab67 502 int MicroBitAccelerometer::setRange(int range)
Jonathan Austin 1:8aa5cdb4ab67 503 {
Jonathan Austin 1:8aa5cdb4ab67 504 this->sampleRange = range;
Jonathan Austin 1:8aa5cdb4ab67 505 return this->configure();
Jonathan Austin 1:8aa5cdb4ab67 506 }
Jonathan Austin 1:8aa5cdb4ab67 507
Jonathan Austin 1:8aa5cdb4ab67 508 /**
Jonathan Austin 1:8aa5cdb4ab67 509 * Reads the currently configured sample range of the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 510 *
Jonathan Austin 1:8aa5cdb4ab67 511 * @return The sample range, in g.
Jonathan Austin 1:8aa5cdb4ab67 512 */
Jonathan Austin 1:8aa5cdb4ab67 513 int MicroBitAccelerometer::getRange()
Jonathan Austin 1:8aa5cdb4ab67 514 {
Jonathan Austin 1:8aa5cdb4ab67 515 return (int)sampleRange;
Jonathan Austin 1:8aa5cdb4ab67 516 }
Jonathan Austin 1:8aa5cdb4ab67 517
Jonathan Austin 1:8aa5cdb4ab67 518 /**
Jonathan Austin 1:8aa5cdb4ab67 519 * Reads the value of the X axis from the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 520 *
Jonathan Austin 1:8aa5cdb4ab67 521 * @param system The coordinate system to use. By default, a simple cartesian system is provided.
Jonathan Austin 1:8aa5cdb4ab67 522 *
Jonathan Austin 1:8aa5cdb4ab67 523 * @return The force measured in the X axis, in milli-g.
Jonathan Austin 1:8aa5cdb4ab67 524 *
Jonathan Austin 1:8aa5cdb4ab67 525 * @code
Jonathan Austin 1:8aa5cdb4ab67 526 * accelerometer.getX();
Jonathan Austin 1:8aa5cdb4ab67 527 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 528 */
Jonathan Austin 1:8aa5cdb4ab67 529 int MicroBitAccelerometer::getX(MicroBitCoordinateSystem system)
Jonathan Austin 1:8aa5cdb4ab67 530 {
Jonathan Austin 1:8aa5cdb4ab67 531 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 532
Jonathan Austin 1:8aa5cdb4ab67 533 switch (system)
Jonathan Austin 1:8aa5cdb4ab67 534 {
Jonathan Austin 1:8aa5cdb4ab67 535 case SIMPLE_CARTESIAN:
Jonathan Austin 1:8aa5cdb4ab67 536 return -sample.x;
Jonathan Austin 1:8aa5cdb4ab67 537
Jonathan Austin 1:8aa5cdb4ab67 538 case NORTH_EAST_DOWN:
Jonathan Austin 1:8aa5cdb4ab67 539 return sample.y;
Jonathan Austin 1:8aa5cdb4ab67 540
Jonathan Austin 1:8aa5cdb4ab67 541 case RAW:
Jonathan Austin 1:8aa5cdb4ab67 542 default:
Jonathan Austin 1:8aa5cdb4ab67 543 return sample.x;
Jonathan Austin 1:8aa5cdb4ab67 544 }
Jonathan Austin 1:8aa5cdb4ab67 545 }
Jonathan Austin 1:8aa5cdb4ab67 546
Jonathan Austin 1:8aa5cdb4ab67 547 /**
Jonathan Austin 1:8aa5cdb4ab67 548 * Reads the value of the Y axis from the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 549 *
Jonathan Austin 1:8aa5cdb4ab67 550 * @return The force measured in the Y axis, in milli-g.
Jonathan Austin 1:8aa5cdb4ab67 551 *
Jonathan Austin 1:8aa5cdb4ab67 552 * @code
Jonathan Austin 1:8aa5cdb4ab67 553 * accelerometer.getY();
Jonathan Austin 1:8aa5cdb4ab67 554 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 555 */
Jonathan Austin 1:8aa5cdb4ab67 556 int MicroBitAccelerometer::getY(MicroBitCoordinateSystem system)
Jonathan Austin 1:8aa5cdb4ab67 557 {
Jonathan Austin 1:8aa5cdb4ab67 558 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 559
Jonathan Austin 1:8aa5cdb4ab67 560 switch (system)
Jonathan Austin 1:8aa5cdb4ab67 561 {
Jonathan Austin 1:8aa5cdb4ab67 562 case SIMPLE_CARTESIAN:
Jonathan Austin 1:8aa5cdb4ab67 563 return -sample.y;
Jonathan Austin 1:8aa5cdb4ab67 564
Jonathan Austin 1:8aa5cdb4ab67 565 case NORTH_EAST_DOWN:
Jonathan Austin 1:8aa5cdb4ab67 566 return -sample.x;
Jonathan Austin 1:8aa5cdb4ab67 567
Jonathan Austin 1:8aa5cdb4ab67 568 case RAW:
Jonathan Austin 1:8aa5cdb4ab67 569 default:
Jonathan Austin 1:8aa5cdb4ab67 570 return sample.y;
Jonathan Austin 1:8aa5cdb4ab67 571 }
Jonathan Austin 1:8aa5cdb4ab67 572 }
Jonathan Austin 1:8aa5cdb4ab67 573
Jonathan Austin 1:8aa5cdb4ab67 574 /**
Jonathan Austin 1:8aa5cdb4ab67 575 * Reads the value of the Z axis from the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 576 *
Jonathan Austin 1:8aa5cdb4ab67 577 * @return The force measured in the Z axis, in milli-g.
Jonathan Austin 1:8aa5cdb4ab67 578 *
Jonathan Austin 1:8aa5cdb4ab67 579 * @code
Jonathan Austin 1:8aa5cdb4ab67 580 * accelerometer.getZ();
Jonathan Austin 1:8aa5cdb4ab67 581 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 582 */
Jonathan Austin 1:8aa5cdb4ab67 583 int MicroBitAccelerometer::getZ(MicroBitCoordinateSystem system)
Jonathan Austin 1:8aa5cdb4ab67 584 {
Jonathan Austin 1:8aa5cdb4ab67 585 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 586
Jonathan Austin 1:8aa5cdb4ab67 587 switch (system)
Jonathan Austin 1:8aa5cdb4ab67 588 {
Jonathan Austin 1:8aa5cdb4ab67 589 case NORTH_EAST_DOWN:
Jonathan Austin 1:8aa5cdb4ab67 590 return -sample.z;
Jonathan Austin 1:8aa5cdb4ab67 591
Jonathan Austin 1:8aa5cdb4ab67 592 case SIMPLE_CARTESIAN:
Jonathan Austin 1:8aa5cdb4ab67 593 case RAW:
Jonathan Austin 1:8aa5cdb4ab67 594 default:
Jonathan Austin 1:8aa5cdb4ab67 595 return sample.z;
Jonathan Austin 1:8aa5cdb4ab67 596 }
Jonathan Austin 1:8aa5cdb4ab67 597 }
Jonathan Austin 1:8aa5cdb4ab67 598
Jonathan Austin 1:8aa5cdb4ab67 599 /**
Jonathan Austin 1:8aa5cdb4ab67 600 * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 601 *
Jonathan Austin 1:8aa5cdb4ab67 602 * @return The pitch of the device, in degrees.
Jonathan Austin 1:8aa5cdb4ab67 603 *
Jonathan Austin 1:8aa5cdb4ab67 604 * @code
Jonathan Austin 1:8aa5cdb4ab67 605 * accelerometer.getPitch();
Jonathan Austin 1:8aa5cdb4ab67 606 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 607 */
Jonathan Austin 1:8aa5cdb4ab67 608 int MicroBitAccelerometer::getPitch()
Jonathan Austin 1:8aa5cdb4ab67 609 {
Jonathan Austin 1:8aa5cdb4ab67 610 return (int) ((360*getPitchRadians()) / (2*PI));
Jonathan Austin 1:8aa5cdb4ab67 611 }
Jonathan Austin 1:8aa5cdb4ab67 612
Jonathan Austin 1:8aa5cdb4ab67 613 /**
Jonathan Austin 1:8aa5cdb4ab67 614 * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 615 *
Jonathan Austin 1:8aa5cdb4ab67 616 * @return The pitch of the device, in radians.
Jonathan Austin 1:8aa5cdb4ab67 617 *
Jonathan Austin 1:8aa5cdb4ab67 618 * @code
Jonathan Austin 1:8aa5cdb4ab67 619 * accelerometer.getPitchRadians();
Jonathan Austin 1:8aa5cdb4ab67 620 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 621 */
Jonathan Austin 1:8aa5cdb4ab67 622 float MicroBitAccelerometer::getPitchRadians()
Jonathan Austin 1:8aa5cdb4ab67 623 {
Jonathan Austin 1:8aa5cdb4ab67 624 if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
Jonathan Austin 1:8aa5cdb4ab67 625 recalculatePitchRoll();
Jonathan Austin 1:8aa5cdb4ab67 626
Jonathan Austin 1:8aa5cdb4ab67 627 return pitch;
Jonathan Austin 1:8aa5cdb4ab67 628 }
Jonathan Austin 1:8aa5cdb4ab67 629
Jonathan Austin 1:8aa5cdb4ab67 630 /**
Jonathan Austin 1:8aa5cdb4ab67 631 * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 632 *
Jonathan Austin 1:8aa5cdb4ab67 633 * @return The roll of the device, in degrees.
Jonathan Austin 1:8aa5cdb4ab67 634 *
Jonathan Austin 1:8aa5cdb4ab67 635 * @code
Jonathan Austin 1:8aa5cdb4ab67 636 * accelerometer.getRoll();
Jonathan Austin 1:8aa5cdb4ab67 637 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 638 */
Jonathan Austin 1:8aa5cdb4ab67 639 int MicroBitAccelerometer::getRoll()
Jonathan Austin 1:8aa5cdb4ab67 640 {
Jonathan Austin 1:8aa5cdb4ab67 641 return (int) ((360*getRollRadians()) / (2*PI));
Jonathan Austin 1:8aa5cdb4ab67 642 }
Jonathan Austin 1:8aa5cdb4ab67 643
Jonathan Austin 1:8aa5cdb4ab67 644 /**
Jonathan Austin 1:8aa5cdb4ab67 645 * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 646 *
Jonathan Austin 1:8aa5cdb4ab67 647 * @return The roll of the device, in radians.
Jonathan Austin 1:8aa5cdb4ab67 648 *
Jonathan Austin 1:8aa5cdb4ab67 649 * @code
Jonathan Austin 1:8aa5cdb4ab67 650 * accelerometer.getRollRadians();
Jonathan Austin 1:8aa5cdb4ab67 651 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 652 */
Jonathan Austin 1:8aa5cdb4ab67 653 float MicroBitAccelerometer::getRollRadians()
Jonathan Austin 1:8aa5cdb4ab67 654 {
Jonathan Austin 1:8aa5cdb4ab67 655 if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
Jonathan Austin 1:8aa5cdb4ab67 656 recalculatePitchRoll();
Jonathan Austin 1:8aa5cdb4ab67 657
Jonathan Austin 1:8aa5cdb4ab67 658 return roll;
Jonathan Austin 1:8aa5cdb4ab67 659 }
Jonathan Austin 1:8aa5cdb4ab67 660
Jonathan Austin 1:8aa5cdb4ab67 661 /**
Jonathan Austin 1:8aa5cdb4ab67 662 * Recalculate roll and pitch values for the current sample.
Jonathan Austin 1:8aa5cdb4ab67 663 *
Jonathan Austin 1:8aa5cdb4ab67 664 * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather
Jonathan Austin 1:8aa5cdb4ab67 665 * heavyweight for a CPU without a floating point unit.
Jonathan Austin 1:8aa5cdb4ab67 666 */
Jonathan Austin 1:8aa5cdb4ab67 667 void MicroBitAccelerometer::recalculatePitchRoll()
Jonathan Austin 1:8aa5cdb4ab67 668 {
Jonathan Austin 1:8aa5cdb4ab67 669 float x = (float) getX(NORTH_EAST_DOWN);
Jonathan Austin 1:8aa5cdb4ab67 670 float y = (float) getY(NORTH_EAST_DOWN);
Jonathan Austin 1:8aa5cdb4ab67 671 float z = (float) getZ(NORTH_EAST_DOWN);
Jonathan Austin 1:8aa5cdb4ab67 672
LancasterUniversity 6:2e1c2e0d8c7a 673 roll = atan2((double)getY(NORTH_EAST_DOWN), (double)getZ(NORTH_EAST_DOWN));
LancasterUniversity 6:2e1c2e0d8c7a 674
Jonathan Austin 1:8aa5cdb4ab67 675 pitch = atan(-x / (y*sin(roll) + z*cos(roll)));
Jonathan Austin 1:8aa5cdb4ab67 676 status |= MICROBIT_ACCEL_PITCH_ROLL_VALID;
Jonathan Austin 1:8aa5cdb4ab67 677 }
Jonathan Austin 1:8aa5cdb4ab67 678
Jonathan Austin 1:8aa5cdb4ab67 679 /**
Jonathan Austin 1:8aa5cdb4ab67 680 * Retrieves the last recorded gesture.
Jonathan Austin 1:8aa5cdb4ab67 681 *
Jonathan Austin 1:8aa5cdb4ab67 682 * @return The last gesture that was detected.
Jonathan Austin 1:8aa5cdb4ab67 683 *
Jonathan Austin 1:8aa5cdb4ab67 684 * Example:
Jonathan Austin 1:8aa5cdb4ab67 685 * @code
Jonathan Austin 1:8aa5cdb4ab67 686 * MicroBitDisplay display;
Jonathan Austin 1:8aa5cdb4ab67 687 *
Jonathan Austin 1:8aa5cdb4ab67 688 * if (accelerometer.getGesture() == SHAKE)
Jonathan Austin 1:8aa5cdb4ab67 689 * display.scroll("SHAKE!");
Jonathan Austin 1:8aa5cdb4ab67 690 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 691 */
LancasterUniversity 39:112df23f039f 692 uint16_t MicroBitAccelerometer::getGesture()
Jonathan Austin 1:8aa5cdb4ab67 693 {
Jonathan Austin 1:8aa5cdb4ab67 694 return lastGesture;
Jonathan Austin 1:8aa5cdb4ab67 695 }
Jonathan Austin 1:8aa5cdb4ab67 696
Jonathan Austin 1:8aa5cdb4ab67 697 /**
Jonathan Austin 1:8aa5cdb4ab67 698 * A periodic callback invoked by the fiber scheduler idle thread.
Jonathan Austin 1:8aa5cdb4ab67 699 *
Jonathan Austin 1:8aa5cdb4ab67 700 * Internally calls updateSample().
Jonathan Austin 1:8aa5cdb4ab67 701 */
Jonathan Austin 1:8aa5cdb4ab67 702 void MicroBitAccelerometer::idleTick()
Jonathan Austin 1:8aa5cdb4ab67 703 {
Jonathan Austin 1:8aa5cdb4ab67 704 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 705 }
Jonathan Austin 1:8aa5cdb4ab67 706
Jonathan Austin 1:8aa5cdb4ab67 707 /**
Jonathan Austin 1:8aa5cdb4ab67 708 * Destructor for MicroBitAccelerometer, where we deregister from the array of fiber components.
Jonathan Austin 1:8aa5cdb4ab67 709 */
Jonathan Austin 1:8aa5cdb4ab67 710 MicroBitAccelerometer::~MicroBitAccelerometer()
Jonathan Austin 1:8aa5cdb4ab67 711 {
Jonathan Austin 1:8aa5cdb4ab67 712 fiber_remove_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 713 }
Jonathan Austin 1:8aa5cdb4ab67 714
Jonathan Austin 1:8aa5cdb4ab67 715 const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = {
Jonathan Austin 1:8aa5cdb4ab67 716 {2, 0},
Jonathan Austin 1:8aa5cdb4ab67 717 {4, 1},
Jonathan Austin 1:8aa5cdb4ab67 718 {8, 2}
Jonathan Austin 1:8aa5cdb4ab67 719 };
Jonathan Austin 1:8aa5cdb4ab67 720
Jonathan Austin 1:8aa5cdb4ab67 721 const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = {
Jonathan Austin 1:8aa5cdb4ab67 722 {1250, 0x00},
Jonathan Austin 1:8aa5cdb4ab67 723 {2500, 0x08},
Jonathan Austin 1:8aa5cdb4ab67 724 {5000, 0x10},
Jonathan Austin 1:8aa5cdb4ab67 725 {10000, 0x18},
Jonathan Austin 1:8aa5cdb4ab67 726 {20000, 0x20},
Jonathan Austin 1:8aa5cdb4ab67 727 {80000, 0x28},
Jonathan Austin 1:8aa5cdb4ab67 728 {160000, 0x30},
Jonathan Austin 1:8aa5cdb4ab67 729 {640000, 0x38}
LancasterUniversity 6:2e1c2e0d8c7a 730 };