I'm using a Teensy 3.2 to read data from an ADXL375 using SPI. In general the communication is going just fine and I can activate settings etc. However, when I try to read X, Y or Z data it seems like some part of the measurement values are missing.
I'm performing measurements with the ADXL375 and writing the LSB values straight to an SD card, so no conversion to g or anything like that. The accelerometer range goes to +/- 200g, so that should give a max LSB value of about 200*20(scale factor) = +/- 4000 LSB.
During some tests I was swinging the accelerometer with my hand, and tapping it directly with a pen, which gives a momentary high impact. The swinging values are represented well and look credible to me, however the pen tapping values seem to be cut off at precisely 511 LSB, see graphs. That seems incorrect. So why is that?
N.B. The range of the ADXL is fixed to 200 g, so no choice to be made there.
My thinking is that something is going wrong with the conversion of the two ADXL registers (two's complement) to form a single number. This is the conversion I'm doing (i.e. I'm reading out the FIFO in one go):
void ADXL375::saveFIFO(){
int fifo_index;
int16_t x, y, z;
fifo_index=0;
// readFrom(DEVICE,ADXL375_INT_SOURCE_REG,1,buff);
for(int i=0;i<32;i++){
multiByteReadSPI(ADXL375_DATAX0_REG, 6, bufferSPI); //read the acceleration data from the ADXL375
x = (((uint16_t)bufferSPI[1]) << 8) | (uint16_t)bufferSPI[0];
y = (((uint16_t)bufferSPI[3]) << 8) | (uint16_t)bufferSPI[2];
z = (((uint16_t)bufferSPI[5]) << 8) | (uint16_t)bufferSPI[4];
// Serial.print(bufferSPI[5], BIN); Serial.println(bufferSPI[4], BIN); // z
// Serial.print(bufferSPI[1], BIN); Serial.print(","); Serial.println(bufferSPI[0], BIN); // x
if (x & 0x8000){ // Check if the binary number is negative, by checking whether left most bit is 1 or not.
// If negative, then perform not operation and add one to get magnitude
x = ~x + 1;
x = - x;
}
if (y & 0x8000){ // Check if the binary number is negative, by checking whether left most bit is 1 or not.
// If negative, then perform not operation and add one to get magnitude
y = ~y + 1;
y = - y;
}
if (z & 0x8000){ // Check if the binary number is negative, by checking whether left most bit is 1 or not.
// If negative, then perform not operation and add one to get magnitude
z = ~z + 1;
z = - z;
}
lastFiFo[fifo_index] = newistFiFo[fifo_index];
newistFiFo[fifo_index] = x;
fifo_index++;
lastFiFo[fifo_index] = newistFiFo[fifo_index];
newistFiFo[fifo_index] = y;
fifo_index++;
lastFiFo[fifo_index] = newistFiFo[fifo_index];
newistFiFo[fifo_index] = z;
fifo_index++;
// debugPrint(x); // debugPrintln(", Saving fifo");
// x = (((int16_t)bufferSPI[1]) << 8) | bufferSPI[0];
// y = (((int16_t)bufferSPI[3])<< 8) | bufferSPI[2];
// z = (((int16_t)bufferSPI[5]) << 8) | bufferSPI[4];
// scaleXYZ(&x,&y,&z);
}
}
This is the SPI Multibyte Read function I'm using:
void ADXL375::multiByteReadSPI(uint8_t regAddr, uint8_t numberOfBytes, uint8_t *dataBuffer){
SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE3));
digitalWrite(_chipSelectPin,LOW);
uint8_t readMBaddr;
if (numberOfBytes > 1){ // for an actual multibyte read
readMBaddr = 0b11000000 | regAddr; // From left to right: read (1), yes multibyte (1), and then a bunch of zeros
}
else{ // for single byte read
readMBaddr = 0b10000000 | regAddr; // From left to right: read (1), not multibyte (0), and then a bunch of zeros
}
SPI.transfer(readMBaddr);
for (uint8_t k = 0; k < numberOfBytes; k++ ){
dataBuffer[k] = SPI.transfer(SPI_DUMMY_VALUE);
}
digitalWrite(_chipSelectPin,HIGH);
SPI.endTransaction();
}
I also had a look whether the SPI transfer are okay. The image shows one multibyte read, consisting of a command byte on the far left, and then 6 read bytes after that. Nothing out of the ordinary there.