Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BLE_API mbed-dev-bin nRF51822
Fork of microbit-dal by
Diff: inc/drivers/MicroBitAccelerometer.h
- Revision:
- 1:8aa5cdb4ab67
- Child:
- 38:1a9e8e5e23f2
diff -r fb15f7887843 -r 8aa5cdb4ab67 inc/drivers/MicroBitAccelerometer.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitAccelerometer.h Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,467 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2016 British Broadcasting Corporation.
+This software is provided by Lancaster University by arrangement with the BBC.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MICROBIT_ACCELEROMETER_H
+#define MICROBIT_ACCELEROMETER_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+#include "MicroBitCoordinateSystem.h"
+#include "MicroBitI2C.h"
+
+/**
+ * Relevant pin assignments
+ */
+#define MICROBIT_PIN_ACCEL_DATA_READY P0_28
+
+/**
+ * Status flags
+ */
+#define MICROBIT_ACCEL_PITCH_ROLL_VALID 0x02
+#define MICROBIT_ACCEL_ADDED_TO_IDLE 0x04
+
+/**
+ * I2C constants
+ */
+#define MMA8653_DEFAULT_ADDR 0x3A
+
+/**
+ * MMA8653 Register map (partial)
+ */
+#define MMA8653_STATUS 0x00
+#define MMA8653_OUT_X_MSB 0x01
+#define MMA8653_WHOAMI 0x0D
+#define MMA8653_XYZ_DATA_CFG 0x0E
+#define MMA8653_CTRL_REG1 0x2A
+#define MMA8653_CTRL_REG2 0x2B
+#define MMA8653_CTRL_REG3 0x2C
+#define MMA8653_CTRL_REG4 0x2D
+#define MMA8653_CTRL_REG5 0x2E
+
+
+/**
+ * MMA8653 constants
+ */
+#define MMA8653_WHOAMI_VAL 0x5A
+
+#define MMA8653_SAMPLE_RANGES 3
+#define MMA8653_SAMPLE_RATES 8
+
+/**
+ * Accelerometer events
+ */
+#define MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE 1
+
+/**
+ * Gesture events
+ */
+#define MICROBIT_ACCELEROMETER_EVT_TILT_UP 1
+#define MICROBIT_ACCELEROMETER_EVT_TILT_DOWN 2
+#define MICROBIT_ACCELEROMETER_EVT_TILT_LEFT 3
+#define MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT 4
+#define MICROBIT_ACCELEROMETER_EVT_FACE_UP 5
+#define MICROBIT_ACCELEROMETER_EVT_FACE_DOWN 6
+#define MICROBIT_ACCELEROMETER_EVT_FREEFALL 7
+#define MICROBIT_ACCELEROMETER_EVT_3G 8
+#define MICROBIT_ACCELEROMETER_EVT_6G 9
+#define MICROBIT_ACCELEROMETER_EVT_8G 10
+#define MICROBIT_ACCELEROMETER_EVT_SHAKE 11
+
+/**
+ * Gesture recogniser constants
+ */
+#define MICROBIT_ACCELEROMETER_REST_TOLERANCE 200
+#define MICROBIT_ACCELEROMETER_TILT_TOLERANCE 200
+#define MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE 400
+#define MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE 1000
+#define MICROBIT_ACCELEROMETER_3G_TOLERANCE 3072
+#define MICROBIT_ACCELEROMETER_6G_TOLERANCE 6144
+#define MICROBIT_ACCELEROMETER_8G_TOLERANCE 8192
+#define MICROBIT_ACCELEROMETER_GESTURE_DAMPING 10
+#define MICROBIT_ACCELEROMETER_SHAKE_DAMPING 10
+
+#define MICROBIT_ACCELEROMETER_REST_THRESHOLD (MICROBIT_ACCELEROMETER_REST_TOLERANCE * MICROBIT_ACCELEROMETER_REST_TOLERANCE)
+#define MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD (MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE * MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE)
+#define MICROBIT_ACCELEROMETER_3G_THRESHOLD (MICROBIT_ACCELEROMETER_3G_TOLERANCE * MICROBIT_ACCELEROMETER_3G_TOLERANCE)
+#define MICROBIT_ACCELEROMETER_6G_THRESHOLD (MICROBIT_ACCELEROMETER_6G_TOLERANCE * MICROBIT_ACCELEROMETER_6G_TOLERANCE)
+#define MICROBIT_ACCELEROMETER_8G_THRESHOLD (MICROBIT_ACCELEROMETER_8G_TOLERANCE * MICROBIT_ACCELEROMETER_8G_TOLERANCE)
+#define MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD 4
+
+struct MMA8653Sample
+{
+ int16_t x;
+ int16_t y;
+ int16_t z;
+};
+
+struct MMA8653SampleRateConfig
+{
+ uint32_t sample_period;
+ uint8_t ctrl_reg1;
+};
+
+struct MMA8653SampleRangeConfig
+{
+ uint8_t sample_range;
+ uint8_t xyz_data_cfg;
+};
+
+
+extern const MMA8653SampleRangeConfig MMA8653SampleRange[];
+extern const MMA8653SampleRateConfig MMA8653SampleRate[];
+
+enum BasicGesture
+{
+ GESTURE_NONE,
+ GESTURE_UP,
+ GESTURE_DOWN,
+ GESTURE_LEFT,
+ GESTURE_RIGHT,
+ GESTURE_FACE_UP,
+ GESTURE_FACE_DOWN,
+ GESTURE_FREEFALL,
+ GESTURE_3G,
+ GESTURE_6G,
+ GESTURE_8G,
+ GESTURE_SHAKE
+};
+
+struct ShakeHistory
+{
+ uint16_t shaken:1,
+ x:1,
+ y:1,
+ z:1,
+ count:4,
+ timer:8;
+};
+
+/**
+ * Class definition for MicroBit Accelerometer.
+ *
+ * Represents an implementation of the Freescale MMA8653 3 axis accelerometer
+ * Also includes basic data caching and on demand activation.
+ */
+class MicroBitAccelerometer : public MicroBitComponent
+{
+ uint16_t address; // I2C address of this accelerometer.
+ uint16_t samplePeriod; // The time between samples, in milliseconds.
+ uint8_t sampleRange; // The sample range of the accelerometer in g.
+ MMA8653Sample sample; // The last sample read.
+ DigitalIn int1; // Data ready interrupt.
+ float pitch; // Pitch of the device, in radians.
+ MicroBitI2C& i2c; // The I2C interface to use.
+ float roll; // Roll of the device, in radians.
+ uint8_t sigma; // the number of ticks that the instantaneous gesture has been stable.
+ BasicGesture lastGesture; // the last, stable gesture recorded.
+ BasicGesture currentGesture; // the instantaneous, unfiltered gesture detected.
+ ShakeHistory shake; // State information needed to detect shake events.
+
+ public:
+
+ /**
+ * Constructor.
+ * Create a software abstraction of an accelerometer.
+ *
+ * @param _i2c an instance of MicroBitI2C used to communicate with the onboard accelerometer.
+ *
+ * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR.
+ *
+ * @param id the unique EventModel id of this component. Defaults to: MICROBIT_ID_ACCELEROMETER
+ *
+ * @code
+ * MicroBitI2C i2c = MicroBitI2C(I2C_SDA0, I2C_SCL0);
+ *
+ * MicroBitAccelerometer accelerometer = MicroBitAccelerometer(i2c);
+ * @endcode
+ */
+ MicroBitAccelerometer(MicroBitI2C &_i2c, uint16_t address = MMA8653_DEFAULT_ADDR, uint16_t id = MICROBIT_ID_ACCELEROMETER);
+
+ /**
+ * Configures the accelerometer for G range and sample rate defined
+ * in this object. The nearest values are chosen to those defined
+ * that are supported by the hardware. The instance variables are then
+ * updated to reflect reality.
+ *
+ * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the accelerometer could not be configured.
+ */
+ int configure();
+
+ /**
+ * Reads the acceleration data from the accelerometer, and stores it in our buffer.
+ * This only happens if the accelerometer indicates that it has new data via int1.
+ *
+ * On first use, this member function will attempt to add this component to the
+ * list of fiber components in order to constantly update the values stored
+ * by this object.
+ *
+ * This technique is called lazy instantiation, and it means that we do not
+ * obtain the overhead from non-chalantly adding this component to fiber components.
+ *
+ * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the read request fails.
+ */
+ int updateSample();
+
+ /**
+ * Attempts to set the sample rate of the accelerometer to the specified value (in ms).
+ *
+ * @param period the requested time between samples, in milliseconds.
+ *
+ * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
+ *
+ * @code
+ * // sample rate is now 20 ms.
+ * accelerometer.setPeriod(20);
+ * @endcode
+ *
+ * @note The requested rate may not be possible on the hardware. In this case, the
+ * nearest lower rate is chosen.
+ */
+ int setPeriod(int period);
+
+ /**
+ * Reads the currently configured sample rate of the accelerometer.
+ *
+ * @return The time between samples, in milliseconds.
+ */
+ int getPeriod();
+
+ /**
+ * Attempts to set the sample range of the accelerometer to the specified value (in g).
+ *
+ * @param range The requested sample range of samples, in g.
+ *
+ * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
+ *
+ * @code
+ * // the sample range of the accelerometer is now 8G.
+ * accelerometer.setRange(8);
+ * @endcode
+ *
+ * @note The requested range may not be possible on the hardware. In this case, the
+ * nearest lower range is chosen.
+ */
+ int setRange(int range);
+
+ /**
+ * Reads the currently configured sample range of the accelerometer.
+ *
+ * @return The sample range, in g.
+ */
+ int getRange();
+
+ /**
+ * Attempts to read the 8 bit ID from the accelerometer, this can be used for
+ * validation purposes.
+ *
+ * @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
+ *
+ * @code
+ * accelerometer.whoAmI();
+ * @endcode
+ */
+ int whoAmI();
+
+ /**
+ * Reads the value of the X axis from the latest update retrieved from the accelerometer.
+ *
+ * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+ *
+ * @return The force measured in the X axis, in milli-g.
+ *
+ * @code
+ * accelerometer.getX();
+ * @endcode
+ */
+ int getX(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+ /**
+ * Reads the value of the Y axis from the latest update retrieved from the accelerometer.
+ *
+ * @return The force measured in the Y axis, in milli-g.
+ *
+ * @code
+ * accelerometer.getY();
+ * @endcode
+ */
+ int getY(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+ /**
+ * Reads the value of the Z axis from the latest update retrieved from the accelerometer.
+ *
+ * @return The force measured in the Z axis, in milli-g.
+ *
+ * @code
+ * accelerometer.getZ();
+ * @endcode
+ */
+ int getZ(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+ /**
+ * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
+ *
+ * @return The pitch of the device, in degrees.
+ *
+ * @code
+ * accelerometer.getPitch();
+ * @endcode
+ */
+ int getPitch();
+
+ /**
+ * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
+ *
+ * @return The pitch of the device, in radians.
+ *
+ * @code
+ * accelerometer.getPitchRadians();
+ * @endcode
+ */
+ float getPitchRadians();
+
+ /**
+ * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
+ *
+ * @return The roll of the device, in degrees.
+ *
+ * @code
+ * accelerometer.getRoll();
+ * @endcode
+ */
+ int getRoll();
+
+ /**
+ * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
+ *
+ * @return The roll of the device, in radians.
+ *
+ * @code
+ * accelerometer.getRollRadians();
+ * @endcode
+ */
+ float getRollRadians();
+
+ /**
+ * Retrieves the last recorded gesture.
+ *
+ * @return The last gesture that was detected.
+ *
+ * Example:
+ * @code
+ * MicroBitDisplay display;
+ *
+ * if (accelerometer.getGesture() == SHAKE)
+ * display.scroll("SHAKE!");
+ * @endcode
+ */
+ BasicGesture getGesture();
+
+ /**
+ * A periodic callback invoked by the fiber scheduler idle thread.
+ *
+ * Internally calls updateSample().
+ */
+ virtual void idleTick();
+
+ /**
+ * Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
+ *
+ * We check if any data is ready for reading by checking the interrupt flag on the accelerometer.
+ */
+ virtual int isIdleCallbackNeeded();
+
+ /**
+ * Destructor for MicroBitButton, where we deregister this instance from the array of fiber components.
+ */
+ ~MicroBitAccelerometer();
+
+ private:
+
+ /**
+ * Issues a standard, 2 byte I2C command write to the accelerometer.
+ *
+ * Blocks the calling thread until complete.
+ *
+ * @param reg The address of the register to write to.
+ *
+ * @param value The value to write.
+ *
+ * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
+ */
+ int writeCommand(uint8_t reg, uint8_t value);
+
+ /**
+ * Issues a read command, copying data into the specified buffer.
+ *
+ * Blocks the calling thread until complete.
+ *
+ * @param reg The address of the register to access.
+ *
+ * @param buffer Memory area to read the data into.
+ *
+ * @param length The number of bytes to read.
+ *
+ * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
+ */
+ int readCommand(uint8_t reg, uint8_t* buffer, int length);
+
+ /**
+ * Recalculate roll and pitch values for the current sample.
+ *
+ * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather
+ * heavyweight for a CPU without a floating point unit.
+ */
+ void recalculatePitchRoll();
+
+ /**
+ * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote
+ * stability.
+ */
+ void updateGesture();
+
+ /**
+ * A service function.
+ * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2).
+ * It does not, however, square root the result, as this is a relatively high cost operation.
+ *
+ * This is left to application code should it be needed.
+ *
+ * @return the sum of the square of the acceleration of the device across all axes.
+ */
+ int instantaneousAccelerationSquared();
+
+ /**
+ * Service function.
+ * Determines a 'best guess' posture of the device based on instantaneous data.
+ *
+ * This makes no use of historic data, and forms this input to the filter implemented in updateGesture().
+ *
+ * @return A 'best guess' of the current posture of the device, based on instanataneous data.
+ */
+ BasicGesture instantaneousPosture();
+};
+
+#endif
