adafruit / Adafruit_ADXL375

Arduino library for ADX375 high-G accelerometer
Other
0 stars 3 forks source link

Check DATA_FORMAT for range saturation #1

Closed ladyada closed 2 years ago

ladyada commented 2 years ago

Hi there,

having just bought one of your wonderful ADXL375 breakout boards, I noticed an error in the datasheet that seems to have trickled down into both your C/C++ Arduino and CircuitPython libraries, and your product page for the breakout board.

The datasheet lists the ADXL375 as having +/- 200 g range, and no range adjustment. In fact, the ADXL375 like AD's related products does have a range adjustment in the DATA_FORMAT register (0x31), and that range is set to +/- 25 g by default on power-up. The datasheet does not mention this and lists two different reset values for the register: 0x00 in the register overview, and 0b0000'1011 in the DATA_FORMAT register detail.

The actual reset value for the register on device power up is 0x00, which corresponds to a +/- 25 g range. The correct value for a +/- 200 g range is 0bxxxx'1x11, which is the default value listed on the DATA_FORMAT register detail.

To test this, simply see if you can get the part to output a value larger than +/- 512 on any channel by tapping the part.

The fix to this is to set the DATA_FORMAT register (0x31) to 0x0f during initialization. This gives you a range of +/- 200 g with an right-aligned, sign-extended integer (int16_t).

The issue seems to be very wide-spread, with many search results for a Google query for "ADXL375 25g" or "ADXL375 512". AD employees have acknowledged the issue in their support forum going back as far as 2017, but so far they don't seem interested in updating their datasheet or issuing an erratum for the incorrect reset value.

I would suggest you place a note on the product page noting the issue since that would have saved me a bunch of time. Ideally, AD should fix their datasheet but since that didn't happen in the last five years I don't think it's worth waiting for them.

Looking at the code, it seems neither your Arduino nor your CircuitPython library set DATA_FORMAT on device initialization, which makes me suspect that maybe both are limited to +/- 25 g. Note that the scale is still the same, so you would only notice if you actually subjected the part to larger accelerations. Here is a forum post of a customer having this issue with the Arduino library:

https://forums.adafruit.com/viewtopic.php?f=8&t=191404&p=926036&hilit=adxl375#p926036

In both cases, initializing DATA_FORMAT to the correct value should fix the issue.

caternuson commented 2 years ago

Quick check to confirm actual POR values for registers. It appears they all agree with the "Reset Value" shown in the Datasheet (Register Map, Table 15).

#include <Wire.h>

#define WIRE Wire 

#define ADXL375_ADDRESS (0x53)

uint8_t read8(uint8_t reg) {
  WIRE.beginTransmission(ADXL375_ADDRESS);
  WIRE.write(reg);
  WIRE.endTransmission();
  WIRE.requestFrom(ADXL375_ADDRESS, 1);
  return WIRE.read();
}

void setup() {
  Serial.begin(9600);
  while(!Serial);
  Serial.println("ADX375 Register Dump.");

  WIRE.begin();

  for (uint8_t r=0x1D; r<=0x39; r++) {
    Serial.print("0x"); Serial.print(r, 16);
    Serial.print(" = 0b"); Serial.println(read8(r), 2);
  }
}

void loop() {
}
ADX375 Register Dump.
0x1D = 0b0
0x1E = 0b0
0x1F = 0b0
0x20 = 0b0
0x21 = 0b0
0x22 = 0b0
0x23 = 0b0
0x24 = 0b0
0x25 = 0b0
0x26 = 0b0
0x27 = 0b0
0x28 = 0b0
0x29 = 0b0
0x2A = 0b0
0x2B = 0b0
0x2C = 0b1010
0x2D = 0b0
0x2E = 0b0
0x2F = 0b0
0x30 = 0b10
0x31 = 0b0
0x32 = 0b0
0x33 = 0b0
0x34 = 0b0
0x35 = 0b0
0x36 = 0b0
0x37 = 0b0
0x38 = 0b0
0x39 = 0b0
caternuson commented 2 years ago

Simple sketch to latch max accel value for Z axis.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL375.h>

float az, maxz = 0;

Adafruit_ADXL375 accel = Adafruit_ADXL375(12345);

void setup(void)
{
  Serial.begin(115200);
  while (!Serial);
  Serial.println("ADXL375 Max Accelo Test"); Serial.println("");

  if(!accel.begin())
  {
    Serial.println("Ooops, no ADXL375 detected ... Check your wiring!");
    while(1);
  }
}

void loop(void)
{
  sensors_event_t event;
  accel.getEvent(&event);

  az = event.acceleration.z;
  if (az > maxz) maxz = az;

  Serial.println(maxz);
}

Run that and then slam sensor into table top several times until value saturates: Screenshot from 2022-07-10 08-58-30

245.55 / 9.83 = 25g

This seems to confirm the behavior described above. The sensor range is actually +/-25g with the reset value of 0b00000000 for register 0x31 (DATA_FORMAT).

caternuson commented 2 years ago

Same sketch with quick update to force DATA_FORMAT register value to have D4, D3, D1, and D0 be as shown in datasheet:

adxl_df

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL375.h>

float az, maxz = 0;

Adafruit_ADXL375 accel = Adafruit_ADXL375(12345);

void setup(void)
{
  Serial.begin(115200);
  while (!Serial);
  Serial.println("ADXL375 Max Accelo Test"); Serial.println("");

  if(!accel.begin())
  {
    Serial.println("Ooops, no ADXL375 detected ... Check your wiring!");
    while(1);
  }

  accel.writeRegister(0x31, 0b00001011);
}

void loop(void)
{
  sensors_event_t event;
  accel.getEvent(&event);

  az = event.acceleration.z;
  if (az > maxz) maxz = az;

  Serial.println(maxz);
}

Now get higher values: Screenshot from 2022-07-10 09-21-03

but still not getting the full 200g (~=1966 m/s2) range value. But the very aggressive slamming of sensor on desk seems to be causing intermittent breaks in the I2C comms, which then cause the values to stop reporting back (sensor in bad state).

Posted in forums asking original poster to try this same modification: https://forums.adafruit.com/viewtopic.php?f=8&t=191404&p=931953#p931953 Hoping their test setup is better suited for generating the high G values.

jaseg commented 2 years ago

(original reporter here) The test setup I used for these high G forces is the following: I used a battery-powered ESP32 board hooked up to the ADXL375 breakout board. I put both in a zip-lock plastic bag, which I then stuck to the inside of my washing machine using some gaffer's tape. My washing machine has a spin cycle setting that does not use any water, and I used that to get > 200 g at 800 rpm. With this setup the sensor reliably saturated.

caternuson commented 2 years ago

@jaseg Can you try again with a value of 0xb sent to the 0x31 register instead of 0xf as mentioned here:

The fix to this is to set the DATA_FORMAT register (0x31) to 0x0f during initialization. This gives you a range of +/- 200 g with an right-aligned, sign-extended integer (int16_t).

With 0xf the Justify Bit will also be set which should be left justified, not right. It seems like the important thing is to insure D4, D3, D1, and D0 are as shown. And leave the Justify Bit as the 0 default.

just

jaseg commented 2 years ago

Hi @caternuson, I've tested it, and it works as expected. Here's a screenshot of two accelerometers,, your ADXL375 on CH0-2 (the top three traces) and an ST H3LIS100 eval board on CH3-5 (the bottom three traces). Screenshot 2022-07-28 at 15-02-55 Data viewer

caternuson commented 2 years ago

Thanks. Keep an eye on PR #2. Hopefully that'll fix this once it gets reviewed and merged.

caternuson commented 2 years ago

Closing. Should be resolved by #2.