No Changes

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit

Fork of microbit-dal by Lancaster University

Committer:
Asimov
Date:
Fri Jan 13 21:14:06 2017 +0000
Revision:
75:ae9a17da71af
Parent:
65:f7ebabf23e15
No Changes

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
LancasterUniversity 65:f7ebabf23e15 351 // If we detected a zero crossing in this sample period, count this.
LancasterUniversity 65:f7ebabf23e15 352 if (shakeDetected && shake.count < MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD)
LancasterUniversity 55:6920de8ba10a 353 {
LancasterUniversity 65:f7ebabf23e15 354 shake.count++;
LancasterUniversity 65:f7ebabf23e15 355
LancasterUniversity 65:f7ebabf23e15 356 if (shake.count == 1)
LancasterUniversity 65:f7ebabf23e15 357 shake.timer = 0;
LancasterUniversity 65:f7ebabf23e15 358
LancasterUniversity 65:f7ebabf23e15 359 if (shake.count == MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD)
Jonathan Austin 1:8aa5cdb4ab67 360 {
LancasterUniversity 65:f7ebabf23e15 361 shake.shaken = 1;
LancasterUniversity 65:f7ebabf23e15 362 shake.timer = 0;
LancasterUniversity 65:f7ebabf23e15 363 return MICROBIT_ACCELEROMETER_EVT_SHAKE;
Jonathan Austin 1:8aa5cdb4ab67 364 }
Jonathan Austin 1:8aa5cdb4ab67 365 }
Jonathan Austin 1:8aa5cdb4ab67 366
LancasterUniversity 65:f7ebabf23e15 367 // measure how long we have been detecting a SHAKE event.
LancasterUniversity 65:f7ebabf23e15 368 if (shake.count > 0)
LancasterUniversity 65:f7ebabf23e15 369 {
LancasterUniversity 65:f7ebabf23e15 370 shake.timer++;
LancasterUniversity 65:f7ebabf23e15 371
LancasterUniversity 65:f7ebabf23e15 372 // If we've issued a SHAKE event already, and sufficient time has assed, allow another SHAKE event to be issued.
LancasterUniversity 65:f7ebabf23e15 373 if (shake.shaken && shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_RTX)
LancasterUniversity 65:f7ebabf23e15 374 {
LancasterUniversity 65:f7ebabf23e15 375 shake.shaken = 0;
LancasterUniversity 65:f7ebabf23e15 376 shake.timer = 0;
LancasterUniversity 65:f7ebabf23e15 377 shake.count = 0;
LancasterUniversity 65:f7ebabf23e15 378 }
LancasterUniversity 65:f7ebabf23e15 379
LancasterUniversity 65:f7ebabf23e15 380 // Decay our count of zero crossings over time. We don't want them to accumulate if the user performs slow moving motions.
LancasterUniversity 65:f7ebabf23e15 381 else if (!shake.shaken && shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_DAMPING)
LancasterUniversity 65:f7ebabf23e15 382 {
LancasterUniversity 65:f7ebabf23e15 383 shake.timer = 0;
LancasterUniversity 65:f7ebabf23e15 384 if (shake.count > 0)
LancasterUniversity 65:f7ebabf23e15 385 shake.count--;
LancasterUniversity 65:f7ebabf23e15 386 }
LancasterUniversity 65:f7ebabf23e15 387 }
Jonathan Austin 1:8aa5cdb4ab67 388
LancasterUniversity 42:e2869e0fa366 389 if (instantaneousAccelerationSquared() < MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD)
LancasterUniversity 42:e2869e0fa366 390 return MICROBIT_ACCELEROMETER_EVT_FREEFALL;
LancasterUniversity 42:e2869e0fa366 391
Jonathan Austin 1:8aa5cdb4ab67 392 // Determine our posture.
Jonathan Austin 1:8aa5cdb4ab67 393 if (getX() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 394 return MICROBIT_ACCELEROMETER_EVT_TILT_LEFT;
Jonathan Austin 1:8aa5cdb4ab67 395
Jonathan Austin 1:8aa5cdb4ab67 396 if (getX() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 397 return MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT;
Jonathan Austin 1:8aa5cdb4ab67 398
Jonathan Austin 1:8aa5cdb4ab67 399 if (getY() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 400 return MICROBIT_ACCELEROMETER_EVT_TILT_DOWN;
Jonathan Austin 1:8aa5cdb4ab67 401
Jonathan Austin 1:8aa5cdb4ab67 402 if (getY() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 403 return MICROBIT_ACCELEROMETER_EVT_TILT_UP;
Jonathan Austin 1:8aa5cdb4ab67 404
Jonathan Austin 1:8aa5cdb4ab67 405 if (getZ() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 406 return MICROBIT_ACCELEROMETER_EVT_FACE_UP;
Jonathan Austin 1:8aa5cdb4ab67 407
Jonathan Austin 1:8aa5cdb4ab67 408 if (getZ() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
LancasterUniversity 39:112df23f039f 409 return MICROBIT_ACCELEROMETER_EVT_FACE_DOWN;
Jonathan Austin 1:8aa5cdb4ab67 410
LancasterUniversity 39:112df23f039f 411 return MICROBIT_ACCELEROMETER_EVT_NONE;
Jonathan Austin 1:8aa5cdb4ab67 412 }
Jonathan Austin 1:8aa5cdb4ab67 413
Jonathan Austin 1:8aa5cdb4ab67 414 /**
Jonathan Austin 1:8aa5cdb4ab67 415 * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote
Jonathan Austin 1:8aa5cdb4ab67 416 * stability.
Jonathan Austin 1:8aa5cdb4ab67 417 */
Jonathan Austin 1:8aa5cdb4ab67 418 void MicroBitAccelerometer::updateGesture()
Jonathan Austin 1:8aa5cdb4ab67 419 {
LancasterUniversity 38:1a9e8e5e23f2 420 // Check for High/Low G force events - typically impulses, impacts etc.
LancasterUniversity 38:1a9e8e5e23f2 421 // Again, during such spikes, these event take priority of the posture of the device.
LancasterUniversity 38:1a9e8e5e23f2 422 // For these events, we don't perform any low pass filtering.
LancasterUniversity 38:1a9e8e5e23f2 423 int force = instantaneousAccelerationSquared();
LancasterUniversity 38:1a9e8e5e23f2 424
LancasterUniversity 38:1a9e8e5e23f2 425 if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD)
LancasterUniversity 38:1a9e8e5e23f2 426 {
LancasterUniversity 38:1a9e8e5e23f2 427 if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD && !shake.impulse_3)
LancasterUniversity 38:1a9e8e5e23f2 428 {
LancasterUniversity 39:112df23f039f 429 MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_3G);
LancasterUniversity 38:1a9e8e5e23f2 430 shake.impulse_3 = 1;
LancasterUniversity 38:1a9e8e5e23f2 431 }
LancasterUniversity 38:1a9e8e5e23f2 432 if (force > MICROBIT_ACCELEROMETER_6G_THRESHOLD && !shake.impulse_6)
LancasterUniversity 38:1a9e8e5e23f2 433 {
LancasterUniversity 39:112df23f039f 434 MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_6G);
LancasterUniversity 38:1a9e8e5e23f2 435 shake.impulse_6 = 1;
LancasterUniversity 38:1a9e8e5e23f2 436 }
LancasterUniversity 38:1a9e8e5e23f2 437 if (force > MICROBIT_ACCELEROMETER_8G_THRESHOLD && !shake.impulse_8)
LancasterUniversity 38:1a9e8e5e23f2 438 {
LancasterUniversity 39:112df23f039f 439 MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_8G);
LancasterUniversity 38:1a9e8e5e23f2 440 shake.impulse_8 = 1;
LancasterUniversity 38:1a9e8e5e23f2 441 }
LancasterUniversity 38:1a9e8e5e23f2 442
LancasterUniversity 38:1a9e8e5e23f2 443 impulseSigma = 0;
LancasterUniversity 38:1a9e8e5e23f2 444 }
LancasterUniversity 38:1a9e8e5e23f2 445
LancasterUniversity 38:1a9e8e5e23f2 446 // Reset the impulse event onve the acceleration has subsided.
LancasterUniversity 38:1a9e8e5e23f2 447 if (impulseSigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
LancasterUniversity 38:1a9e8e5e23f2 448 impulseSigma++;
LancasterUniversity 38:1a9e8e5e23f2 449 else
LancasterUniversity 42:e2869e0fa366 450 shake.impulse_3 = shake.impulse_6 = shake.impulse_8 = 0;
LancasterUniversity 38:1a9e8e5e23f2 451
LancasterUniversity 38:1a9e8e5e23f2 452
Jonathan Austin 1:8aa5cdb4ab67 453 // Determine what it looks like we're doing based on the latest sample...
LancasterUniversity 39:112df23f039f 454 uint16_t g = instantaneousPosture();
Jonathan Austin 1:8aa5cdb4ab67 455
LancasterUniversity 65:f7ebabf23e15 456 if (g == MICROBIT_ACCELEROMETER_EVT_SHAKE)
LancasterUniversity 65:f7ebabf23e15 457 {
LancasterUniversity 65:f7ebabf23e15 458 MicroBitEvent e(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_SHAKE);
LancasterUniversity 65:f7ebabf23e15 459 return;
LancasterUniversity 65:f7ebabf23e15 460 }
LancasterUniversity 65:f7ebabf23e15 461
Jonathan Austin 1:8aa5cdb4ab67 462 // Perform some low pass filtering to reduce jitter from any detected effects
Jonathan Austin 1:8aa5cdb4ab67 463 if (g == currentGesture)
Jonathan Austin 1:8aa5cdb4ab67 464 {
Jonathan Austin 1:8aa5cdb4ab67 465 if (sigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
Jonathan Austin 1:8aa5cdb4ab67 466 sigma++;
Jonathan Austin 1:8aa5cdb4ab67 467 }
Jonathan Austin 1:8aa5cdb4ab67 468 else
Jonathan Austin 1:8aa5cdb4ab67 469 {
Jonathan Austin 1:8aa5cdb4ab67 470 currentGesture = g;
Jonathan Austin 1:8aa5cdb4ab67 471 sigma = 0;
Jonathan Austin 1:8aa5cdb4ab67 472 }
Jonathan Austin 1:8aa5cdb4ab67 473
Jonathan Austin 1:8aa5cdb4ab67 474 // If we've reached threshold, update our record and raise the relevant event...
Jonathan Austin 1:8aa5cdb4ab67 475 if (currentGesture != lastGesture && sigma >= MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
Jonathan Austin 1:8aa5cdb4ab67 476 {
Jonathan Austin 1:8aa5cdb4ab67 477 lastGesture = currentGesture;
Jonathan Austin 1:8aa5cdb4ab67 478 MicroBitEvent e(MICROBIT_ID_GESTURE, lastGesture);
Jonathan Austin 1:8aa5cdb4ab67 479 }
Jonathan Austin 1:8aa5cdb4ab67 480 }
Jonathan Austin 1:8aa5cdb4ab67 481
Jonathan Austin 1:8aa5cdb4ab67 482 /**
Jonathan Austin 1:8aa5cdb4ab67 483 * Attempts to set the sample rate of the accelerometer to the specified value (in ms).
Jonathan Austin 1:8aa5cdb4ab67 484 *
Jonathan Austin 1:8aa5cdb4ab67 485 * @param period the requested time between samples, in milliseconds.
Jonathan Austin 1:8aa5cdb4ab67 486 *
Jonathan Austin 1:8aa5cdb4ab67 487 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
Jonathan Austin 1:8aa5cdb4ab67 488 *
Jonathan Austin 1:8aa5cdb4ab67 489 * @code
Jonathan Austin 1:8aa5cdb4ab67 490 * // sample rate is now 20 ms.
Jonathan Austin 1:8aa5cdb4ab67 491 * accelerometer.setPeriod(20);
Jonathan Austin 1:8aa5cdb4ab67 492 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 493 *
Jonathan Austin 1:8aa5cdb4ab67 494 * @note The requested rate may not be possible on the hardware. In this case, the
Jonathan Austin 1:8aa5cdb4ab67 495 * nearest lower rate is chosen.
Jonathan Austin 1:8aa5cdb4ab67 496 */
Jonathan Austin 1:8aa5cdb4ab67 497 int MicroBitAccelerometer::setPeriod(int period)
Jonathan Austin 1:8aa5cdb4ab67 498 {
Jonathan Austin 1:8aa5cdb4ab67 499 this->samplePeriod = period;
Jonathan Austin 1:8aa5cdb4ab67 500 return this->configure();
Jonathan Austin 1:8aa5cdb4ab67 501 }
Jonathan Austin 1:8aa5cdb4ab67 502
Jonathan Austin 1:8aa5cdb4ab67 503 /**
Jonathan Austin 1:8aa5cdb4ab67 504 * Reads the currently configured sample rate of the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 505 *
Jonathan Austin 1:8aa5cdb4ab67 506 * @return The time between samples, in milliseconds.
Jonathan Austin 1:8aa5cdb4ab67 507 */
Jonathan Austin 1:8aa5cdb4ab67 508 int MicroBitAccelerometer::getPeriod()
Jonathan Austin 1:8aa5cdb4ab67 509 {
Jonathan Austin 1:8aa5cdb4ab67 510 return (int)samplePeriod;
Jonathan Austin 1:8aa5cdb4ab67 511 }
Jonathan Austin 1:8aa5cdb4ab67 512
Jonathan Austin 1:8aa5cdb4ab67 513 /**
Jonathan Austin 1:8aa5cdb4ab67 514 * Attempts to set the sample range of the accelerometer to the specified value (in g).
Jonathan Austin 1:8aa5cdb4ab67 515 *
Jonathan Austin 1:8aa5cdb4ab67 516 * @param range The requested sample range of samples, in g.
Jonathan Austin 1:8aa5cdb4ab67 517 *
Jonathan Austin 1:8aa5cdb4ab67 518 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
Jonathan Austin 1:8aa5cdb4ab67 519 *
Jonathan Austin 1:8aa5cdb4ab67 520 * @code
Jonathan Austin 1:8aa5cdb4ab67 521 * // the sample range of the accelerometer is now 8G.
Jonathan Austin 1:8aa5cdb4ab67 522 * accelerometer.setRange(8);
Jonathan Austin 1:8aa5cdb4ab67 523 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 524 *
Jonathan Austin 1:8aa5cdb4ab67 525 * @note The requested range may not be possible on the hardware. In this case, the
Jonathan Austin 1:8aa5cdb4ab67 526 * nearest lower range is chosen.
Jonathan Austin 1:8aa5cdb4ab67 527 */
Jonathan Austin 1:8aa5cdb4ab67 528 int MicroBitAccelerometer::setRange(int range)
Jonathan Austin 1:8aa5cdb4ab67 529 {
Jonathan Austin 1:8aa5cdb4ab67 530 this->sampleRange = range;
Jonathan Austin 1:8aa5cdb4ab67 531 return this->configure();
Jonathan Austin 1:8aa5cdb4ab67 532 }
Jonathan Austin 1:8aa5cdb4ab67 533
Jonathan Austin 1:8aa5cdb4ab67 534 /**
Jonathan Austin 1:8aa5cdb4ab67 535 * Reads the currently configured sample range of the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 536 *
Jonathan Austin 1:8aa5cdb4ab67 537 * @return The sample range, in g.
Jonathan Austin 1:8aa5cdb4ab67 538 */
Jonathan Austin 1:8aa5cdb4ab67 539 int MicroBitAccelerometer::getRange()
Jonathan Austin 1:8aa5cdb4ab67 540 {
Jonathan Austin 1:8aa5cdb4ab67 541 return (int)sampleRange;
Jonathan Austin 1:8aa5cdb4ab67 542 }
Jonathan Austin 1:8aa5cdb4ab67 543
Jonathan Austin 1:8aa5cdb4ab67 544 /**
Jonathan Austin 1:8aa5cdb4ab67 545 * Reads the value of the X axis from the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 546 *
Jonathan Austin 1:8aa5cdb4ab67 547 * @param system The coordinate system to use. By default, a simple cartesian system is provided.
Jonathan Austin 1:8aa5cdb4ab67 548 *
Jonathan Austin 1:8aa5cdb4ab67 549 * @return The force measured in the X axis, in milli-g.
Jonathan Austin 1:8aa5cdb4ab67 550 *
Jonathan Austin 1:8aa5cdb4ab67 551 * @code
Jonathan Austin 1:8aa5cdb4ab67 552 * accelerometer.getX();
Jonathan Austin 1:8aa5cdb4ab67 553 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 554 */
Jonathan Austin 1:8aa5cdb4ab67 555 int MicroBitAccelerometer::getX(MicroBitCoordinateSystem system)
Jonathan Austin 1:8aa5cdb4ab67 556 {
Jonathan Austin 1:8aa5cdb4ab67 557 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 558
Jonathan Austin 1:8aa5cdb4ab67 559 switch (system)
Jonathan Austin 1:8aa5cdb4ab67 560 {
Jonathan Austin 1:8aa5cdb4ab67 561 case SIMPLE_CARTESIAN:
Jonathan Austin 1:8aa5cdb4ab67 562 return -sample.x;
Jonathan Austin 1:8aa5cdb4ab67 563
Jonathan Austin 1:8aa5cdb4ab67 564 case NORTH_EAST_DOWN:
Jonathan Austin 1:8aa5cdb4ab67 565 return sample.y;
Jonathan Austin 1:8aa5cdb4ab67 566
Jonathan Austin 1:8aa5cdb4ab67 567 case RAW:
Jonathan Austin 1:8aa5cdb4ab67 568 default:
Jonathan Austin 1:8aa5cdb4ab67 569 return sample.x;
Jonathan Austin 1:8aa5cdb4ab67 570 }
Jonathan Austin 1:8aa5cdb4ab67 571 }
Jonathan Austin 1:8aa5cdb4ab67 572
Jonathan Austin 1:8aa5cdb4ab67 573 /**
Jonathan Austin 1:8aa5cdb4ab67 574 * Reads the value of the Y axis from the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 575 *
Jonathan Austin 1:8aa5cdb4ab67 576 * @return The force measured in the Y axis, in milli-g.
Jonathan Austin 1:8aa5cdb4ab67 577 *
Jonathan Austin 1:8aa5cdb4ab67 578 * @code
Jonathan Austin 1:8aa5cdb4ab67 579 * accelerometer.getY();
Jonathan Austin 1:8aa5cdb4ab67 580 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 581 */
Jonathan Austin 1:8aa5cdb4ab67 582 int MicroBitAccelerometer::getY(MicroBitCoordinateSystem system)
Jonathan Austin 1:8aa5cdb4ab67 583 {
Jonathan Austin 1:8aa5cdb4ab67 584 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 585
Jonathan Austin 1:8aa5cdb4ab67 586 switch (system)
Jonathan Austin 1:8aa5cdb4ab67 587 {
Jonathan Austin 1:8aa5cdb4ab67 588 case SIMPLE_CARTESIAN:
Jonathan Austin 1:8aa5cdb4ab67 589 return -sample.y;
Jonathan Austin 1:8aa5cdb4ab67 590
Jonathan Austin 1:8aa5cdb4ab67 591 case NORTH_EAST_DOWN:
Jonathan Austin 1:8aa5cdb4ab67 592 return -sample.x;
Jonathan Austin 1:8aa5cdb4ab67 593
Jonathan Austin 1:8aa5cdb4ab67 594 case RAW:
Jonathan Austin 1:8aa5cdb4ab67 595 default:
Jonathan Austin 1:8aa5cdb4ab67 596 return sample.y;
Jonathan Austin 1:8aa5cdb4ab67 597 }
Jonathan Austin 1:8aa5cdb4ab67 598 }
Jonathan Austin 1:8aa5cdb4ab67 599
Jonathan Austin 1:8aa5cdb4ab67 600 /**
Jonathan Austin 1:8aa5cdb4ab67 601 * Reads the value of the Z axis from the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 602 *
Jonathan Austin 1:8aa5cdb4ab67 603 * @return The force measured in the Z axis, in milli-g.
Jonathan Austin 1:8aa5cdb4ab67 604 *
Jonathan Austin 1:8aa5cdb4ab67 605 * @code
Jonathan Austin 1:8aa5cdb4ab67 606 * accelerometer.getZ();
Jonathan Austin 1:8aa5cdb4ab67 607 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 608 */
Jonathan Austin 1:8aa5cdb4ab67 609 int MicroBitAccelerometer::getZ(MicroBitCoordinateSystem system)
Jonathan Austin 1:8aa5cdb4ab67 610 {
Jonathan Austin 1:8aa5cdb4ab67 611 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 612
Jonathan Austin 1:8aa5cdb4ab67 613 switch (system)
Jonathan Austin 1:8aa5cdb4ab67 614 {
Jonathan Austin 1:8aa5cdb4ab67 615 case NORTH_EAST_DOWN:
Jonathan Austin 1:8aa5cdb4ab67 616 return -sample.z;
Jonathan Austin 1:8aa5cdb4ab67 617
Jonathan Austin 1:8aa5cdb4ab67 618 case SIMPLE_CARTESIAN:
Jonathan Austin 1:8aa5cdb4ab67 619 case RAW:
Jonathan Austin 1:8aa5cdb4ab67 620 default:
Jonathan Austin 1:8aa5cdb4ab67 621 return sample.z;
Jonathan Austin 1:8aa5cdb4ab67 622 }
Jonathan Austin 1:8aa5cdb4ab67 623 }
Jonathan Austin 1:8aa5cdb4ab67 624
Jonathan Austin 1:8aa5cdb4ab67 625 /**
Jonathan Austin 1:8aa5cdb4ab67 626 * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 627 *
Jonathan Austin 1:8aa5cdb4ab67 628 * @return The pitch of the device, in degrees.
Jonathan Austin 1:8aa5cdb4ab67 629 *
Jonathan Austin 1:8aa5cdb4ab67 630 * @code
Jonathan Austin 1:8aa5cdb4ab67 631 * accelerometer.getPitch();
Jonathan Austin 1:8aa5cdb4ab67 632 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 633 */
Jonathan Austin 1:8aa5cdb4ab67 634 int MicroBitAccelerometer::getPitch()
Jonathan Austin 1:8aa5cdb4ab67 635 {
Jonathan Austin 1:8aa5cdb4ab67 636 return (int) ((360*getPitchRadians()) / (2*PI));
Jonathan Austin 1:8aa5cdb4ab67 637 }
Jonathan Austin 1:8aa5cdb4ab67 638
Jonathan Austin 1:8aa5cdb4ab67 639 /**
Jonathan Austin 1:8aa5cdb4ab67 640 * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 641 *
Jonathan Austin 1:8aa5cdb4ab67 642 * @return The pitch of the device, in radians.
Jonathan Austin 1:8aa5cdb4ab67 643 *
Jonathan Austin 1:8aa5cdb4ab67 644 * @code
Jonathan Austin 1:8aa5cdb4ab67 645 * accelerometer.getPitchRadians();
Jonathan Austin 1:8aa5cdb4ab67 646 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 647 */
Jonathan Austin 1:8aa5cdb4ab67 648 float MicroBitAccelerometer::getPitchRadians()
Jonathan Austin 1:8aa5cdb4ab67 649 {
Jonathan Austin 1:8aa5cdb4ab67 650 if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
Jonathan Austin 1:8aa5cdb4ab67 651 recalculatePitchRoll();
Jonathan Austin 1:8aa5cdb4ab67 652
Jonathan Austin 1:8aa5cdb4ab67 653 return pitch;
Jonathan Austin 1:8aa5cdb4ab67 654 }
Jonathan Austin 1:8aa5cdb4ab67 655
Jonathan Austin 1:8aa5cdb4ab67 656 /**
Jonathan Austin 1:8aa5cdb4ab67 657 * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 658 *
Jonathan Austin 1:8aa5cdb4ab67 659 * @return The roll of the device, in degrees.
Jonathan Austin 1:8aa5cdb4ab67 660 *
Jonathan Austin 1:8aa5cdb4ab67 661 * @code
Jonathan Austin 1:8aa5cdb4ab67 662 * accelerometer.getRoll();
Jonathan Austin 1:8aa5cdb4ab67 663 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 664 */
Jonathan Austin 1:8aa5cdb4ab67 665 int MicroBitAccelerometer::getRoll()
Jonathan Austin 1:8aa5cdb4ab67 666 {
Jonathan Austin 1:8aa5cdb4ab67 667 return (int) ((360*getRollRadians()) / (2*PI));
Jonathan Austin 1:8aa5cdb4ab67 668 }
Jonathan Austin 1:8aa5cdb4ab67 669
Jonathan Austin 1:8aa5cdb4ab67 670 /**
Jonathan Austin 1:8aa5cdb4ab67 671 * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 672 *
Jonathan Austin 1:8aa5cdb4ab67 673 * @return The roll of the device, in radians.
Jonathan Austin 1:8aa5cdb4ab67 674 *
Jonathan Austin 1:8aa5cdb4ab67 675 * @code
Jonathan Austin 1:8aa5cdb4ab67 676 * accelerometer.getRollRadians();
Jonathan Austin 1:8aa5cdb4ab67 677 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 678 */
Jonathan Austin 1:8aa5cdb4ab67 679 float MicroBitAccelerometer::getRollRadians()
Jonathan Austin 1:8aa5cdb4ab67 680 {
Jonathan Austin 1:8aa5cdb4ab67 681 if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
Jonathan Austin 1:8aa5cdb4ab67 682 recalculatePitchRoll();
Jonathan Austin 1:8aa5cdb4ab67 683
Jonathan Austin 1:8aa5cdb4ab67 684 return roll;
Jonathan Austin 1:8aa5cdb4ab67 685 }
Jonathan Austin 1:8aa5cdb4ab67 686
Jonathan Austin 1:8aa5cdb4ab67 687 /**
Jonathan Austin 1:8aa5cdb4ab67 688 * Recalculate roll and pitch values for the current sample.
Jonathan Austin 1:8aa5cdb4ab67 689 *
Jonathan Austin 1:8aa5cdb4ab67 690 * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather
Jonathan Austin 1:8aa5cdb4ab67 691 * heavyweight for a CPU without a floating point unit.
Jonathan Austin 1:8aa5cdb4ab67 692 */
Jonathan Austin 1:8aa5cdb4ab67 693 void MicroBitAccelerometer::recalculatePitchRoll()
Jonathan Austin 1:8aa5cdb4ab67 694 {
LancasterUniversity 43:0374ea4d2167 695 double x = (double) getX(NORTH_EAST_DOWN);
LancasterUniversity 43:0374ea4d2167 696 double y = (double) getY(NORTH_EAST_DOWN);
LancasterUniversity 43:0374ea4d2167 697 double z = (double) getZ(NORTH_EAST_DOWN);
Jonathan Austin 1:8aa5cdb4ab67 698
LancasterUniversity 43:0374ea4d2167 699 roll = atan2(y, z);
LancasterUniversity 43:0374ea4d2167 700 pitch = atan(-x / (y*sin(roll) + z*cos(roll)));
LancasterUniversity 6:2e1c2e0d8c7a 701
Jonathan Austin 1:8aa5cdb4ab67 702 status |= MICROBIT_ACCEL_PITCH_ROLL_VALID;
Jonathan Austin 1:8aa5cdb4ab67 703 }
Jonathan Austin 1:8aa5cdb4ab67 704
Jonathan Austin 1:8aa5cdb4ab67 705 /**
Jonathan Austin 1:8aa5cdb4ab67 706 * Retrieves the last recorded gesture.
Jonathan Austin 1:8aa5cdb4ab67 707 *
Jonathan Austin 1:8aa5cdb4ab67 708 * @return The last gesture that was detected.
Jonathan Austin 1:8aa5cdb4ab67 709 *
Jonathan Austin 1:8aa5cdb4ab67 710 * Example:
Jonathan Austin 1:8aa5cdb4ab67 711 * @code
Jonathan Austin 1:8aa5cdb4ab67 712 * MicroBitDisplay display;
Jonathan Austin 1:8aa5cdb4ab67 713 *
Jonathan Austin 1:8aa5cdb4ab67 714 * if (accelerometer.getGesture() == SHAKE)
Jonathan Austin 1:8aa5cdb4ab67 715 * display.scroll("SHAKE!");
Jonathan Austin 1:8aa5cdb4ab67 716 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 717 */
LancasterUniversity 39:112df23f039f 718 uint16_t MicroBitAccelerometer::getGesture()
Jonathan Austin 1:8aa5cdb4ab67 719 {
Jonathan Austin 1:8aa5cdb4ab67 720 return lastGesture;
Jonathan Austin 1:8aa5cdb4ab67 721 }
Jonathan Austin 1:8aa5cdb4ab67 722
Jonathan Austin 1:8aa5cdb4ab67 723 /**
Jonathan Austin 1:8aa5cdb4ab67 724 * A periodic callback invoked by the fiber scheduler idle thread.
Jonathan Austin 1:8aa5cdb4ab67 725 *
Jonathan Austin 1:8aa5cdb4ab67 726 * Internally calls updateSample().
Jonathan Austin 1:8aa5cdb4ab67 727 */
Jonathan Austin 1:8aa5cdb4ab67 728 void MicroBitAccelerometer::idleTick()
Jonathan Austin 1:8aa5cdb4ab67 729 {
Jonathan Austin 1:8aa5cdb4ab67 730 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 731 }
Jonathan Austin 1:8aa5cdb4ab67 732
Jonathan Austin 1:8aa5cdb4ab67 733 /**
Jonathan Austin 1:8aa5cdb4ab67 734 * Destructor for MicroBitAccelerometer, where we deregister from the array of fiber components.
Jonathan Austin 1:8aa5cdb4ab67 735 */
Jonathan Austin 1:8aa5cdb4ab67 736 MicroBitAccelerometer::~MicroBitAccelerometer()
Jonathan Austin 1:8aa5cdb4ab67 737 {
Jonathan Austin 1:8aa5cdb4ab67 738 fiber_remove_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 739 }
Jonathan Austin 1:8aa5cdb4ab67 740
Jonathan Austin 1:8aa5cdb4ab67 741 const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = {
Jonathan Austin 1:8aa5cdb4ab67 742 {2, 0},
Jonathan Austin 1:8aa5cdb4ab67 743 {4, 1},
Jonathan Austin 1:8aa5cdb4ab67 744 {8, 2}
Jonathan Austin 1:8aa5cdb4ab67 745 };
Jonathan Austin 1:8aa5cdb4ab67 746
Jonathan Austin 1:8aa5cdb4ab67 747 const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = {
Jonathan Austin 1:8aa5cdb4ab67 748 {1250, 0x00},
Jonathan Austin 1:8aa5cdb4ab67 749 {2500, 0x08},
Jonathan Austin 1:8aa5cdb4ab67 750 {5000, 0x10},
Jonathan Austin 1:8aa5cdb4ab67 751 {10000, 0x18},
Jonathan Austin 1:8aa5cdb4ab67 752 {20000, 0x20},
Jonathan Austin 1:8aa5cdb4ab67 753 {80000, 0x28},
Jonathan Austin 1:8aa5cdb4ab67 754 {160000, 0x30},
Jonathan Austin 1:8aa5cdb4ab67 755 {640000, 0x38}
LancasterUniversity 6:2e1c2e0d8c7a 756 };