3

I am using ADXL373Z accelerometer with Arduino Uno for a project.

When I run the code, I am getting incorrect values which are probably not even acceleration data. I am thinking it might be a wiring problem, I attached circuit diagram below. This is my first Arduino project, and I couldn't find any other applications with the sensor I am using so any help would be much appreciated. Thanks in advance.

Datasheet for sensor : https://www.analog.com/media/en/technical-documentation/data-sheets/adxl373.pdf

Code ( for x-axis data only) :

// ADXL373 Accelerometer Test
#include <Wire.h>
/* -------- REGISTERS -------- */
#define ADDRESS_ADXL373 0x53 // sensor adress (assumes MISO pin high)
#define ADDRESS_POWER_CTL 0x3F // power control
#define ADDRESS_MEASURE 0x0E // measurement control
#define ADDRESS_TIMING 0x3D // output data rate and extarnal timing triggers
#define ADDRESS_XDATA_H 0x08 // x-axis acceleration data [11:4]
#define ADDRESS_XDATA_L 0x09 // x-axis acceleration data [3:0]
#define ADDRESS_YDATA_H 0x0A // y-axis acceleration data [11:4]
#define ADDRESS_YDATA_L 0x0B // y-axis acceleration data [3:0]
#define ADDRESS_ZDATA_H 0x0C // z-axis acceleration data [11:4]
#define ADDRESS_ZDATA_L 0x0D // z-axis acceleration data [3:0]
/* -------- REGISTERS -------- */
#define SCALE_FACTOR 0.2f // 200 mg per LSB scaling factor
#define GRAVITY_EARTH 9.80665f // gravity of earth in m/s^2
void setup() {
 Serial.begin(115200);
 while(!Serial);
 Serial.println("ADXL373 Accelerometer Test");
 Wire.begin();
 Wire.beginTransmission(ADDRESS_ADXL373);
 Wire.write(ADDRESS_POWER_CTL);
 Wire.write(0x03); // activate full bandwith measurement mode
 Wire.endTransmission(true);
 delay(50);
 Wire.beginTransmission(ADDRESS_ADXL373);
 Wire.write(ADDRESS_MEASURE);
 Wire.write(0x04); // set output signal bandwith to 2560 Hz
 Wire.endTransmission(true);
 delay(50);
 Wire.beginTransmission(ADDRESS_ADXL373);
 Wire.write(ADDRESS_TIMING);
 Wire.write(0x80); // set output data rate to 5120 Hz
 Wire.endTransmission(true);
 delay(50);
}
void loop() {
 byte xAxisH, xAxisL;
 Wire.beginTransmission(ADDRESS_ADXL373);
 Wire.write(ADDRESS_XDATA_H);
 Wire.endTransmission(false);
 Wire.requestFrom(ADDRESS_ADXL373, 1, true);
 xAxisH = Wire.read();
 Wire.beginTransmission(ADDRESS_ADXL373);
 Wire.write(ADDRESS_XDATA_L);
 Wire.endTransmission(false);
 Wire.requestFrom(ADDRESS_ADXL373, 1, true);
 xAxisL = Wire.read();
 int16_t xAxisFinal;
 xAxisFinal = (uint16_t) xAxisH << 8 | xAxisL; // bit shift and combine two components
 xAxisFinal = xAxisFinal >> 4; // 12-bit resolution
 float xAccel;
 xAccel = xAxisFinal * SCALE_FACTOR * GRAVITY_EARTH;
 Serial.print("Xa = "); Serial.println(xAccel);
 delay(200);
}

Circuit Diagram :

Circuit Diagram

Results from Serial Monitor (in m/s^2) :

Serial Monitor

asked Jun 19, 2022 at 17:15
1
  • 1
    xAxisFinal = xAxisH << 4 | xAxisL; I think you mean << 8. Commented Jun 19, 2022 at 18:58

1 Answer 1

5

According to the datasheet, the 12 bits of the X acceleration are stored into the registers XDATA_H and XDATA_L as follows:

XDATA_H: b11b10b9 b8 b7 b6 b5 b4
XDATA_L: b3 b2 b1 b0 x x x x

where x means "reserved".

Now, there are two issues with this code:

xAxisFinal = xAxisH << 4 | xAxisL; // bit shift 12-bit output data

The first issue is that, by shifting xAxisH by four places, the bits b7–b4 end up in the same positions as the bits b3–b0 in xAxisL. Then, when those values are combined with |, the bit b7 gets mixed with b3, b6 with b2, etc. If you really want to shift xAxisH left by four places, you should also shift xAxisL right by four places.

The second issue is that the x data is a signed number represented as two's complement, and the sign bit (b11) ends up in the wrong place. For example, if the measured value is −16 (XDATA_H:XDATA_L = 0xff:0x00), you end up reading 4980 (0x0ff0). In order to avoid this issue you could sign extend the 12-bit number to 16 bits.

I would suggest, though, a completely different approach. The number is left justified in the sensor registers, so just keep it like this:

xAxisFinal = (uint16_t) xAxisH << 8 | xAxisL;

The intermediate cast to uint16_t is here to avoid an undefined behavior, the final result is signed. If there is some risk that the reserved bits are non-zero (the datasheet is not very clear in this respect), you could

xAxisFinal &= 0xfff0; // clear last 4 bits

Note that now the unit of the acceleration is 1/16 of the resolution of the sensor, and all values you get are multiples of 16. I don't expect this to be an issue. If you really want to use the sensor resolution as your unit, you could now shift xAxisFinal four places to the right, which would automatically perform the sign extension.


Edit: Addressing the edited code from the OP:

I modified the code according to your suggestions. But I am still getting incorrect values from serial monitor.

What I see in your post is very small values, around ±3 LSBs of the sensor. This could very well be sensor noise. But then, there is the occasional larger value. Interestingly, those larger values seem to be very close to ±16 LSBs, hinting at some kind of communication problem.

I guess the answer is in this warning from the sensor's datasheet:

Always read acceleration data using multibyte transfers to ensure that a concurrent and complete set of x, y, and z acceleration data is read.

Imagine the sensor is outputting only noise, and the noise fluctuates between −1 and +1 LSB. What you expect then is:

value XDATA_H XDATA_L
 −1 11111111 11110000
 +1 00000000 00010000

If you read XDATA_H and XDATA_L in two different transactions, you may well read 0b11111111 for XDATA_H (as the sensor is reading −1), then read 00010000 for XDATA_L (as it is getting +1). When you combine these two readings together, you get

value XDATA_H XDATA_L
 −15 11111111 00010000

I suggest you follow the recommendation from the datasheet and read both registers in one go:

Wire.beginTransmission(ADDRESS_ADXL373);
Wire.write(ADDRESS_XDATA_H);
Wire.endTransmission(false);
Wire.requestFrom(ADDRESS_ADXL373, 2, true);
xAxisH = Wire.read();
xAxisL = Wire.read();
answered Jun 19, 2022 at 18:58
3
  • Heh. Your answer came in about when my comment did. Commented Jun 19, 2022 at 19:01
  • Thanks, I modified the code according to your suggestions. But I am still getting incorrect values from serial monitor. I edited the code and results in my post. If you have any other suggestions I would appreciate it. Commented Jun 20, 2022 at 8:11
  • @Maxxie: See expanded answer. Commented Jun 20, 2022 at 14:56

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.