/**************************************************************************/ /*! @file MSA300.h */ /**************************************************************************/ #include "Arduino.h" #include /*========================================================================= CONSTANTS -----------------------------------------------------------------------*/ /** */ #define GRAVITY (9.80665F) ///< Gravity constant /*=========================================================================*/ /*========================================================================= I2C ADDRESS/BITS -----------------------------------------------------------------------*/ #define MSA300_I2C_ADDRESS (0x26) ///< I2C write address. Assumes SDO pulled to GND, otherwise 0x4E /*=========================================================================*/ /*========================================================================= REGISTERS -----------------------------------------------------------------------*/ /** MSA300 Registers */ #define MSA_300_REG_SOFT_RESET (0x00) ///< Soft reset (R) #define MSA300_REG_PARTID (0x01) ///< Part ID (R) #define MSA300_REG_ACC_X_LSB (0x02) ///< X-acceleration LSB (R) #define MSA300_REG_ACC_X_MSB (0x03) ///< X-acceleration MSB (R) #define MSA300_REG_ACC_Y_LSB (0x04) ///< Y-acceleration LSB (R) #define MSA300_REG_ACC_Y_MSB (0x05) ///< Y-acceleration MSB (R) #define MSA300_REG_ACC_Z_LSB (0x06) ///< Z-acceleration LSB (R) #define MSA300_REG_ACC_Z_MSB (0x07) ///< Z-acceleration MSB (R) #define MSA300_REG_MOTION_INT (0x09) ///< Motion interrupt (R) #define MSA300_REG_DATA_INT (0x0A) ///< Data interrupt (R) #define MSA300_REG_TAP_ACTIVE_STATUS (0x0B) ///< Tap status (R) #define MSA300_REG_ORIENT_STATUS (0x0C) ///< Orientation status (R) #define MSA300_REG_RES_RANGE (0x0F) ///< Resolution/Range (R/W) #define MSA300_REG_ODR (0x10) ///< Output Data Rate (R/W) #define MSA300_REG_PWR_MODE_BW (0x11) ///< Power Mode/Bandwidth (R/W) #define MSA300_REG_SWAP_POLARITY (0x12) ///< Swap Axis Polarity (R/W) #define MSA300_REG_INT_SET_0 (0x16) ///< Interrupt Set 0 (R/W) #define MSA300_REG_INT_SET_1 (0x17) ///< Interrupt Set 1 (R/W) #define MSA300_REG_INT_MAP_0 (0x19) ///< Interrupt Map 0 (R/W) #define MSA300_REG_INT_MAP_1 (0x1A) ///< Interrupt Map 1 (R/W) #define MSA300_REG_INT_MAP_2_1 (0x1B) ///< Interrupt Map 2_1 (R/W) #define MSA300_REG_INT_MAP_2_2 (0x20) ///< Interrupt Map 2_2 (R/W) #define MSA300_REG_INT_LATCH (0x21) ///< Interrupt Latch (R/W) #define MSA300_REG_FREEFALL_DUR (0x22) ///< Freefall Duration (R/W) #define MSA300_REG_FREEFALL_TH (0x23) ///< Freefall Threshold (R/W) #define MSA300_REG_FREEFALL_HY (0x24) ///< Freefall Hysteresis (R/W) #define MSA300_REG_ACTIVE_DUR (0x27) ///< Active Duration (R/W) #define MSA300_REG_ACTIVE_TH (0x28) ///< Active Threshold (R/W) #define MSA300_REG_TAP_DUR (0x2A) ///< Tap Duration (R/W) #define MSA300_REG_TAP_TH (0x2B) ///< Tap Threshold (R/W) #define MSA300_REG_ORIENT_HY (0x2C) ///< Orientation Hysteresis (R/W) #define MSA300_REG_Z_BLOCK (0x2D) ///< Z Blocking (R/W) #define MSA300_REG_OFFSET_COMP_X (0x38) ///< X Offset Compensation (R/W) #define MSA300_REG_OFFSET_COMP_Y (0x39) ///< Y Offset Compensation (R/W) #define MSA300_REG_OFFSET_COMP_Z (0x3A) ///< Z Offset Compensation (R/W) /*=========================================================================*/ /*========================================================================= REGISTERS -----------------------------------------------------------------------*/ /* Value conversion multipliers */ #define MSA300_MG2G_MULTIPLIER_16_G (0.00195) ///< 1.95mg per lsb #define MSA300_MG2G_MULTIPLIER_8_G (0.000976) ///< 0.976mg per lsb #define MSA300_MG2G_MULTIPLIER_4_G (0.000488) ///< 0.488mg per lsb #define MSA300_MG2G_MULTIPLIER_2_G (0.000244) ///< 0.244mg per lsb /* Tap interrupt threshold conversion multiplier */ #define MSA300_MG2G_TAP_TH_16_G (0.5) ///< 500mg per lsb #define MSA300_MG2G_TAP_TH_8_G (0.25) ///< 250mg per lsb #define MSA300_MG2G_TAP_TH_4_G (0.125) ///< 125mg per lsb #define MSA300_MG2G_TAP_TH_2_G (0.0625) ///< 62.5mg per lsb /* Active interrupt threshold conversion multiplier */ #define MSA300_MG2G_ACTIVE_TH_16_G (0.03125) ///< 31.25mg per lsb #define MSA300_MG2G_ACTIVE_TH_8_G (0.015625) ///< 15.625mg per lsb #define MSA300_MG2G_ACTIVE_TH_4_G (0.00781) ///< 7.81mg per lsb #define MSA300_MG2G_ACTIVE_TH_2_G (0.00391) ///< 3.91mg per lsb /*=========================================================================*/ /** Datarate settings. Used with register 0x10 (MSA300_REG_ODR) to set datarate and with register 0x11 (MSA_REG_PWR_MODE_BW) to set Bandwidth */ typedef enum { MSA300_DATARATE_1000_HZ = 0b1111, ///< 500Hz Bandwidth, not available in low power mode MSA300_DATARATE_500_HZ = 0b1001, ///< 250Hz Bandwidth, not available in low power mode MSA300_DATARATE_250_HZ = 0b1000, ///< 125Hz Bandwidth MSA300_DATARATE_125_HZ = 0b0111, ///< 62.5Hz Bandwidth MSA300_DATARATE_62_5_HZ = 0b0110, ///< 31.25Hz Bandwidth MSA300_DATARATE_31_25_HZ = 0b0101, ///< 15.63Hz Bandwidth MSA300_DATARATE_15_63_HZ = 0b0100, ///< 7.81Hz Bandwidth MSA300_DATARATE_7_81_HZ = 0b0011, ///< 3.9Hz Bandwidth MSA300_DATARATE_3_9_HZ = 0b0010, ///< 1.95Hz Bandwidth MSA300_DATARATE_1_95_HZ = 0b0001, ///< 0.975Hz Bandwidth, not available in normal mode MSA300_DATARATE_1_HZ = 0b0000, ///< 0.5Hz Bandwidth, not available in normal mode } dataRate_t; /** Range settings. Used with register 0x0F (MSA300_REG_RES_RANGE) to set g range */ typedef enum { MSA300_RANGE_16_G = 0b11, ///< +/- 16g MSA300_RANGE_8_G = 0b10, ///< +/- 8g MSA300_RANGE_4_G = 0b01, ///< +/- 4g MSA300_RANGE_2_G = 0b00 ///< +/- 2g (default value) } range_t; /** Resolution settings. */ typedef enum { MSA300_RES_14_BIT = 0b00, ///< 14 bit (default value) MSA300_RES_12_BIT = 0b01, ///< 12 bit MSA300_RES_8_BIT = 0b11 ///< 8 bit } res_t; /** Power mode settings. */ typedef enum { MSA300_MODE_NORMAL = 0b00, ///< Normal operation mode MSA300_MODE_LOW = 0b01, ///< Low power mode MSA300_MODE_SUSPEND = 0b11 ///< Suspend/Shutdown mode } pwrMode_t; /** Interrupt latch settings. */ typedef enum { MSA300_INT_NON_LATCHED = 0b0000, ///< Non Latched MSA300_INT_LATCHED_250_MS = 0b0001, ///< 250ms Latched MSA300_INT_LATCHED_500_MS = 0b0010, ///< 500ms Latched MSA300_INT_LATCHED_1_S = 0b0011, ///< 1s Latched MSA300_INT_LATCHED_2_S = 0b0100, ///< 2s Latched MSA300_INT_LATCHED_4_S = 0b0101, ///< 4s Latched MSA300_INT_LATCHED_8_S = 0b0110, ///< 8s Latched MSA300_INT_LATCHED = 0b0111, ///< Permament Latched MSA300_INT_LATCHED_1_MS = 0b1001, ///< 1ms Latched MSA300_INT_LATCHED_2_MS = 0b1011, ///< 2ms Latched MSA300_INT_LATCHED_25_MS = 0b1100, ///< 25ms Latched MSA300_INT_LATCHED_50_MS = 0b1101, ///< 50ms Latched MSA300_INT_LATCHED_100_MS = 0b1110 ///< 100ms Latched } intMode_t; /** Axes. */ typedef enum { MSA300_AXIS_X = 0b00, ///< X axis MSA300_AXIS_Y = 0b01, ///< Y axis MSA300_AXIS_Z = 0b10 ///< Z axis } axis_t; /** Tap duration settings. */ typedef enum { MSA300_TAP_DUR_50_MS = 0b000, ///< 50ms tap MSA300_TAP_DUR_100_MS = 0b001, ///< 100ms tap MSA300_TAP_DUR_150_MS = 0b010, ///< 150ms tap MSA300_TAP_DUR_200_MS = 0b011, ///< 200ms tap MSA300_TAP_DUR_250_MS = 0b100, ///< 250ms tap MSA300_TAP_DUR_375_MS = 0b101, ///< 375ms tap MSA300_TAP_DUR_500_MS = 0b110, ///< 500ms tap MSA300_TAP_DUR_700_MS = 0b111 ///< 700ms tap } tapDuration_t; /** Acceleration container */ typedef struct { float x; ///< X acceleration float y; ///< Y acceleration float z; ///< Z acceleration } acc_t; /** Interrupt container. If active or tap interrupts are raised, populates intStatus with more info about interrupt. */ typedef struct { bool orientInt = false; ///< Orientation interrupt bool sTapInt = false; ///< Single tap interrupt bool dTapInt = false; ///< Double tap interrupt bool activeInt = false; ///< Active interrupt bool freefallInt = false; ///< Freefall interrupt bool newDataInt = false; ///< New data interrupt /** Optional interrupt status container */ union { /** Interrupt status container */ struct { uint8_t tapSign; ///< Tap interrupt sign uint8_t tapFirstX; ///< Tap triggered by x axis uint8_t tapFirstY; ///< Tap triggered by y axis uint8_t tapFirstZ; ///< Tap triggered by z axis uint8_t activeSign; ///< Active interrupt sign uint8_t activeFirstX; ///< Active interrupt triggered by x axis uint8_t activeFirstY; ///< Active interrupt triggered by y axis uint8_t activeFirstZ; ///< Active interrupt triggered by z axis } intStatus; }; } interrupt_t; /** Z orientation */ typedef enum { ORIENT_UPWARD_LOOKING = 0b0, ///< Upward looking orientation ORIENT_DOWNWARD_LOOKING = 0b1 ///< Downward looking orientation } zOrient_t; /** XY orientation */ typedef enum { ORIENT_PORTRAIT_UPRIGHT = 0b00, ///< Portait upright orientation ORIENT_PORTRAIT_UPSIDEDOWN = 0b01, ///< Portait upsidedown orientation ORIENT_LANDSCAPE_LEFT = 0b10, ///< Landscape left orientation ORIENT_LANDSCAPE_RIGHT = 0b11 ///< Landscape right orientation } xyOrient_t; /** Orientation container */ typedef struct { zOrient_t z; ///< Z orientation container xyOrient_t xy; ///< XY orientation container } orient_t; /** Polarity swap */ typedef enum { X_POLARITY = 3, ///< X polarity Y_POLARITY = 2, ///< Y polarity Z_POLARITY = 1, ///< Z polarity X_Y_SWAP = 0 ///< XY polarity swap } pol_t; /** Orientation mode */ typedef enum { MODE_SYMMETRICAL = 0b00, ///< Symmetrical mode MODE_HIGH_ASYMMETRICAL = 0b01, ///< High asymmetrical mode MODE_LOW_ASYMMETRICAL = 0b10 ///< Low asymmetrical mode } orientMode_t; /** Orientation blocking */ typedef enum { ORIENT_NO_BLOCKING = 0b00, ///< No blocking ORIENT_Z_BLOCKING = 0b01, ///< Z blocking ORIENT_Z_BLOCKING_0_2_G = 0b10 ///< Z blocking or slope in any axis > 0.2g } orientBlockMode_t; /** Class for MSA300 */ class MSA300{ public: MSA300(int32_t sensorID = -1); bool begin(void); void setRange(range_t range); range_t getRange(void); void setResolution(res_t resolution); res_t getResolution(void); void setDataRate(dataRate_t dataRate); dataRate_t getDataRate(void); void setMode(pwrMode_t mode); pwrMode_t getMode(void); void setOffset(axis_t axis, float value); void setTapThreshold(float value); void setTapDuration(tapDuration_t duration, uint8_t quiet, uint8_t shock); void setActiveThreshold(float value); void setActiveDuration(uint8_t duration); void setFreefallDuration(uint16_t duration); void setFreefallThreshold(float value); void setFreefallHysteresis(uint8_t mode, uint8_t value); void swapPolarity(pol_t polarity); void setOrientMode(orientMode_t mode); void setOrientHysteresis(float value); void setBlocking(orientBlockMode_t mode, float zBlockValue); void resetInterrupt(void); void clearInterrupts(void); interrupt_t checkInterrupts(void); void setInterruptLatch(intMode_t mode); void enableActiveInterrupt(axis_t axis, uint8_t interrupt); void enableFreefallInterrupt(uint8_t interrupt); void enableOrientationInterrupt(uint8_t interrupt); void enableSingleTapInterrupt(uint8_t interrupt); void enableDoubleTapInterrupt(uint8_t interrupt); void enableNewDataInterrupt(uint8_t interrupt); acc_t getAcceleration(void); orient_t checkOrientation(void); uint8_t getPartID(void); void writeRegister(uint8_t reg, uint8_t value); uint8_t readRegister(uint8_t reg); int16_t read16(uint8_t reg); int16_t getX(void), getY(void), getZ(void); private: int32_t _sensorID; range_t _range; float _multiplier; res_t _res; pwrMode_t _mode; }; /*! @brief Generic function for clamping values. @tparam T Type of value to be clamped @tparam value Value to be clamped @tparam min Minimum limit value @tparam max Maximum limit value @return Value if value inside limits, else min or max */ template T clamp(T value, T min, T max) { if(value > max) { value = max; } else if(value < min) { value = min; } return value; }