/* * Author: Jon Trulson * Copyright (c) 2015 Intel Corporation. * * 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. */ #pragma once #include #include #define H3LIS331DL_I2C_BUS 0 #define H3LIS331DL_DEFAULT_I2C_ADDR 0x18 namespace upm { /** * @brief H3LIS331DL I2C accelerometer (400g) library * @defgroup h3lis331dl libupm-h3lis331dl * @ingroup seeed i2c accelerometer */ /** * @library h3lis331dl * @sensor h3lis331dl * @comname H3LIS331DL 3-Axis Digital Accelerometer * @altname Grove 3-Axis Digital Accelerometer (400g) * @type accelerometer * @man seeed * @web http://www.seeedstudio.com/depot/Grove-3Axis-Digital-Accelerometer400g-p-1897.html * @con i2c * * @brief API for the H3LIS331DL based Grove 3-axis I2C (400G) * * This is a high performance, high range accelerometer for extreme applications. * * @image html h3lis331dl.jpg * @snippet h3lis331dl.cxx Interesting */ class H3LIS331DL { public: /** * H3LIS331DL registers */ typedef enum { // Reserved bytes must not be written into as they contain // factory calibration data. Changing those values may lead to // improper functioning of the device. // 0x00-0x0E reserved REG_WHOAMI = 0x0f, // 0x10-0x1f reserved REG_REG1 = 0x20, REG_REG2 = 0x21, REG_REG3 = 0x22, REG_REG4 = 0x23, REG_REG5 = 0x24, REG_HP_FILTER_RESET = 0x25, REG_REFERENCE = 0x26, REG_STATUS = 0x27, REG_OUT_X_L = 0x28, REG_OUT_X_H = 0x29, REG_OUT_Y_L = 0x2a, REG_OUT_Y_H = 0x2b, REG_OUT_Z_L = 0x2c, REG_OUT_Z_H = 0x2d, // 0x2e, 0x2f reserved REG_INT1_CFG = 0x30, REG_INT1_SRC = 0x31, REG_INT1_THS = 0x32, REG_INT1_DUR = 0x33, REG_INT2_CFG = 0x34, REG_INT2_SRC = 0x35, REG_INT2_THS = 0x36, REG_INT2_DUR = 0x37, // 0x38-0x3f reserved } H3LIS331DL_REG_T; /** * REG1 bits */ typedef enum { REG1_XEN = 0x01, // X axis enable REG1_YEN = 0x02, REG1_ZEN = 0x04, REG1_DR0 = 0x08, // data rate REG1_DR1 = 0x10, REG1_DR_SHIFT = 3, // DR shift REG1_PM0 = 0x20, // power mode REG1_PM1 = 0x40, REG1_PM2 = 0x80, REG1_PM_SHIFT = 5 } REG1_BITS_T; /** * REG1 DR (output rate) bits */ typedef enum { DR_50_37 = 0x0, // 50Hz output with 37Hz LPF cutoff DR_100_74 = 0x1, DR_400_292 = 0x2, DR_1000_780 = 0x3 } DR_BITS_T; /** * REG1 PM (Power mode) bits */ typedef enum { PM_POWERDWN = 0x0, PM_NORMAL = 0x1, PM_LP05 = 0x2, // .5 updates/sec PM_LP1 = 0x3, // 1 update/sec PM_LP2 = 0x4, PM_LP5 = 0x5, PM_LP10 = 0x6 } PM_BITS_T; /** * REG2 bits */ typedef enum { REG2_HPCF0 = 0x01, REG2_HPCF1 = 0x02, REG2_HPCF_SHIFT = 0, REG2_HPEN1 = 0x04, REG2_HPEN2 = 0x08, REG2_FDS = 0x10, REG2_HPM0 = 0x20, REG2_HPM1 = 0x40, REG2_HPM_SHIFT = 5, REG2_BOOT = 0x80 } REG2_BITS_T; /** * REG2 HPCF (High Pass Cutoff Frequency) bits */ typedef enum { HPCF_8 = 0x0, HPCF_16 = 0x1, HPCF_32 = 0x2, HPCF_64 = 0x3, } HPCF_BITS_T; /** * REG2 HPM (High Pass Filter Mode) bits */ typedef enum { HPM_NORMAL0 = 0x0, HPM_REF = 0x1, HPM_NORMAL1 = 0x2 } HPM_BITS_T; /** * REG3 bits */ typedef enum { REG3_I1_CFG0 = 0x01, REG3_I1_CFG1 = 0x02, REG3_I1_CFG_SHIFT = 0, REG3_LIR1 = 0x04, REG3_I2_CFG0 = 0x08, REG3_I2_CFG1 = 0x10, REG3_I2_CFG_SHIFT = 3, REG3_LIR2 = 0x20, REG3_PP_OD = 0x40, REG3_IHL = 0x80 } REG3_BITS_T; /** * REG3 I1/I2 PAD control bits */ typedef enum { I_SRC = 0x0, // INT source I_OR = 0x1, // INT1 OR INT2 source I_DR = 0x2, // Data Ready I_BOOTING = 0x3 // Boot is running } I_CFG_BITS_T; /** * REG4 bits */ typedef enum { REG4_SIM = 0x01, // SPI 4 or 3 wire // bits 01,02,04 reserved REG4_FS0 = 0x10, REG4_FS1 = 0x20, REG4_FS_SHIFT = 4, REG4_BLE = 0x40, // big/little endian REG4_BDU = 0x80 // Block data update } REG4_BITS_T; /** * REG4 FS (Full Scale) bits */ typedef enum { FS_100 = 0x0, // 100g scale FS_200 = 0x1, // 200g scale FS_400 = 0x3 // 400g scale } FS_BITS_T; /** * REG5 TURNON (sleep to wake) bits */ typedef enum { REG5_TURNON0 = 0x01, // turnon mode for sleep-to-wake REG5_TURNON1 = 0x02 // bits 04-80 reserved } REG5_BITS_T; /** * STATUS bits */ typedef enum { STATUS_XDA = 0x01, // X data available STATUS_YDA = 0x02, STATUS_ZDA = 0x04, STATUS_ZYXDA = 0x08, // X, Y, and Z data available STATUS_XOR = 0x10, // X overrun STATUS_YOR = 0x20, STATUS_ZOR = 0x40, STATUS_ZYXOR = 0x80 // X, Y, and Z data overrun } STATUS_BITS_T; /** * INT1/INT2 CFG bits */ typedef enum { INT_CFG_XLIE = 0x01, // enable intr on low X event INT_CFG_XHIE = 0x02, // enable intr on high X event INT_CFG_YLIE = 0x04, INT_CFG_YHIE = 0x08, INT_CFG_ZLIE = 0x10, INT_CFG_ZHIE = 0x20, // 0x40 reserved INT_CFG_AOI = 0x80 // AND or OR combination or intrs } INT_CFG_BITS_T; /** * INT1/INT2 SRC bits */ typedef enum { INT_SRC_XL = 0x01, // X low intr event INT_SRC_XH = 0x02, // X high intr event INT_SRC_YL = 0x04, INT_SRC_YH = 0x08, INT_SRC_ZL = 0x10, INT_SRC_ZH = 0x20, INT_SRC_IA = 0x40 // Interrupt generated (active) // 0x80 reserved } INT_SRC_BITS_T; /** * h3lis331dl constructor * * @param bus i2c bus to use * @param address the address for this device */ H3LIS331DL(int bus, uint8_t address = H3LIS331DL_DEFAULT_I2C_ADDR); /** * H3LIS331DL Destructor */ ~H3LIS331DL(); /** * set up initial values and start operation * * @param odr the data rate: one of the DR_BITS_T values * @param pm the power mode: one of the PM_BITS_T values * @param fs the FullScale: one of the FS_BITS_T values * @return true if successful */ bool init(DR_BITS_T odr=DR_50_37, PM_BITS_T pm=PM_NORMAL, FS_BITS_T fs=FS_100); /** * read and return the Chip ID (WHO_AM_I register) * * @return true if successful */ uint8_t getChipID(); /** * set the output data rate * * @param one of the DR_BITS_T values * @return true if successful */ bool setDataRate(DR_BITS_T odr); /** * set the power mode * * @param one of the PM_BITS_T values * @return true if successful */ bool setPowerMode(PM_BITS_T pm); /** * enable one or more of the 3 axes. The arguement is a bitmsk * composed of REG1_XEN, REG1_YEN and/or REG1_ZEN corresponding * the axes you want enabled. * * @param axisEnable bitmask of axes to enable * (REG1_XEN | REG1_YEN | REG1_ZEN) * @return true if successful */ bool enableAxis(uint8_t axisEnable); /** * set the scaling factor to 100, 200, or 400G's * * @param fs one of the FS_BITS_T values * @return true if successful */ bool setFullScale(FS_BITS_T fs); /** * set high pass cutoff filter * * @param val one of the HPCF_BITS_T values * @return true if successful */ bool setHPCF(HPCF_BITS_T val); /** * set high pass filter mode * * @param val one of the HPM_BITS_T values * @return true if successful */ bool setHPM(HPM_BITS_T val); /** * boot the device. Booting the device causes internal flash * calibration values to be reloaded into the visible registers, * in the event they have been corrupted. This function will * return when boot is complete. * * @return true if successful */ bool boot(); /** * enable high pass filter for interrupt 1 source * * @param enable true to enable the filter, false otherwise * @return true if successful */ bool enableHPF1(bool enable); /** * enable high pass filter for interrupt 2 source * * @param enable true to enable the filter, false otherwise * @return true if successful */ bool enableHPF2(bool enable); /** * enable filtered data selection * * @param enable true to enable, false otherwise * @return true if successful */ bool enableFDS(bool enable); /** * set interrupts to be active low instead of high * * @param enable true to enable, false otherwise * @return true if successful */ bool setInterruptActiveLow(bool enable); /** * set interrupt output mode to open drain rather than push/pull * * @param enable true to enable, false otherwise * @return true if successful */ bool setInterruptOpenDrain(bool enable); /** * set interrupt 1 latch enable * * @param enable true to enable, false otherwise * @return true if successful */ bool setInterrupt1Latch(bool enable); /** * set interrupt 2 latch enable * * @param enable true to enable, false otherwise * @return true if successful */ bool setInterrupt2Latch(bool enable); /** * set the interrupt 1 pad configuration * * @param val one fo the I_CFG_BITS_T values * @return true if successful */ bool setInterrupt1PadConfig(I_CFG_BITS_T val); /** * set the interrupt 2 pad configuration * * @param val one fo the I_CFG_BITS_T values * @return true if successful */ bool setInterrupt2PadConfig(I_CFG_BITS_T val); /** * enable block data update. When enabled, low/high output * registers are not update until both low and high values have * been read. * * @param enable true to enable, false otherwise * @return true if successful */ bool enableBDU(bool enable); /** * enable big endian output for 16b reads * * @param enable true to enable, false otherwise * @return true if successful */ bool enableBLE(bool enable); /** * enable sleep to wake functionality. * * @param enable true to enable, false otherwise * @return true if successful */ bool enableSleepToWake(bool enable); /** * return the contents of the REG_STATUS register * * @return the contents of the REG_STATUS register */ uint8_t getStatus(); /** * setup the interrupt 1 config register * * @param val a bitmask of desired INT_CFG_BITS_T bits * @return true if successful */ bool setInterrupt1Config(uint8_t val); /** * setup the interrupt 2 config register * * @param val a bitmask of desired INT_CFG_BITS_T bits * @return true if successful */ bool setInterrupt2Config(uint8_t val); /** * setup the interrupt 1 source register * * @param val a bitmask of desired INT_SRC_BITS_T bits * @return true if successful */ bool setInterrupt1Source(uint8_t val); /** * setup the interrupt 2 source register * * @param val a bitmask of desired INT_SRC_BITS_T bits * @return true if successful */ bool setInterrupt2Source(uint8_t val); /** * setup the interrupt 1 threshold register * * @param val the threshhold to set * @return true if successful */ bool setInterrupt1Threshold(uint8_t val); /** * setup the interrupt 2 threshold register * * @param val the threshhold to set * @return true if successful */ bool setInterrupt2Threshold(uint8_t val); /** * setup the interrupt 1 duration register * * @param val the duration to set * @return true if successful */ bool setInterrupt1Duration(uint8_t val); /** * setup the interrupt 2 duration register * * @param val the duration to set * @return true if successful */ bool setInterrupt2Duration(uint8_t val); /** * read the sensor and store current values internally */ void update(); /** * set adjustment offsets for each of the axes. This can be used * for calibration. The values supplied here will be subtracted * from the axis data read from the device. * * @param adjX the amount by which to correct the X axis measurement * @param adjY the amount by which to correct the Y axis measurement * @param adjZ the amount by which to correct the Z axis measurement */ void setAdjustmentOffsets(int adjX, int adjY, int adjZ); /** * get the acceleration values for each of the axes * * @param aX the returned X acceleration * @param aY the returned Y acceleration * @param aZ the returned Z acceleration */ void getAcceleration(float *aX, float *aY, float *aZ); /** * get the raw axis values * * @param x the returned raw X value * @param y the returned raw Y value * @param z the returned raw Z value */ void getRawXYZ(int *x, int *y, int *z); /** * get the adjusted axis values * * @param x the returned X value * @param y the returned Y value * @param z the returned Z value */ void getXYZ(int *x, int *y, int *z); /** * provide public access to the class's MRAA i2C context for * direct user access * * @return a reference to the class i2c context */ mraa::I2c& i2cContext() { return m_i2c; }; protected: int16_t m_rawX, m_rawY, m_rawZ; int16_t m_adjX, m_adjY, m_adjZ; mraa::I2c m_i2c; private: uint8_t m_addr; }; }