You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

478 lines
14 KiB

/**************************************************************************/
/*!
@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 <Wire.h>
#include <Adafruit_CPlay_LIS3DH.h>
#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<<i));
digitalWrite(_sck, HIGH);
if (digitalRead(_miso))
reply |= 1;
}
return reply;
#endif
}
/**************************************************************************/
/*!
@brief Writes 8-bits to the specified destination register
*/
/**************************************************************************/
void Adafruit_CPlay_LIS3DH::writeRegister8(uint8_t reg, uint8_t value) {
if (_cs == -1) {
Wire.beginTransmission((uint8_t)_i2caddr);
Wire.write((uint8_t)reg);
Wire.write((uint8_t)value);
Wire.endTransmission();
}
#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); // write, bit 7 low
spixfer(value);
digitalWrite(_cs, HIGH);
#if SPI_HAS_TRANSACTION
if (_sck == -1)
SPI.endTransaction(); // release the SPI bus
#endif
}
#endif
}
/**************************************************************************/
/*!
@brief Reads 8-bits from the specified register
*/
/**************************************************************************/
uint8_t Adafruit_CPlay_LIS3DH::readRegister8(uint8_t reg) {
uint8_t value;
if (_cs == -1) {
Wire.beginTransmission(_i2caddr);
Wire.write((uint8_t)reg);
Wire.endTransmission();
Wire.requestFrom(_i2caddr, 1);
value = Wire.read();
}
#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); // read, bit 7 high
value = spixfer(0);
digitalWrite(_cs, HIGH);
#if SPI_HAS_TRANSACTION
if (_sck == -1)
SPI.endTransaction(); // release the SPI bus
#endif
}
#endif
return value;
}