/**************************************************************************/ /*! @file Adafruit_CPlay_LIS3DH.cpp @author K. Townsend / Limor Fried (Adafruit Industries) license BSD (see license.txt) This is a library for the Adafruit LIS3DH Accel breakout board ----> https://www.adafruit.com/products/2809 Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! v1.0 - First release */ /**************************************************************************/ #if ARDUINO >= 100 #include "Arduino.h" #else #include "WProgram.h" #endif #include #include #ifdef __SAMD21G18A__ #define Wire Wire1 // CP Express has LIS on Wire1 bus #endif /**************************************************************************/ /*! @brief Instantiates a new LIS3DH class in I2C mode */ /**************************************************************************/ Adafruit_CPlay_LIS3DH::Adafruit_CPlay_LIS3DH() : _cs(-1), _mosi(-1), _miso(-1), _sck(-1), _sensorID(-1) { } /**************************************************************************/ /*! @brief Instantiates a new LIS3DH class in hardware SPI mode @param cspin the pin used as a chip select */ /**************************************************************************/ Adafruit_CPlay_LIS3DH::Adafruit_CPlay_LIS3DH(int8_t cspin) : _cs(cspin), _mosi(-1), _miso(-1), _sck(-1), _sensorID(-1) { } /**************************************************************************/ /*! @brief Instantiates a new LIS3DH class in software SPI mode @param cspin the pin used as a chip select @param mosipin the pin used as master-out-slave-in @param misopin the pin used as master-in-slave-out @param sckpin the pin used as SPI serial clock */ /**************************************************************************/ Adafruit_CPlay_LIS3DH::Adafruit_CPlay_LIS3DH(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin) : _cs(cspin), _mosi(mosipin), _miso(misopin), _sck(sckpin), _sensorID(-1) { } /**************************************************************************/ /*! @brief Setups the HW (reads coefficients values, etc.) @param i2caddr the I2C address the device can be found on. defaults to 0x18 @return true on success, false on any failure */ /**************************************************************************/ bool Adafruit_CPlay_LIS3DH::begin(uint8_t i2caddr) { _i2caddr = i2caddr; if (_cs == -1) { // i2c Wire.begin(); } else { digitalWrite(_cs, HIGH); pinMode(_cs, OUTPUT); #ifndef __AVR_ATtiny85__ if (_sck == -1) { // hardware SPI SPI.begin(); } else { // software SPI pinMode(_sck, OUTPUT); pinMode(_mosi, OUTPUT); pinMode(_miso, INPUT); } #endif } /* for (uint8_t i=0; i<0x30; i++) { Serial.print("$"); Serial.print(i, HEX); Serial.print(" = 0x"); Serial.println(readRegister8(i), HEX); } */ /* Check connection */ uint8_t deviceid = readRegister8(LIS3DH_REG_WHOAMI); if (deviceid != 0x33) { /* No LIS3DH detected ... return false */ //Serial.println(deviceid, HEX); return false; } // enable all axes, normal mode writeRegister8(LIS3DH_REG_CTRL1, 0x07); // 400Hz rate setDataRate(LIS3DH_DATARATE_400_HZ); // High res & BDU enabled writeRegister8(LIS3DH_REG_CTRL4, 0x88); // DRDY on INT1 writeRegister8(LIS3DH_REG_CTRL3, 0x10); // Turn on orientation config //writeRegister8(LIS3DH_REG_PL_CFG, 0x40); // enable adcs writeRegister8(LIS3DH_REG_TEMPCFG, 0x80); /* for (uint8_t i=0; i<0x30; i++) { Serial.print("$"); Serial.print(i, HEX); Serial.print(" = 0x"); Serial.println(readRegister8(i), HEX); } */ return true; } /**************************************************************************/ /*! @brief read x, y, and z axis data and store in class variables. */ /**************************************************************************/ void Adafruit_CPlay_LIS3DH::read(void) { // read x y z at once if (_cs == -1) { // i2c Wire.beginTransmission(_i2caddr); Wire.write(LIS3DH_REG_OUT_X_L | 0x80); // 0x80 for autoincrement Wire.endTransmission(); Wire.requestFrom(_i2caddr, 6); x = Wire.read(); x |= ((uint16_t)Wire.read()) << 8; y = Wire.read(); y |= ((uint16_t)Wire.read()) << 8; z = Wire.read(); z |= ((uint16_t)Wire.read()) << 8; } #ifndef __AVR_ATtiny85__ else { #if SPI_HAS_TRANSACTION if (_sck == -1) SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); #endif digitalWrite(_cs, LOW); spixfer(LIS3DH_REG_OUT_X_L | 0x80 | 0x40); // read multiple, bit 7&6 high x = spixfer(); x |= ((uint16_t)spixfer()) << 8; y = spixfer(); y |= ((uint16_t)spixfer()) << 8; z = spixfer(); z |= ((uint16_t)spixfer()) << 8; digitalWrite(_cs, HIGH); #if SPI_HAS_TRANSACTION if (_sck == -1) SPI.endTransaction(); // release the SPI bus #endif } #endif uint8_t range = getRange(); uint16_t divider = 1; if (range == LIS3DH_RANGE_16_G) divider = 1365; if (range == LIS3DH_RANGE_8_G) divider = 4096; if (range == LIS3DH_RANGE_4_G) divider = 8190; if (range == LIS3DH_RANGE_2_G) divider = 16380; x_g = (float)x / divider; y_g = (float)y / divider; z_g = (float)z / divider; } /**************************************************************************/ /*! @brief Read the auxilary ADC @param adc the adc number to read. Valid adc numbers are 1, 2, and 3. @return the measured value */ /**************************************************************************/ int16_t Adafruit_CPlay_LIS3DH::readADC(uint8_t adc) { if ((adc < 1) || (adc > 3)) return 0; uint16_t value; adc--; uint8_t reg = LIS3DH_REG_OUTADC1_L + adc*2; if (_cs == -1) { // i2c Wire.beginTransmission(_i2caddr); Wire.write(reg | 0x80); // 0x80 for autoincrement Wire.endTransmission(); Wire.requestFrom(_i2caddr, 2); value = Wire.read(); value |= ((uint16_t)Wire.read()) << 8; } #ifndef __AVR_ATtiny85__ else { #if SPI_HAS_TRANSACTION if (_sck == -1) SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); #endif digitalWrite(_cs, LOW); spixfer(reg | 0x80 | 0x40); // read multiple, bit 7&6 high value = spixfer(); value |= ((uint16_t)spixfer()) << 8; digitalWrite(_cs, HIGH); #if SPI_HAS_TRANSACTION if (_sck == -1) SPI.endTransaction(); // release the SPI bus #endif } #endif return value; } /**************************************************************************/ /*! @brief Set INT to output for single or double click @param c the number of taps to detect. pass 1 for single tap on all axis, 2 for double tap on all axis. Pass 0 to disable taps. @param clickthresh the threshold over which to register a tap. @param timelimit Optional time limit for a tap. Defaults to 10 @param timelatency Optional tap latency. defaults to 20 @param timewindow Optional time window. defaults to 255 */ /**************************************************************************/ void Adafruit_CPlay_LIS3DH::setClick(uint8_t c, uint8_t clickthresh, uint8_t timelimit, uint8_t timelatency, uint8_t timewindow) { if (!c) { //disable int uint8_t r = readRegister8(LIS3DH_REG_CTRL3); r &= ~(0x80); // turn off I1_CLICK writeRegister8(LIS3DH_REG_CTRL3, r); writeRegister8(LIS3DH_REG_CLICKCFG, 0); return; } // else... writeRegister8(LIS3DH_REG_CTRL3, 0x80); // turn on int1 click writeRegister8(LIS3DH_REG_CTRL5, 0x08); // latch interrupt on int1 if (c == 1) writeRegister8(LIS3DH_REG_CLICKCFG, 0x15); // turn on all axes & singletap if (c == 2) writeRegister8(LIS3DH_REG_CLICKCFG, 0x2A); // turn on all axes & doubletap writeRegister8(LIS3DH_REG_CLICKTHS, clickthresh); // arbitrary writeRegister8(LIS3DH_REG_TIMELIMIT, timelimit); // arbitrary writeRegister8(LIS3DH_REG_TIMELATENCY, timelatency); // arbitrary writeRegister8(LIS3DH_REG_TIMEWINDOW, timewindow); // arbitrary } /**************************************************************************/ /*! @brief get a tap reading @return the tap reading */ /**************************************************************************/ uint8_t Adafruit_CPlay_LIS3DH::getClick(void) { return readRegister8(LIS3DH_REG_CLICKSRC); } /**************************************************************************/ /*! @brief Sets the g range for the accelerometer @param range the desired range of the device. Pass LIS3DH_RANGE_2_G for highest sensitivity and lowest max/min value (+-2G), LIS3DH_RANGE_16_G for lowest sensitivity and highest max/min value (+-16G). Other acceptable values are LIS3DH_RANGE_4_G and LIS3DH_RANGE_8_G. */ /**************************************************************************/ void Adafruit_CPlay_LIS3DH::setRange(lis3dh_range_t range) { uint8_t r = readRegister8(LIS3DH_REG_CTRL4); r &= ~(0x30); r |= range << 4; writeRegister8(LIS3DH_REG_CTRL4, r); } /**************************************************************************/ /*! @brief Sets the g range for the accelerometer @return the range reading from the sensor. */ /**************************************************************************/ lis3dh_range_t Adafruit_CPlay_LIS3DH::getRange(void) { /* Read the data format register to preserve bits */ return (lis3dh_range_t)((readRegister8(LIS3DH_REG_CTRL4) >> 4) & 0x03); } /**************************************************************************/ /*! @brief Sets the data rate for the LIS3DH (controls power consumption) @param dataRate the desired datarate. */ /**************************************************************************/ void Adafruit_CPlay_LIS3DH::setDataRate(lis3dh_dataRate_t dataRate) { uint8_t ctl1 = readRegister8(LIS3DH_REG_CTRL1); ctl1 &= ~(0xF0); // mask off bits ctl1 |= (dataRate << 4); writeRegister8(LIS3DH_REG_CTRL1, ctl1); } /**************************************************************************/ /*! @brief Sets the data rate for the LIS3DH (controls power consumption) @return the data rate reading from the sensor. */ /**************************************************************************/ lis3dh_dataRate_t Adafruit_CPlay_LIS3DH::getDataRate(void) { return (lis3dh_dataRate_t)((readRegister8(LIS3DH_REG_CTRL1) >> 4)& 0x0F); } /**************************************************************************/ /*! @brief Gets the most recent sensor event @param event the pointer to place the event reading in @return none */ /**************************************************************************/ bool Adafruit_CPlay_LIS3DH::getEvent(sensors_event_t *event) { /* Clear the event */ memset(event, 0, sizeof(sensors_event_t)); event->version = sizeof(sensors_event_t); event->sensor_id = _sensorID; event->type = SENSOR_TYPE_ACCELEROMETER; event->timestamp = 0; read(); event->acceleration.x = x_g * SENSORS_GRAVITY_STANDARD; event->acceleration.y = y_g * SENSORS_GRAVITY_STANDARD; event->acceleration.z = z_g * SENSORS_GRAVITY_STANDARD; } /**************************************************************************/ /*! @brief Gets the sensor_t data @param sensor the pointer to place sensor information into. */ /**************************************************************************/ void Adafruit_CPlay_LIS3DH::getSensor(sensor_t *sensor) { /* Clear the sensor_t object */ memset(sensor, 0, sizeof(sensor_t)); /* Insert the sensor name in the fixed length char array */ strncpy (sensor->name, "LIS3DH", sizeof(sensor->name) - 1); sensor->name[sizeof(sensor->name)- 1] = 0; sensor->version = 1; sensor->sensor_id = _sensorID; sensor->type = SENSOR_TYPE_ACCELEROMETER; sensor->min_delay = 0; sensor->max_value = 0; sensor->min_value = 0; sensor->resolution = 0; } /**************************************************************************/ /*! @brief Low level SPI @param x the byte to transfer @return the read byte */ /**************************************************************************/ uint8_t Adafruit_CPlay_LIS3DH::spixfer(uint8_t x) { #ifndef __AVR_ATtiny85__ if (_sck == -1) return SPI.transfer(x); // software spi //Serial.println("Software SPI"); uint8_t reply = 0; for (int i=7; i>=0; i--) { reply <<= 1; digitalWrite(_sck, LOW); digitalWrite(_mosi, x & (1<