/*----------------------------------------------------------------------------*/ | |
/* Copyright (c) FIRST 2008. All Rights Reserved. */ | |
/* Open Source Software - may be modified and shared by FRC teams. The code */ | |
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ | |
/*----------------------------------------------------------------------------*/ | |
#include "ADXL345_SPI.h" | |
#include "DigitalInput.h" | |
#include "DigitalOutput.h" | |
#include "NetworkCommunication/UsageReporting.h" | |
#include "SPI.h" | |
const UINT8 ADXL345_SPI::kPowerCtlRegister; | |
const UINT8 ADXL345_SPI::kDataFormatRegister; | |
const UINT8 ADXL345_SPI::kDataRegister; | |
const double ADXL345_SPI::kGsPerLSB; | |
/** | |
* Constructor. | |
* | |
* @param clk The GPIO the clock signal is wired to. | |
* @param mosi The GPIO the MOSI (Master Out Slave In) signal is wired to. | |
* @param miso The GPIO the MISO (Master In Slave Out) signal is wired to. | |
* @param cs The GPIO the CS (Chip Select) signal is wired to. | |
* @param range The range (+ or -) that the accelerometer will measure. | |
*/ | |
ADXL345_SPI::ADXL345_SPI(DigitalOutput &clk, DigitalOutput &mosi, DigitalInput &miso, | |
DigitalOutput &cs, DataFormat_Range range) | |
: m_clk (NULL) | |
, m_mosi (NULL) | |
, m_miso (NULL) | |
, m_cs (NULL) | |
, m_spi (NULL) | |
{ | |
Init(&clk, &mosi, &miso, &cs, range); | |
} | |
/** | |
* Constructor. | |
* | |
* @param clk The GPIO the clock signal is wired to. | |
* @param mosi The GPIO the MOSI (Master Out Slave In) signal is wired to. | |
* @param miso The GPIO the MISO (Master In Slave Out) signal is wired to. | |
* @param cs The GPIO the CS (Chip Select) signal is wired to. | |
* @param range The range (+ or -) that the accelerometer will measure. | |
*/ | |
ADXL345_SPI::ADXL345_SPI(DigitalOutput *clk, DigitalOutput *mosi, DigitalInput *miso, | |
DigitalOutput *cs, DataFormat_Range range) | |
: m_clk (NULL) | |
, m_mosi (NULL) | |
, m_miso (NULL) | |
, m_cs (NULL) | |
, m_spi (NULL) | |
{ | |
Init(clk, mosi, miso, cs, range); | |
} | |
/** | |
* Constructor. | |
* | |
* @param moduleNumber The digital module with the sensor attached. | |
* @param clk The GPIO the clock signal is wired to. | |
* @param mosi The GPIO the MOSI (Master Out Slave In) signal is wired to. | |
* @param miso The GPIO the MISO (Master In Slave Out) signal is wired to. | |
* @param cs The GPIO the CS (Chip Select) signal is wired to. | |
* @param range The range (+ or -) that the accelerometer will measure. | |
*/ | |
ADXL345_SPI::ADXL345_SPI(UINT8 moduleNumber, UINT32 clk, UINT32 mosi, UINT32 miso, | |
UINT32 cs, ADXL345_SPI::DataFormat_Range range) | |
: m_clk (NULL) | |
, m_mosi (NULL) | |
, m_miso (NULL) | |
, m_cs (NULL) | |
, m_spi (NULL) | |
{ | |
m_clk = new DigitalOutput(moduleNumber, clk); | |
m_mosi = new DigitalOutput(moduleNumber, mosi); | |
m_miso = new DigitalInput(moduleNumber, miso); | |
m_cs = new DigitalOutput(moduleNumber, cs); | |
Init(m_clk, m_mosi, m_miso, m_cs, range); | |
} | |
/** | |
* Internal common init function. | |
*/ | |
void ADXL345_SPI::Init(DigitalOutput *clk, DigitalOutput *mosi, DigitalInput *miso, | |
DigitalOutput *cs, DataFormat_Range range) | |
{ | |
if (clk != NULL && mosi != NULL && miso != NULL && cs != NULL) | |
{ | |
m_spi = new SPI(clk, mosi, miso); | |
m_spi->SetMSBFirst(); | |
m_spi->SetSampleDataOnRising(); | |
m_spi->SetSlaveSelect(cs, SPI::kChipSelect, false); | |
m_spi->SetClockActiveLow(); | |
// 8-bit address and 8-bit data | |
m_spi->SetBitsPerWord(16); | |
m_spi->ApplyConfig(); | |
m_spi->ClearReceivedData(); | |
// Turn on the measurements | |
m_spi->Write((kPowerCtlRegister << 8) | kPowerCtl_Measure); | |
m_spi->Read(); | |
// Specify the data format to read | |
m_spi->Write((kDataFormatRegister << 8) | kDataFormat_FullRes | (UINT8)(range & 0x03)); | |
m_spi->Read(); | |
// 8-bit address and 16-bit data | |
m_spi->SetBitsPerWord(24); | |
m_spi->ApplyConfig(); | |
nUsageReporting::report(nUsageReporting::kResourceType_ADXL345, nUsageReporting::kADXL345_SPI); | |
} | |
} | |
/** | |
* Destructor. | |
*/ | |
ADXL345_SPI::~ADXL345_SPI() | |
{ | |
delete m_spi; | |
m_spi = NULL; | |
delete m_cs; | |
m_cs = NULL; | |
delete m_miso; | |
m_miso = NULL; | |
delete m_mosi; | |
m_mosi = NULL; | |
delete m_clk; | |
m_clk = NULL; | |
} | |
/** | |
* Get the acceleration of one axis in Gs. | |
* | |
* @param axis The axis to read from. | |
* @return Acceleration of the ADXL345 in Gs. | |
*/ | |
double ADXL345_SPI::GetAcceleration(ADXL345_SPI::Axes axis) | |
{ | |
INT16 rawAccel = 0; | |
if(m_spi) | |
{ | |
m_spi->Write(((kAddress_Read | kAddress_MultiByte | kDataRegister) + (UINT8)axis) << 16); | |
rawAccel = (UINT16)m_spi->Read(); | |
// Sensor is little endian... swap bytes | |
rawAccel = ((rawAccel >> 8) & 0xFF) | (rawAccel << 8); | |
} | |
return rawAccel * kGsPerLSB; | |
} | |
/** | |
* Get the acceleration of all axes in Gs. | |
* | |
* @return Acceleration measured on all axes of the ADXL345 in Gs. | |
*/ | |
ADXL345_SPI::AllAxes ADXL345_SPI::GetAccelerations() | |
{ | |
AllAxes data = {0.0}; | |
INT16 rawData[3]; | |
if (m_spi) | |
{ | |
SPI::tFrameMode mode; | |
bool activeLow; | |
// Backup original settings. | |
DigitalOutput *cs = m_spi->GetSlaveSelect(&mode, &activeLow); | |
UINT32 bitsPerWord = m_spi->GetBitsPerWord(); | |
// Initialize the chip select to inactive. | |
cs->Set(activeLow); | |
// Control the chip select manually. | |
m_spi->SetSlaveSelect(NULL); | |
// 8-bit address | |
m_spi->SetBitsPerWord(8); | |
m_spi->ApplyConfig(); | |
// Assert chip select. | |
cs->Set(!activeLow); | |
// Select the data address. | |
m_spi->Write(kAddress_Read | kAddress_MultiByte | kDataRegister); | |
m_spi->Read(); | |
// 16-bits for each axis | |
m_spi->SetBitsPerWord(16); | |
m_spi->ApplyConfig(); | |
for (INT32 i=0; i<3; i++) | |
{ | |
// SPI Interface can't read enough data in a single transaction to read all axes at once. | |
rawData[i] = (UINT16)m_spi->Read(true); | |
// Sensor is little endian... swap bytes | |
rawData[i] = ((rawData[i] >> 8) & 0xFF) | (rawData[i] << 8); | |
} | |
// Deassert chip select. | |
cs->Set(activeLow); | |
// Restore original settings. | |
m_spi->SetSlaveSelect(cs, mode, activeLow); | |
m_spi->SetBitsPerWord(bitsPerWord); | |
m_spi->ApplyConfig(); | |
data.XAxis = rawData[0] * kGsPerLSB; | |
data.YAxis = rawData[1] * kGsPerLSB; | |
data.ZAxis = rawData[2] * kGsPerLSB; | |
} | |
return data; | |
} | |