blob: d97d33cde47fdae93661f77ab691b3395dcd6d2a [file] [log] [blame]
/*----------------------------------------------------------------------------*/
/* 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;
}