Solution for Bluetooth SIG hands-on training course
Dependencies: BLE_API mbed-dev-bin nRF51822-bluetooth-mdw
Fork of microbit-dal-bluetooth-mdw_starter by
source/drivers/MicroBitAccelerometer.cpp@22:23d7b9a4b082, 2016-07-13 (annotated)
- Committer:
- LancasterUniversity
- Date:
- Wed Jul 13 12:17:54 2016 +0100
- Revision:
- 22:23d7b9a4b082
- Parent:
- 6:2e1c2e0d8c7a
- Child:
- 37:b624ae5e94a5
Synchronized with git rev 7cf98c22
Author: James Devine
microbit-dal: patch for fiber_wake_on_event
fiber_wake_on_event used to crash after forking a FOB fiber.
It would attempt to obtain a new fiber context, and would place it on the wait queue.
Then when that fiber was paged in, the context of that fiber would not have been
initialised, as the function presumed schedule would be called immediately after
fiber initialisation.
This patch catches that edge case.
Who changed what in which revision?
User | Revision | Line number | New 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 *)®, 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; |
Jonathan Austin |
1:8aa5cdb4ab67 | 192 | this->lastGesture = GESTURE_NONE; |
Jonathan Austin |
1:8aa5cdb4ab67 | 193 | this->currentGesture = GESTURE_NONE; |
Jonathan Austin |
1:8aa5cdb4ab67 | 194 | this->shake.x = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 195 | this->shake.y = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 196 | this->shake.z = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 197 | this->shake.count = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 198 | this->shake.timer = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 199 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 200 | // Configure and enable the accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 201 | if (this->configure() == MICROBIT_OK) |
Jonathan Austin |
1:8aa5cdb4ab67 | 202 | status |= MICROBIT_COMPONENT_RUNNING; |
Jonathan Austin |
1:8aa5cdb4ab67 | 203 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 204 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 205 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 206 | * Attempts to read the 8 bit ID from the accelerometer, this can be used for |
Jonathan Austin |
1:8aa5cdb4ab67 | 207 | * validation purposes. |
Jonathan Austin |
1:8aa5cdb4ab67 | 208 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 209 | * @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails. |
Jonathan Austin |
1:8aa5cdb4ab67 | 210 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 211 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 212 | * accelerometer.whoAmI(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 213 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 214 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 215 | int MicroBitAccelerometer::whoAmI() |
Jonathan Austin |
1:8aa5cdb4ab67 | 216 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 217 | uint8_t data; |
Jonathan Austin |
1:8aa5cdb4ab67 | 218 | int result; |
Jonathan Austin |
1:8aa5cdb4ab67 | 219 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 220 | result = readCommand(MMA8653_WHOAMI, &data, 1); |
Jonathan Austin |
1:8aa5cdb4ab67 | 221 | if (result !=0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 222 | return MICROBIT_I2C_ERROR; |
Jonathan Austin |
1:8aa5cdb4ab67 | 223 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 224 | return (int)data; |
Jonathan Austin |
1:8aa5cdb4ab67 | 225 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 226 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 227 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 228 | * Reads the acceleration data from the accelerometer, and stores it in our buffer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 229 | * This only happens if the accelerometer indicates that it has new data via int1. |
Jonathan Austin |
1:8aa5cdb4ab67 | 230 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 231 | * On first use, this member function will attempt to add this component to the |
Jonathan Austin |
1:8aa5cdb4ab67 | 232 | * list of fiber components in order to constantly update the values stored |
Jonathan Austin |
1:8aa5cdb4ab67 | 233 | * by this object. |
Jonathan Austin |
1:8aa5cdb4ab67 | 234 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 235 | * This technique is called lazy instantiation, and it means that we do not |
Jonathan Austin |
1:8aa5cdb4ab67 | 236 | * obtain the overhead from non-chalantly adding this component to fiber components. |
Jonathan Austin |
1:8aa5cdb4ab67 | 237 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 238 | * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the read request fails. |
Jonathan Austin |
1:8aa5cdb4ab67 | 239 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 240 | int MicroBitAccelerometer::updateSample() |
Jonathan Austin |
1:8aa5cdb4ab67 | 241 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 242 | if(!(status & MICROBIT_ACCEL_ADDED_TO_IDLE)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 243 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 244 | fiber_add_idle_component(this); |
Jonathan Austin |
1:8aa5cdb4ab67 | 245 | status |= MICROBIT_ACCEL_ADDED_TO_IDLE; |
Jonathan Austin |
1:8aa5cdb4ab67 | 246 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 247 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 248 | // Poll interrupt line from accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 249 | // n.b. Default is Active LO. Interrupt is cleared in data read. |
Jonathan Austin |
1:8aa5cdb4ab67 | 250 | if(!int1) |
Jonathan Austin |
1:8aa5cdb4ab67 | 251 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 252 | int8_t data[6]; |
Jonathan Austin |
1:8aa5cdb4ab67 | 253 | int result; |
Jonathan Austin |
1:8aa5cdb4ab67 | 254 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 255 | result = readCommand(MMA8653_OUT_X_MSB, (uint8_t *)data, 6); |
Jonathan Austin |
1:8aa5cdb4ab67 | 256 | if (result !=0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 257 | return MICROBIT_I2C_ERROR; |
Jonathan Austin |
1:8aa5cdb4ab67 | 258 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 259 | // read MSB values... |
Jonathan Austin |
1:8aa5cdb4ab67 | 260 | sample.x = data[0]; |
Jonathan Austin |
1:8aa5cdb4ab67 | 261 | sample.y = data[2]; |
Jonathan Austin |
1:8aa5cdb4ab67 | 262 | sample.z = data[4]; |
Jonathan Austin |
1:8aa5cdb4ab67 | 263 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 264 | // Normalize the data in the 0..1024 range. |
Jonathan Austin |
1:8aa5cdb4ab67 | 265 | sample.x *= 8; |
Jonathan Austin |
1:8aa5cdb4ab67 | 266 | sample.y *= 8; |
Jonathan Austin |
1:8aa5cdb4ab67 | 267 | sample.z *= 8; |
Jonathan Austin |
1:8aa5cdb4ab67 | 268 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 269 | #if CONFIG_ENABLED(USE_ACCEL_LSB) |
Jonathan Austin |
1:8aa5cdb4ab67 | 270 | // Add in LSB values. |
Jonathan Austin |
1:8aa5cdb4ab67 | 271 | sample.x += (data[1] / 64); |
Jonathan Austin |
1:8aa5cdb4ab67 | 272 | sample.y += (data[3] / 64); |
Jonathan Austin |
1:8aa5cdb4ab67 | 273 | sample.z += (data[5] / 64); |
Jonathan Austin |
1:8aa5cdb4ab67 | 274 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 275 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 276 | // Scale into millig (approx!) |
Jonathan Austin |
1:8aa5cdb4ab67 | 277 | sample.x *= this->sampleRange; |
Jonathan Austin |
1:8aa5cdb4ab67 | 278 | sample.y *= this->sampleRange; |
Jonathan Austin |
1:8aa5cdb4ab67 | 279 | sample.z *= this->sampleRange; |
Jonathan Austin |
1:8aa5cdb4ab67 | 280 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 281 | // Indicate that pitch and roll data is now stale, and needs to be recalculated if needed. |
Jonathan Austin |
1:8aa5cdb4ab67 | 282 | status &= ~MICROBIT_ACCEL_PITCH_ROLL_VALID; |
Jonathan Austin |
1:8aa5cdb4ab67 | 283 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 284 | // Update gesture tracking |
Jonathan Austin |
1:8aa5cdb4ab67 | 285 | updateGesture(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 286 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 287 | // Indicate that a new sample is available |
Jonathan Austin |
1:8aa5cdb4ab67 | 288 | MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE); |
Jonathan Austin |
1:8aa5cdb4ab67 | 289 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 290 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 291 | return MICROBIT_OK; |
Jonathan Austin |
1:8aa5cdb4ab67 | 292 | }; |
Jonathan Austin |
1:8aa5cdb4ab67 | 293 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 294 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 295 | * A service function. |
Jonathan Austin |
1:8aa5cdb4ab67 | 296 | * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2). |
Jonathan Austin |
1:8aa5cdb4ab67 | 297 | * It does not, however, square root the result, as this is a relatively high cost operation. |
Jonathan Austin |
1:8aa5cdb4ab67 | 298 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 299 | * This is left to application code should it be needed. |
Jonathan Austin |
1:8aa5cdb4ab67 | 300 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 301 | * @return the sum of the square of the acceleration of the device across all axes. |
Jonathan Austin |
1:8aa5cdb4ab67 | 302 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 303 | int MicroBitAccelerometer::instantaneousAccelerationSquared() |
Jonathan Austin |
1:8aa5cdb4ab67 | 304 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 305 | updateSample(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 306 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 307 | // Use pythagoras theorem to determine the combined force acting on the device. |
Jonathan Austin |
1:8aa5cdb4ab67 | 308 | return (int)sample.x*(int)sample.x + (int)sample.y*(int)sample.y + (int)sample.z*(int)sample.z; |
Jonathan Austin |
1:8aa5cdb4ab67 | 309 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 310 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 311 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 312 | * Service function. |
Jonathan Austin |
1:8aa5cdb4ab67 | 313 | * Determines a 'best guess' posture of the device based on instantaneous data. |
Jonathan Austin |
1:8aa5cdb4ab67 | 314 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 315 | * This makes no use of historic data, and forms this input to the filter implemented in updateGesture(). |
Jonathan Austin |
1:8aa5cdb4ab67 | 316 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 317 | * @return A 'best guess' of the current posture of the device, based on instanataneous data. |
Jonathan Austin |
1:8aa5cdb4ab67 | 318 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 319 | BasicGesture MicroBitAccelerometer::instantaneousPosture() |
Jonathan Austin |
1:8aa5cdb4ab67 | 320 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 321 | int force = instantaneousAccelerationSquared(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 322 | bool shakeDetected = false; |
Jonathan Austin |
1:8aa5cdb4ab67 | 323 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 324 | // Test for shake events. |
Jonathan Austin |
1:8aa5cdb4ab67 | 325 | // 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 |
Jonathan Austin |
1:8aa5cdb4ab67 | 326 | // a string acceleration to the right, then we can infer a shake. Similarly, we can do this for each acxis (left/right, up/down, in/out). |
Jonathan Austin |
1:8aa5cdb4ab67 | 327 | // |
Jonathan Austin |
1:8aa5cdb4ab67 | 328 | // If we see enough zero crossings in succession (MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the device |
Jonathan Austin |
1:8aa5cdb4ab67 | 329 | // has been shaken. |
Jonathan Austin |
1:8aa5cdb4ab67 | 330 | if ((getX() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || (getX() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.x)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 331 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 332 | shakeDetected = true; |
Jonathan Austin |
1:8aa5cdb4ab67 | 333 | shake.x = !shake.x; |
Jonathan Austin |
1:8aa5cdb4ab67 | 334 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 335 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 336 | if ((getY() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.y) || (getY() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.y)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 337 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 338 | shakeDetected = true; |
Jonathan Austin |
1:8aa5cdb4ab67 | 339 | shake.y = !shake.y; |
Jonathan Austin |
1:8aa5cdb4ab67 | 340 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 341 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 342 | if ((getZ() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.z) || (getZ() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.z)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 343 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 344 | shakeDetected = true; |
Jonathan Austin |
1:8aa5cdb4ab67 | 345 | shake.z = !shake.z; |
Jonathan Austin |
1:8aa5cdb4ab67 | 346 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 347 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 348 | if (shakeDetected && shake.count < MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD && ++shake.count == MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD) |
Jonathan Austin |
1:8aa5cdb4ab67 | 349 | shake.shaken = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 350 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 351 | if (++shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_DAMPING) |
Jonathan Austin |
1:8aa5cdb4ab67 | 352 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 353 | shake.timer = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 354 | if (shake.count > 0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 355 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 356 | if(--shake.count == 0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 357 | shake.shaken = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 358 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 359 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 360 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 361 | if (shake.shaken) |
Jonathan Austin |
1:8aa5cdb4ab67 | 362 | return GESTURE_SHAKE; |
Jonathan Austin |
1:8aa5cdb4ab67 | 363 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 364 | if (force < MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD) |
Jonathan Austin |
1:8aa5cdb4ab67 | 365 | return GESTURE_FREEFALL; |
Jonathan Austin |
1:8aa5cdb4ab67 | 366 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 367 | if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD) |
Jonathan Austin |
1:8aa5cdb4ab67 | 368 | return GESTURE_3G; |
Jonathan Austin |
1:8aa5cdb4ab67 | 369 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 370 | if (force > MICROBIT_ACCELEROMETER_6G_THRESHOLD) |
Jonathan Austin |
1:8aa5cdb4ab67 | 371 | return GESTURE_6G; |
Jonathan Austin |
1:8aa5cdb4ab67 | 372 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 373 | if (force > MICROBIT_ACCELEROMETER_8G_THRESHOLD) |
Jonathan Austin |
1:8aa5cdb4ab67 | 374 | return GESTURE_8G; |
Jonathan Austin |
1:8aa5cdb4ab67 | 375 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 376 | // Determine our posture. |
Jonathan Austin |
1:8aa5cdb4ab67 | 377 | if (getX() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 378 | return GESTURE_LEFT; |
Jonathan Austin |
1:8aa5cdb4ab67 | 379 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 380 | if (getX() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 381 | return GESTURE_RIGHT; |
Jonathan Austin |
1:8aa5cdb4ab67 | 382 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 383 | if (getY() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 384 | return GESTURE_DOWN; |
Jonathan Austin |
1:8aa5cdb4ab67 | 385 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 386 | if (getY() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 387 | return GESTURE_UP; |
Jonathan Austin |
1:8aa5cdb4ab67 | 388 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 389 | if (getZ() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 390 | return GESTURE_FACE_UP; |
Jonathan Austin |
1:8aa5cdb4ab67 | 391 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 392 | if (getZ() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 393 | return GESTURE_FACE_DOWN; |
Jonathan Austin |
1:8aa5cdb4ab67 | 394 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 395 | return GESTURE_NONE; |
Jonathan Austin |
1:8aa5cdb4ab67 | 396 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 397 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 398 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 399 | * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote |
Jonathan Austin |
1:8aa5cdb4ab67 | 400 | * stability. |
Jonathan Austin |
1:8aa5cdb4ab67 | 401 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 402 | void MicroBitAccelerometer::updateGesture() |
Jonathan Austin |
1:8aa5cdb4ab67 | 403 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 404 | // Determine what it looks like we're doing based on the latest sample... |
Jonathan Austin |
1:8aa5cdb4ab67 | 405 | BasicGesture g = instantaneousPosture(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 406 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 407 | // Perform some low pass filtering to reduce jitter from any detected effects |
Jonathan Austin |
1:8aa5cdb4ab67 | 408 | if (g == currentGesture) |
Jonathan Austin |
1:8aa5cdb4ab67 | 409 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 410 | if (sigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING) |
Jonathan Austin |
1:8aa5cdb4ab67 | 411 | sigma++; |
Jonathan Austin |
1:8aa5cdb4ab67 | 412 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 413 | else |
Jonathan Austin |
1:8aa5cdb4ab67 | 414 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 415 | currentGesture = g; |
Jonathan Austin |
1:8aa5cdb4ab67 | 416 | sigma = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 417 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 418 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 419 | // If we've reached threshold, update our record and raise the relevant event... |
Jonathan Austin |
1:8aa5cdb4ab67 | 420 | if (currentGesture != lastGesture && sigma >= MICROBIT_ACCELEROMETER_GESTURE_DAMPING) |
Jonathan Austin |
1:8aa5cdb4ab67 | 421 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 422 | lastGesture = currentGesture; |
Jonathan Austin |
1:8aa5cdb4ab67 | 423 | MicroBitEvent e(MICROBIT_ID_GESTURE, lastGesture); |
Jonathan Austin |
1:8aa5cdb4ab67 | 424 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 425 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 426 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 427 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 428 | * Attempts to set the sample rate of the accelerometer to the specified value (in ms). |
Jonathan Austin |
1:8aa5cdb4ab67 | 429 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 430 | * @param period the requested time between samples, in milliseconds. |
Jonathan Austin |
1:8aa5cdb4ab67 | 431 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 432 | * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails. |
Jonathan Austin |
1:8aa5cdb4ab67 | 433 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 434 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 435 | * // sample rate is now 20 ms. |
Jonathan Austin |
1:8aa5cdb4ab67 | 436 | * accelerometer.setPeriod(20); |
Jonathan Austin |
1:8aa5cdb4ab67 | 437 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 438 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 439 | * @note The requested rate may not be possible on the hardware. In this case, the |
Jonathan Austin |
1:8aa5cdb4ab67 | 440 | * nearest lower rate is chosen. |
Jonathan Austin |
1:8aa5cdb4ab67 | 441 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 442 | int MicroBitAccelerometer::setPeriod(int period) |
Jonathan Austin |
1:8aa5cdb4ab67 | 443 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 444 | this->samplePeriod = period; |
Jonathan Austin |
1:8aa5cdb4ab67 | 445 | return this->configure(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 446 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 447 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 448 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 449 | * Reads the currently configured sample rate of the accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 450 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 451 | * @return The time between samples, in milliseconds. |
Jonathan Austin |
1:8aa5cdb4ab67 | 452 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 453 | int MicroBitAccelerometer::getPeriod() |
Jonathan Austin |
1:8aa5cdb4ab67 | 454 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 455 | return (int)samplePeriod; |
Jonathan Austin |
1:8aa5cdb4ab67 | 456 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 457 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 458 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 459 | * Attempts to set the sample range of the accelerometer to the specified value (in g). |
Jonathan Austin |
1:8aa5cdb4ab67 | 460 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 461 | * @param range The requested sample range of samples, in g. |
Jonathan Austin |
1:8aa5cdb4ab67 | 462 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 463 | * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails. |
Jonathan Austin |
1:8aa5cdb4ab67 | 464 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 465 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 466 | * // the sample range of the accelerometer is now 8G. |
Jonathan Austin |
1:8aa5cdb4ab67 | 467 | * accelerometer.setRange(8); |
Jonathan Austin |
1:8aa5cdb4ab67 | 468 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 469 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 470 | * @note The requested range may not be possible on the hardware. In this case, the |
Jonathan Austin |
1:8aa5cdb4ab67 | 471 | * nearest lower range is chosen. |
Jonathan Austin |
1:8aa5cdb4ab67 | 472 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 473 | int MicroBitAccelerometer::setRange(int range) |
Jonathan Austin |
1:8aa5cdb4ab67 | 474 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 475 | this->sampleRange = range; |
Jonathan Austin |
1:8aa5cdb4ab67 | 476 | return this->configure(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 477 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 478 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 479 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 480 | * Reads the currently configured sample range of the accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 481 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 482 | * @return The sample range, in g. |
Jonathan Austin |
1:8aa5cdb4ab67 | 483 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 484 | int MicroBitAccelerometer::getRange() |
Jonathan Austin |
1:8aa5cdb4ab67 | 485 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 486 | return (int)sampleRange; |
Jonathan Austin |
1:8aa5cdb4ab67 | 487 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 488 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 489 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 490 | * Reads the value of the X axis from the latest update retrieved from the accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 491 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 492 | * @param system The coordinate system to use. By default, a simple cartesian system is provided. |
Jonathan Austin |
1:8aa5cdb4ab67 | 493 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 494 | * @return The force measured in the X axis, in milli-g. |
Jonathan Austin |
1:8aa5cdb4ab67 | 495 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 496 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 497 | * accelerometer.getX(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 498 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 499 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 500 | int MicroBitAccelerometer::getX(MicroBitCoordinateSystem system) |
Jonathan Austin |
1:8aa5cdb4ab67 | 501 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 502 | updateSample(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 503 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 504 | switch (system) |
Jonathan Austin |
1:8aa5cdb4ab67 | 505 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 506 | case SIMPLE_CARTESIAN: |
Jonathan Austin |
1:8aa5cdb4ab67 | 507 | return -sample.x; |
Jonathan Austin |
1:8aa5cdb4ab67 | 508 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 509 | case NORTH_EAST_DOWN: |
Jonathan Austin |
1:8aa5cdb4ab67 | 510 | return sample.y; |
Jonathan Austin |
1:8aa5cdb4ab67 | 511 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 512 | case RAW: |
Jonathan Austin |
1:8aa5cdb4ab67 | 513 | default: |
Jonathan Austin |
1:8aa5cdb4ab67 | 514 | return sample.x; |
Jonathan Austin |
1:8aa5cdb4ab67 | 515 | } |
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 Y axis from the latest update retrieved from the accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 520 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 521 | * @return The force measured in the Y axis, in milli-g. |
Jonathan Austin |
1:8aa5cdb4ab67 | 522 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 523 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 524 | * accelerometer.getY(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 525 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 526 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 527 | int MicroBitAccelerometer::getY(MicroBitCoordinateSystem system) |
Jonathan Austin |
1:8aa5cdb4ab67 | 528 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 529 | updateSample(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 530 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 531 | switch (system) |
Jonathan Austin |
1:8aa5cdb4ab67 | 532 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 533 | case SIMPLE_CARTESIAN: |
Jonathan Austin |
1:8aa5cdb4ab67 | 534 | return -sample.y; |
Jonathan Austin |
1:8aa5cdb4ab67 | 535 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 536 | case NORTH_EAST_DOWN: |
Jonathan Austin |
1:8aa5cdb4ab67 | 537 | return -sample.x; |
Jonathan Austin |
1:8aa5cdb4ab67 | 538 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 539 | case RAW: |
Jonathan Austin |
1:8aa5cdb4ab67 | 540 | default: |
Jonathan Austin |
1:8aa5cdb4ab67 | 541 | return sample.y; |
Jonathan Austin |
1:8aa5cdb4ab67 | 542 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 543 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 544 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 545 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 546 | * Reads the value of the Z axis from the latest update retrieved from the accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 547 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 548 | * @return The force measured in the Z axis, in milli-g. |
Jonathan Austin |
1:8aa5cdb4ab67 | 549 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 550 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 551 | * accelerometer.getZ(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 552 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 553 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 554 | int MicroBitAccelerometer::getZ(MicroBitCoordinateSystem system) |
Jonathan Austin |
1:8aa5cdb4ab67 | 555 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 556 | updateSample(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 557 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 558 | switch (system) |
Jonathan Austin |
1:8aa5cdb4ab67 | 559 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 560 | case NORTH_EAST_DOWN: |
Jonathan Austin |
1:8aa5cdb4ab67 | 561 | return -sample.z; |
Jonathan Austin |
1:8aa5cdb4ab67 | 562 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 563 | case SIMPLE_CARTESIAN: |
Jonathan Austin |
1:8aa5cdb4ab67 | 564 | case RAW: |
Jonathan Austin |
1:8aa5cdb4ab67 | 565 | default: |
Jonathan Austin |
1:8aa5cdb4ab67 | 566 | return sample.z; |
Jonathan Austin |
1:8aa5cdb4ab67 | 567 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 568 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 569 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 570 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 571 | * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 572 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 573 | * @return The pitch of the device, in degrees. |
Jonathan Austin |
1:8aa5cdb4ab67 | 574 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 575 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 576 | * accelerometer.getPitch(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 577 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 578 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 579 | int MicroBitAccelerometer::getPitch() |
Jonathan Austin |
1:8aa5cdb4ab67 | 580 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 581 | return (int) ((360*getPitchRadians()) / (2*PI)); |
Jonathan Austin |
1:8aa5cdb4ab67 | 582 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 583 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 584 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 585 | * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 586 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 587 | * @return The pitch of the device, in radians. |
Jonathan Austin |
1:8aa5cdb4ab67 | 588 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 589 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 590 | * accelerometer.getPitchRadians(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 591 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 592 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 593 | float MicroBitAccelerometer::getPitchRadians() |
Jonathan Austin |
1:8aa5cdb4ab67 | 594 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 595 | if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 596 | recalculatePitchRoll(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 597 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 598 | return pitch; |
Jonathan Austin |
1:8aa5cdb4ab67 | 599 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 600 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 601 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 602 | * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 603 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 604 | * @return The roll of the device, in degrees. |
Jonathan Austin |
1:8aa5cdb4ab67 | 605 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 606 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 607 | * accelerometer.getRoll(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 608 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 609 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 610 | int MicroBitAccelerometer::getRoll() |
Jonathan Austin |
1:8aa5cdb4ab67 | 611 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 612 | return (int) ((360*getRollRadians()) / (2*PI)); |
Jonathan Austin |
1:8aa5cdb4ab67 | 613 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 614 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 615 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 616 | * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 617 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 618 | * @return The roll of the device, in radians. |
Jonathan Austin |
1:8aa5cdb4ab67 | 619 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 620 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 621 | * accelerometer.getRollRadians(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 622 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 623 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 624 | float MicroBitAccelerometer::getRollRadians() |
Jonathan Austin |
1:8aa5cdb4ab67 | 625 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 626 | if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 627 | recalculatePitchRoll(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 628 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 629 | return roll; |
Jonathan Austin |
1:8aa5cdb4ab67 | 630 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 631 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 632 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 633 | * Recalculate roll and pitch values for the current sample. |
Jonathan Austin |
1:8aa5cdb4ab67 | 634 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 635 | * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather |
Jonathan Austin |
1:8aa5cdb4ab67 | 636 | * heavyweight for a CPU without a floating point unit. |
Jonathan Austin |
1:8aa5cdb4ab67 | 637 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 638 | void MicroBitAccelerometer::recalculatePitchRoll() |
Jonathan Austin |
1:8aa5cdb4ab67 | 639 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 640 | float x = (float) getX(NORTH_EAST_DOWN); |
Jonathan Austin |
1:8aa5cdb4ab67 | 641 | float y = (float) getY(NORTH_EAST_DOWN); |
Jonathan Austin |
1:8aa5cdb4ab67 | 642 | float z = (float) getZ(NORTH_EAST_DOWN); |
Jonathan Austin |
1:8aa5cdb4ab67 | 643 | |
LancasterUniversity | 6:2e1c2e0d8c7a | 644 | roll = atan2((double)getY(NORTH_EAST_DOWN), (double)getZ(NORTH_EAST_DOWN)); |
LancasterUniversity | 6:2e1c2e0d8c7a | 645 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 646 | pitch = atan(-x / (y*sin(roll) + z*cos(roll))); |
Jonathan Austin |
1:8aa5cdb4ab67 | 647 | status |= MICROBIT_ACCEL_PITCH_ROLL_VALID; |
Jonathan Austin |
1:8aa5cdb4ab67 | 648 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 649 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 650 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 651 | * Retrieves the last recorded gesture. |
Jonathan Austin |
1:8aa5cdb4ab67 | 652 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 653 | * @return The last gesture that was detected. |
Jonathan Austin |
1:8aa5cdb4ab67 | 654 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 655 | * Example: |
Jonathan Austin |
1:8aa5cdb4ab67 | 656 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 657 | * MicroBitDisplay display; |
Jonathan Austin |
1:8aa5cdb4ab67 | 658 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 659 | * if (accelerometer.getGesture() == SHAKE) |
Jonathan Austin |
1:8aa5cdb4ab67 | 660 | * display.scroll("SHAKE!"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 661 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 662 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 663 | BasicGesture MicroBitAccelerometer::getGesture() |
Jonathan Austin |
1:8aa5cdb4ab67 | 664 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 665 | return lastGesture; |
Jonathan Austin |
1:8aa5cdb4ab67 | 666 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 667 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 668 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 669 | * A periodic callback invoked by the fiber scheduler idle thread. |
Jonathan Austin |
1:8aa5cdb4ab67 | 670 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 671 | * Internally calls updateSample(). |
Jonathan Austin |
1:8aa5cdb4ab67 | 672 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 673 | void MicroBitAccelerometer::idleTick() |
Jonathan Austin |
1:8aa5cdb4ab67 | 674 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 675 | updateSample(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 676 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 677 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 678 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 679 | * Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read. |
Jonathan Austin |
1:8aa5cdb4ab67 | 680 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 681 | * We check if any data is ready for reading by checking the interrupt flag on the accelerometer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 682 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 683 | int MicroBitAccelerometer::isIdleCallbackNeeded() |
Jonathan Austin |
1:8aa5cdb4ab67 | 684 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 685 | return !int1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 686 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 687 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 688 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 689 | * Destructor for MicroBitAccelerometer, where we deregister from the array of fiber components. |
Jonathan Austin |
1:8aa5cdb4ab67 | 690 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 691 | MicroBitAccelerometer::~MicroBitAccelerometer() |
Jonathan Austin |
1:8aa5cdb4ab67 | 692 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 693 | fiber_remove_idle_component(this); |
Jonathan Austin |
1:8aa5cdb4ab67 | 694 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 695 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 696 | const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = { |
Jonathan Austin |
1:8aa5cdb4ab67 | 697 | {2, 0}, |
Jonathan Austin |
1:8aa5cdb4ab67 | 698 | {4, 1}, |
Jonathan Austin |
1:8aa5cdb4ab67 | 699 | {8, 2} |
Jonathan Austin |
1:8aa5cdb4ab67 | 700 | }; |
Jonathan Austin |
1:8aa5cdb4ab67 | 701 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 702 | const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = { |
Jonathan Austin |
1:8aa5cdb4ab67 | 703 | {1250, 0x00}, |
Jonathan Austin |
1:8aa5cdb4ab67 | 704 | {2500, 0x08}, |
Jonathan Austin |
1:8aa5cdb4ab67 | 705 | {5000, 0x10}, |
Jonathan Austin |
1:8aa5cdb4ab67 | 706 | {10000, 0x18}, |
Jonathan Austin |
1:8aa5cdb4ab67 | 707 | {20000, 0x20}, |
Jonathan Austin |
1:8aa5cdb4ab67 | 708 | {80000, 0x28}, |
Jonathan Austin |
1:8aa5cdb4ab67 | 709 | {160000, 0x30}, |
Jonathan Austin |
1:8aa5cdb4ab67 | 710 | {640000, 0x38} |
LancasterUniversity | 6:2e1c2e0d8c7a | 711 | }; |