509 lines
18 KiB
C++
509 lines
18 KiB
C++
/**************************************************************************/
|
|
/*!
|
|
@file Adafruit_ADXL343.cpp
|
|
@author Bryan Siepert and K.Townsend (Adafruit Industries)
|
|
|
|
BSD License (see license.txt)
|
|
|
|
The ADXL343 is a digital accelerometer with 13-bit resolution, capable
|
|
of measuring up to +/-16g. This driver communicates using I2C.
|
|
|
|
This is a library for the Adafruit ADXL343 breakout
|
|
----> https://www.adafruit.com/product/4097
|
|
or the Adafruit ADXL343 + ADT7410 FeatherWing
|
|
----> https://www.adafruit.com/product/4147
|
|
|
|
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 <limits.h>
|
|
|
|
#include "Adafruit_ADXL343.h"
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Writes 8-bits to the specified destination register
|
|
|
|
@param reg The register to write to
|
|
@param value The value to write to the register
|
|
*/
|
|
/**************************************************************************/
|
|
|
|
void Adafruit_ADXL343::writeRegister(uint8_t reg, uint8_t value) {
|
|
Adafruit_BusIO_Register reg_obj = Adafruit_BusIO_Register(
|
|
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, reg, 1);
|
|
reg_obj.write(value);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Reads 8-bits from the specified register
|
|
|
|
@param reg register to read
|
|
|
|
@return The results of the register read request
|
|
*/
|
|
/**************************************************************************/
|
|
uint8_t Adafruit_ADXL343::readRegister(uint8_t reg) {
|
|
Adafruit_BusIO_Register reg_obj = Adafruit_BusIO_Register(
|
|
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, reg, 1);
|
|
return ((uint8_t)reg_obj.read());
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Reads 16-bits from the specified register
|
|
|
|
@param reg The register to read two bytes from
|
|
|
|
@return The 16-bit value read from the reg starting address
|
|
*/
|
|
/**************************************************************************/
|
|
|
|
int16_t Adafruit_ADXL343::read16(uint8_t reg) {
|
|
Adafruit_BusIO_Register reg_obj = Adafruit_BusIO_Register(
|
|
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, reg, 2);
|
|
return ((uint16_t)reg_obj.read());
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Read the device ID (can be used to check connection)
|
|
|
|
@return The 8-bit device ID
|
|
*/
|
|
/**************************************************************************/
|
|
uint8_t Adafruit_ADXL343::getDeviceID(void) {
|
|
// Check device ID register
|
|
return readRegister(ADXL3XX_REG_DEVID);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Enables (1) or disables (0) the interrupts on the specified
|
|
interrupt pin.
|
|
|
|
@param cfg The bitfield of the interrupts to enable or disable.
|
|
|
|
@return True if the operation was successful, otherwise false.
|
|
*/
|
|
/**************************************************************************/
|
|
bool Adafruit_ADXL343::enableInterrupts(int_config cfg) {
|
|
/* Update the INT_ENABLE register with 'config'. */
|
|
writeRegister(ADXL3XX_REG_INT_ENABLE, cfg.value);
|
|
|
|
/* ToDo: Add proper error checking! */
|
|
return true;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief 'Maps' the specific interrupt to either pin INT1 (bit=0),
|
|
of pin INT2 (bit=1).
|
|
|
|
@param cfg The bitfield of the interrupts to enable or disable.
|
|
|
|
@return True if the operation was successful, otherwise false.
|
|
*/
|
|
/**************************************************************************/
|
|
bool Adafruit_ADXL343::mapInterrupts(int_config cfg) {
|
|
/* Update the INT_MAP register with 'config'. */
|
|
writeRegister(ADXL3XX_REG_INT_MAP, cfg.value);
|
|
|
|
/* ToDo: Add proper error checking! */
|
|
return true;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Reads the status of the interrupt pins. Reading this register
|
|
also clears or deasserts any currently active interrupt.
|
|
|
|
@return The 8-bit content of the INT_SOURCE register.
|
|
*/
|
|
/**************************************************************************/
|
|
uint8_t Adafruit_ADXL343::checkInterrupts(void) {
|
|
return readRegister(ADXL3XX_REG_INT_SOURCE);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Gets the most recent X axis value
|
|
|
|
@return The 16-bit signed value for the X axis
|
|
*/
|
|
/**************************************************************************/
|
|
int16_t Adafruit_ADXL343::getX(void) { return read16(ADXL3XX_REG_DATAX0); }
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Gets the most recent Y axis value
|
|
|
|
@return The 16-bit signed value for the Y axis
|
|
*/
|
|
/**************************************************************************/
|
|
int16_t Adafruit_ADXL343::getY(void) { return read16(ADXL3XX_REG_DATAY0); }
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Gets the most recent Z axis value
|
|
|
|
@return The 16-bit signed value for the Z axis
|
|
*/
|
|
/**************************************************************************/
|
|
int16_t Adafruit_ADXL343::getZ(void) { return read16(ADXL3XX_REG_DATAZ0); }
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Reads 3x16-bits from the x, y, and z data register
|
|
@param x reference to return x acceleration data
|
|
@param y reference to return y acceleration data
|
|
@param z reference to return z acceleration data
|
|
@return True if the operation was successful, otherwise false.
|
|
*/
|
|
/**************************************************************************/
|
|
bool Adafruit_ADXL343::getXYZ(int16_t &x, int16_t &y, int16_t &z) {
|
|
int16_t buffer[] = {0, 0, 0};
|
|
Adafruit_BusIO_Register reg_obj = Adafruit_BusIO_Register(
|
|
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_DATAX0, 6);
|
|
if (!reg_obj.read((uint8_t *)&buffer, 6))
|
|
return false;
|
|
x = buffer[0];
|
|
y = buffer[1];
|
|
z = buffer[2];
|
|
return true;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
* @brief Instantiates a new ADXL343 class
|
|
*
|
|
* @param sensorID An optional ID # so you can track this sensor, it will
|
|
* tag sensorEvents you create.
|
|
*/
|
|
/**************************************************************************/
|
|
Adafruit_ADXL343::Adafruit_ADXL343(int32_t sensorID) {
|
|
_sensorID = sensorID;
|
|
_wire = &Wire;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
* @brief Instantiates a new ADXL343 class
|
|
*
|
|
* @param sensorID An optional ID # so you can track this sensor, it will
|
|
* tag sensorEvents you create.
|
|
* @param wireBus TwoWire instance to use for I2C communication.
|
|
*/
|
|
/**************************************************************************/
|
|
Adafruit_ADXL343::Adafruit_ADXL343(int32_t sensorID, TwoWire *wireBus) {
|
|
_sensorID = sensorID;
|
|
_wire = wireBus;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Instantiates a new ADXL343 class in software SPI mode
|
|
|
|
@param clock The SCK pin
|
|
@param miso The MISO pin
|
|
@param mosi The MOSI pin
|
|
@param cs The CS/SSEL pin
|
|
@param sensorID An optional ID # so you can track this sensor, it will tag
|
|
sensorEvents you create.
|
|
*/
|
|
/**************************************************************************/
|
|
Adafruit_ADXL343::Adafruit_ADXL343(uint8_t clock, uint8_t miso, uint8_t mosi,
|
|
uint8_t cs, int32_t sensorID) {
|
|
_sensorID = sensorID;
|
|
_cs = cs;
|
|
_clk = clock;
|
|
_do = mosi;
|
|
_di = miso;
|
|
_wire = NULL;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Instantiates a new ADXL343 class in hardware SPI mode
|
|
|
|
@param cs The CS/SSEL pin
|
|
@param theSPI SPIClass instance to use for SPI communication.
|
|
@param sensorID An optional ID # so you can track this sensor, it will tag
|
|
sensorEvents you create.
|
|
*/
|
|
/**************************************************************************/
|
|
Adafruit_ADXL343::Adafruit_ADXL343(uint8_t cs, SPIClass *theSPI,
|
|
int32_t sensorID) {
|
|
_sensorID = sensorID;
|
|
_cs = cs;
|
|
_spi = theSPI;
|
|
_wire = NULL;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Setups the HW (reads coefficients values, etc.)
|
|
@param i2caddr The 7-bit I2C address to find the ADXL on
|
|
@return True if the sensor was successfully initialised.
|
|
*/
|
|
/**************************************************************************/
|
|
bool Adafruit_ADXL343::begin(uint8_t i2caddr) {
|
|
|
|
if (_wire) {
|
|
//-- I2C --------------
|
|
if (i2c_dev) {
|
|
delete i2c_dev; // remove old interface
|
|
}
|
|
i2c_dev = new Adafruit_I2CDevice(i2caddr, _wire);
|
|
|
|
if (!i2c_dev->begin()) {
|
|
return false;
|
|
}
|
|
|
|
} else {
|
|
//-- SPI --------------
|
|
i2c_dev = NULL;
|
|
|
|
if (spi_dev) {
|
|
delete spi_dev; // remove old interface
|
|
}
|
|
if (_spi) {
|
|
// hardware spi
|
|
spi_dev = new Adafruit_SPIDevice(_cs,
|
|
1000000, // frequency
|
|
SPI_BITORDER_MSBFIRST, // bit order
|
|
SPI_MODE3, // data mode
|
|
_spi); // hardware SPI
|
|
} else {
|
|
// software spi
|
|
spi_dev = new Adafruit_SPIDevice(_cs, _clk, _di, _do,
|
|
1000000, // frequency
|
|
SPI_BITORDER_MSBFIRST, // bit order
|
|
SPI_MODE3); // data mode
|
|
}
|
|
|
|
if (!spi_dev->begin()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Check connection */
|
|
uint8_t deviceid = getDeviceID();
|
|
if (deviceid != 0xE5) {
|
|
/* No ADXL343 detected ... return false */
|
|
return false;
|
|
}
|
|
|
|
_range = ADXL343_RANGE_2_G;
|
|
// Default tap detection level (2G, 31.25ms duration, single tap only)
|
|
// If only the single tap function is in use, the single tap interrupt
|
|
// is triggered when the acceleration goes below the threshold, as
|
|
// long as DUR has not been exceeded.
|
|
writeRegister(ADXL3XX_REG_INT_ENABLE, 0); // Disable interrupts to start
|
|
writeRegister(ADXL3XX_REG_THRESH_TAP, 20); // 62.5 mg/LSB (so 0xFF = 16 g)
|
|
writeRegister(ADXL3XX_REG_DUR, 50); // Max tap duration, 625 µs/LSB
|
|
writeRegister(ADXL3XX_REG_LATENT,
|
|
0); // Tap latency, 1.25 ms/LSB, 0=no double tap
|
|
writeRegister(ADXL3XX_REG_WINDOW,
|
|
0); // Waiting period, 1.25 ms/LSB, 0=no double tap
|
|
writeRegister(ADXL3XX_REG_TAP_AXES, 0x7); // Enable the XYZ axis for tap
|
|
|
|
// Enable measurements
|
|
writeRegister(ADXL3XX_REG_POWER_CTL, 0x08);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Sets the g range for the accelerometer
|
|
|
|
@param range The range to set, based on adxl34x_range_t
|
|
*/
|
|
/**************************************************************************/
|
|
void Adafruit_ADXL343::setRange(adxl34x_range_t range) {
|
|
Adafruit_BusIO_Register data_format_reg =
|
|
Adafruit_BusIO_Register(i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC,
|
|
ADXL3XX_REG_DATA_FORMAT, 1);
|
|
|
|
Adafruit_BusIO_RegisterBits range_bits =
|
|
Adafruit_BusIO_RegisterBits(&data_format_reg, 2, 0);
|
|
|
|
Adafruit_BusIO_RegisterBits full_range_bit =
|
|
Adafruit_BusIO_RegisterBits(&data_format_reg, 1, 3);
|
|
|
|
/* Update the data rate */
|
|
range_bits.write(range);
|
|
/* Make sure that the FULL-RES bit is enabled for range scaling */
|
|
full_range_bit.write(true);
|
|
|
|
/* Keep track of the current range (to avoid readbacks) */
|
|
_range = range;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Sets the g range for the accelerometer
|
|
|
|
@return The adxl34x_range_t value corresponding to the sensors range
|
|
*/
|
|
/**************************************************************************/
|
|
adxl34x_range_t Adafruit_ADXL343::getRange(void) {
|
|
Adafruit_BusIO_Register data_format_reg =
|
|
Adafruit_BusIO_Register(i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC,
|
|
ADXL3XX_REG_DATA_FORMAT, 1);
|
|
|
|
Adafruit_BusIO_RegisterBits range_bits =
|
|
Adafruit_BusIO_RegisterBits(&data_format_reg, 2, 0);
|
|
return (adxl34x_range_t)range_bits.read();
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Sets the data rate for the ADXL343 (controls power consumption)
|
|
|
|
@param dataRate The data rate to set, based on adxl3xx_dataRate_t
|
|
*/
|
|
/**************************************************************************/
|
|
void Adafruit_ADXL343::setDataRate(adxl3xx_dataRate_t dataRate) {
|
|
/* Note: The LOW_POWER bits are currently ignored and we always keep
|
|
the device in 'normal' mode */
|
|
writeRegister(ADXL3XX_REG_BW_RATE, dataRate);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Sets the data rate for the ADXL343 (controls power consumption)
|
|
|
|
@return The current data rate, based on adxl3xx_dataRate_t
|
|
*/
|
|
/**************************************************************************/
|
|
adxl3xx_dataRate_t Adafruit_ADXL343::getDataRate(void) {
|
|
Adafruit_BusIO_Register bw_rate_reg = Adafruit_BusIO_Register(
|
|
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_BW_RATE, 1);
|
|
|
|
Adafruit_BusIO_RegisterBits rate_bits =
|
|
Adafruit_BusIO_RegisterBits(&bw_rate_reg, 4, 0);
|
|
|
|
return (adxl3xx_dataRate_t)rate_bits.read();
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Retrieves the X Y Z trim offsets, note that they are 4 bits signed
|
|
but we use int8_t to store and 'extend' the sign bit!
|
|
@param x Pointer to the x offset, from -5 to 4 (internally multiplied by 8
|
|
lsb)
|
|
@param y Pointer to the y offset, from -5 to 4 (internally multiplied by 8
|
|
lsb)
|
|
@param z Pointer to the z offset, from -5 to 4 (internally multiplied by 8
|
|
lsb)
|
|
*/
|
|
/**************************************************************************/
|
|
void Adafruit_ADXL343::getTrimOffsets(int8_t *x, int8_t *y, int8_t *z) {
|
|
Adafruit_BusIO_Register x_off = Adafruit_BusIO_Register(
|
|
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSX, 1);
|
|
if (x != NULL)
|
|
*x = x_off.read();
|
|
Adafruit_BusIO_Register y_off = Adafruit_BusIO_Register(
|
|
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSY, 1);
|
|
if (y != NULL)
|
|
*y = y_off.read();
|
|
Adafruit_BusIO_Register z_off = Adafruit_BusIO_Register(
|
|
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSZ, 1);
|
|
if (z != NULL)
|
|
*z = z_off.read();
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Sets the X Y Z trim offsets, note that they are 4 bits signed
|
|
but we use int8_t to store and 'extend' the sign bit!
|
|
@param x The x offset, from -5 to 4 (internally multiplied by 8 lsb)
|
|
@param y The y offset, from -5 to 4 (internally multiplied by 8 lsb)
|
|
@param z The z offset, from -5 to 4 (internally multiplied by 8 lsb)
|
|
*/
|
|
/**************************************************************************/
|
|
void Adafruit_ADXL343::setTrimOffsets(int8_t x, int8_t y, int8_t z) {
|
|
Adafruit_BusIO_Register x_off = Adafruit_BusIO_Register(
|
|
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSX, 1);
|
|
x_off.write(x);
|
|
|
|
Adafruit_BusIO_Register y_off = Adafruit_BusIO_Register(
|
|
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSY, 1);
|
|
y_off.write(y);
|
|
|
|
Adafruit_BusIO_Register z_off = Adafruit_BusIO_Register(
|
|
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSZ, 1);
|
|
z_off.write(z);
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Gets the most recent sensor event
|
|
|
|
@param event Pointer to the sensors_event_t placeholder
|
|
|
|
@return True of the read request was successful.
|
|
*/
|
|
/**************************************************************************/
|
|
bool Adafruit_ADXL343::getEvent(sensors_event_t *event) {
|
|
int16_t x, y, z;
|
|
/* 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 = millis();
|
|
if (!getXYZ(x, y, z))
|
|
return false;
|
|
event->acceleration.x =
|
|
x * ADXL343_MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD;
|
|
event->acceleration.y =
|
|
y * ADXL343_MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD;
|
|
event->acceleration.z =
|
|
z * ADXL343_MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Gets the sensor_t data
|
|
|
|
@param sensor Pointer to the sensor_t placeholder.
|
|
*/
|
|
/**************************************************************************/
|
|
void Adafruit_ADXL343::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, "ADXL343", 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->min_value = -156.9064F; /* -16g = 156.9064 m/s^2 */
|
|
sensor->max_value = 156.9064F; /* 16g = 156.9064 m/s^2 */
|
|
sensor->resolution = 0.03923F; /* 4mg = 0.0392266 m/s^2 */
|
|
}
|