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) :
1 Answer 1
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();
-
Heh. Your answer came in about when my comment did.timemage– timemage2022年06月19日 19:01:02 +00:00Commented 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.Maxxie– Maxxie2022年06月20日 08:11:38 +00:00Commented Jun 20, 2022 at 8:11
-
@Maxxie: See expanded answer.Edgar Bonet– Edgar Bonet2022年06月20日 14:56:45 +00:00Commented Jun 20, 2022 at 14:56
xAxisFinal = xAxisH << 4 | xAxisL;
I think you mean<< 8
.