user85550: 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 :

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


user7508: 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:   b₁₁b₁₀b₉ b₈ b₇ b₆ b₅ b₄
XDATA_L:   b₃ b₂ b₁ b₀ 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
b₇–b₄ end up in the same positions as the bits b₃–b₀ in xAxisL. Then,
when those values are combined with |, the bit b₇ gets mixed with b₃,
b₆ with b₂, 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 (b₁₁) 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();


85550: <p>I am using <a href="https://eu.mouser.com/ProductDetail/Analog-Devices/EVAL-ADXL373Z?qs=QNEnbhJQKva6ENie%252BWXLsQ%3D%3D" rel="nofollow noreferrer">ADXL373Z</a> accelerometer with Arduino Uno for a project.</p>
<p>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.</p>
<p>Datasheet for sensor : <a href="https://www.analog.com/media/en/technical-documentation/data-sheets/adxl373.pdf" rel="nofollow noreferrer">https://www.analog.com/media/en/technical-documentation/data-sheets/adxl373.pdf</a></p>
<p>Code ( for x-axis data only) :</p>
<pre><code>// ADXL373 Accelerometer Test

#include &lt;Wire.h&gt;

/* -------- 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(&quot;ADXL373 Accelerometer Test&quot;);
  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 &lt;&lt; 8 | xAxisL; // bit shift and combine two components
  xAxisFinal = xAxisFinal &gt;&gt; 4; // 12-bit resolution
  float xAccel;
  xAccel = xAxisFinal * SCALE_FACTOR * GRAVITY_EARTH;
  Serial.print(&quot;Xa = &quot;); Serial.println(xAccel);
  delay(200);
}
</code></pre>
<p>Circuit Diagram :</p>
<p><a href="https://i.stack.imgur.com/qFgje.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/qFgje.png" alt="Circuit Diagram" /></a></p>
<p>Results from Serial Monitor (in m/s^2) :</p>
<p><a href="https://i.stack.imgur.com/Gnn1p.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Gnn1p.png" alt="Serial Monitor" /></a></p>
 7508: <p>According to the datasheet, the 12 bits of the X acceleration are stored
into the registers <code>XDATA_H</code> and <code>XDATA_L</code> as follows:</p>
<pre><code>XDATA_H:   b₁₁b₁₀b₉ b₈ b₇ b₆ b₅ b₄
XDATA_L:   b₃ b₂ b₁ b₀ x  x  x  x
</code></pre>
<p>where <code>x</code> means “reserved”.</p>
<p>Now, there are two issues with this code:</p>
<pre class="lang-cpp prettyprint-override"><code>xAxisFinal = xAxisH &lt;&lt; 4 | xAxisL; // bit shift 12-bit output data
</code></pre>
<p>The first issue is that, by shifting <code>xAxisH</code> by four places, the bits
b₇–b₄ end up in the same positions as the bits b₃–b₀ in <code>xAxisL</code>. Then,
when those values are combined with <code>|</code>, the bit b₇ gets mixed with b₃,
b₆ with b₂, etc. If you really want to shift <code>xAxisH</code> left by four
places, you should also shift <code>xAxisL</code> right by four places.</p>
<p>The second issue is that the x data is a signed number represented as
two's complement, and the sign bit (b₁₁) 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
<a href="https://en.wikipedia.org/wiki/Sign_extension" rel="nofollow noreferrer">sign extend</a> the 12-bit number to 16 bits.</p>
<p>I would suggest, though, a completely different approach. The number is
left justified in the sensor registers, so just keep it like this:</p>
<pre class="lang-cpp prettyprint-override"><code>xAxisFinal = (uint16_t) xAxisH &lt;&lt; 8 | xAxisL;
</code></pre>
<p>The intermediate cast to <code>uint16_t</code> 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</p>
<pre class="lang-cpp prettyprint-override"><code>xAxisFinal &amp;= 0xfff0;  // clear last 4 bits
</code></pre>
<p>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 <code>xAxisFinal</code> four places to the right,
which would automatically perform the sign extension.</p>
<hr />
<p><strong>Edit</strong>: Addressing the edited code from the OP:</p>
<blockquote>
<p>I modified the code according to your suggestions. But I am still
getting incorrect values from serial monitor.</p>
</blockquote>
<p>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.</p>
<p>I guess the answer is in this warning from the sensor's datasheet:</p>
<blockquote>
<p>Always read acceleration data using multibyte transfers to ensure that
a concurrent and complete set of x, y, and z acceleration data is
read.</p>
</blockquote>
<p>Imagine the sensor is outputting only noise, and the noise fluctuates
between −1 and +1 LSB. What you expect then is:</p>
<pre><code>value  XDATA_H   XDATA_L
  −1   11111111  11110000
  +1   00000000  00010000
</code></pre>
<p>If you read <code>XDATA_H</code> and <code>XDATA_L</code> in two different transactions, you
may well read 0b11111111 for <code>XDATA_H</code> (as the sensor is reading  −1),
then read <code>00010000</code> for <code>XDATA_L</code> (as it is getting +1). When you
combine these two readings together, you get</p>
<pre><code>value  XDATA_H   XDATA_L
 −15   11111111  00010000
</code></pre>
<p>I suggest you follow the recommendation from the datasheet and read both
registers in one go:</p>
<pre class="lang-cpp prettyprint-override"><code>Wire.beginTransmission(ADDRESS_ADXL373);
Wire.write(ADDRESS_XDATA_H);
Wire.endTransmission(false);
Wire.requestFrom(ADDRESS_ADXL373, 2, true);
xAxisH = Wire.read();
xAxisL = Wire.read();
</code></pre>
