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
478 lines
14 KiB
5 years ago
|
/**************************************************************************/
|
||
|
/*!
|
||
|
@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;
|
||
|
}
|