As a preface, I'm new to Arduino and electronic communication. I'm in the initial stages of an Arduino based accelerometer setup to record high acceleration spikes from impacts. I'm communicating with a single ADXL373 accelerometer to start via SPI.
I've been stuck for a while on the SPI code in that it only will read 0 from all 3 axis. The issue I expect remains with how I'm coding my reads/writes. Does anything standout as egregiously wrong in how I'm executing them?
ADXL373 Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/adxl373.pdf
// ADXL373 400g Accelerometer sensor connected to Arduino 2560 Mega Board
// V5: pin 3.3V
// GND: pin GND
// MOSI: pin 51
// MISO: pin 50
// SCLK: pin 52
// CS: pin 53
// the sensor communicates using SPI, so include the library:
#include <SPI.h>
const int CS = 53; //Chip Select (Arduino Mega Pin 53)
/////////////////////////////////////////////////////////////////////////////////
///////////////////////////// Register Addresses ////////////////////////////////
byte XDATA_H = 0x08; // (0b00001000) X Data Register, High 8 MSB
byte XDATA_L = 0x09; // (0b00001001) X Data Register, Low 4 MSB
byte YDATA_H = 0x0A; // (0b00001010) Y Data Register, High 8 MSB
byte YDATA_L = 0x0B; // (0b00001011) Y Data Register, Low 4 MSB
byte ZDATA_H = 0x0C; // (0b00001100) Z Data Register, High 8 MSB
byte ZDATA_L = 0x0D; // (0b00001101) Z Data Register, Low 4 MSB
byte OFFSET_X = 0x20; // X Data Offset Register, Lower 4 bits
byte OFFSET_Y = 0x21; // Y Data Offset Register, Lower 4 bits
byte OFFSET_Z = 0x22; // Z Data Offset Register, Lower 4 bits
byte TIME_CTRL = 0x3D; // (0b00111101) Timing Control Register -> Select ODR (0b10000000) for 5120 Hz
byte MEASR_CTRL = 0x3E; // (0b00111110) Measurement Control -> Bandwidth set (0b00000100) for 2560 Hz
byte POWER_CTRL = 0x3F; // (0b00111111) Power Control Register -> Op. Mode and HPF off (0b00000111)
const byte WRITE = 0b11111110; // Reads with a 1, high
const byte READ = 0b00000001; // Writes with a 0, low
////////////////////////////////////////////////////////////////////////////////
// Establish variables to identify x, y, and z axis accelerations
int x_axis = 1;
int y_axis = 2;
int z_axis = 3;
void setup()
{
SPI.begin(); // Initialize SPI
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST); // Data for the device is sent MSB first, RW is last bit
Serial.begin(115200); // Establish a serial connection to display data through terminal
pinMode(CS, OUTPUT); // Set CS Pin Direction
digitalWrite(CS, LOW);
writeRegister(MEASR_CTRL, 0b00000100); // Set Measurement Mode to 2560Hz bandwidth (0x04)
writeRegister(POWER_CTRL, 0b00000111); // Set full bandwidth measurement mode, HPF disabled (0x07)
writeRegister(TIME_CTRL, 0b10000000); // Set ODR to 5120 Hz
digitalWrite(CS, HIGH);
delay(1);
}
void loop()
{
Serial.print(" x = ");
Serial.print(getValue(x_axis));
Serial.print(" y = ");
Serial.print(getValue(y_axis));
Serial.print(" z = ");
Serial.println(getValue(z_axis));
delay(0.2);
}
int getValue(int axis)
{
int AccelData = 0;
int Offset = 0;
int high, low;
if (axis == 1)
{
high = readRegister(XDATA_H);
low = readRegister(XDATA_L);
}
else if (axis == 2)
{
high = readRegister(YDATA_H);
low = readRegister(YDATA_L);
}
else if (axis == 3)
{
high = readRegister(ZDATA_H);
low = readRegister(ZDATA_L);
}
AccelData = (high << 4) | (low >> 4); // Merge 8 bits from 'high' with upper 4 of 'low'
AccelData = (AccelData - Offset)*200; // (Reading-Offset)*ScaleFactor --> 200mg/LSB for ADXL373
return AccelData;
}
byte readRegister(byte thisRegister)
{
byte result = 0; // predeclare result to return
// ADXL373 expects the register address in the upper 7 bits of the transmitted byte
// Shift the register bits left by 1 to apply READ bit:
thisRegister = thisRegister << 1;
byte dataToSend = thisRegister | READ; // Combine register address with READ command
digitalWrite(CS,LOW); //Set the Chip Select pin low to start an SPI packet
result = SPI.transfer(dataToSend); // Tell device to read register and save response
digitalWrite(CS, HIGH); //Set CS high to close communcation
return result;
}
void writeRegister(byte thisRegister, byte thisValue)
{
// ADXL373 expects the register address in the upper 7 bits of the transmitted byte
// Shift the register bits left by 1 bit to apply WRITE bit:
thisRegister = thisRegister << 1;
byte dataWrite = thisRegister & WRITE; // Combine the register address and WRITE command
byte dataToSend = ((dataWrite << 8) | thisValue);
digitalWrite(CS,LOW); //Set CS pin low to signal SPI packet start
SPI.transfer(dataToSend); //Transfer the register address, RW, and desired register value over SPI
digitalWrite(CS,HIGH); //Set the Chip Select pin high to signal the end of an SPI packet.
}
Any guidance is greatly appreciated.
You need to use two SPI.transfer() statements, like in the example in the Arduino SPI Tutorial for a Barometric Pressure Sensor. See lines 160 - 164:
158 // send the device the register you want to read:
159
160 SPI.transfer(dataToSend);
161
162 // send a value of 0 to read the first byte returned:
163
164 result = SPI.transfer(0x00);
The first statement tells the sensor which register you want to read. The second statement returns the data (the sensor in this example does not work exactly like your ADXL, so I don't think you have to send a 0x00 to start a read, but the point is the same).
The description for SPI.transfer() says it performs a "simultaneous send and receive", but that can also be used as a send or receive.