0

I am working on ADXL375 and interfacing it with Arduino UNO using I2C protocol. I get the values of X, Y, Z axis as mentioned in the datasheet, i.e., when placed horizontally I get x=0g, y=0g, z=1g(approx. calibrated). I have enabled trigger mode and mapped interrupt to INT2. My Shock Threshold is set to 0x28 = 31.2g.

When I tap the module on table, interrupt triggers even though the threshold is 31.2g, but the values I get are unchanged (around x= 0, y=0, z=1). How to get the values of X, Y, Z during the shock? When I tilt the module, I can see the values change accordingly. but these values hardly go beyond 3g. what am I doing wrong?

Here is my code setup for registers:

  /*START Set Shock Threshold*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x1D); //Shock Duration Register Address
  Wire.write(0x28); //Scale Factor is 780mg/LSB, hence 0x28 = 31.2g
  Wire.endTransmission();
  /*END Set Shock Threshold*/

  /*START Set DUR Thresh_SHOCK*/
  //Used for Double Shock Detection Only**
  Wire.beginTransmission(Device_Address);
  Wire.write(0x21); //Shock Duration Register Address
  Wire.write(0x50); //Scale Factor is 625us/LSB, hence 0x50 = 50ms
  Wire.endTransmission();
  /*END Set DUR Thresh_SHOCK*/

  /*START Set Latency*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x22); //Latent Register Address
  Wire.write(0x20); //Scale Factor is 1.25ms/LSB, hence 0x20 = 400ms
  Wire.endTransmission();
  /*END Set Latency*/

  /*START Set Shock Window to 300ms*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x23); //Window Register Address
  Wire.write(0xF0); //Scale Factor is 1.25ms/LSB, hence 0xF0 = 300ms
  Wire.endTransmission();
  /*END Set Shock Window to 300ms*/

  /*START Enable XYZ-Axis Shock Detection START*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x2A); //SHOCK_AXES Register
  Wire.write(0x07); //Enable SHOCK_X, SHOCK_Y, SHOCK_Z
  Wire.endTransmission();
  /*END Enable XYZ-Axis Shock Detection END*/

  /*START Set Out-Data-Rate(ODR) to 3200Hz*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x2C); //BW_RATE Register Address
  Wire.write(0x0F); //3200 Hz Output Data Rate
  Wire.endTransmission();
  /*END Set Out-Data-Rate(ODR) to 3200Hz */

  /*START Enable Single Shock Interrupt*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x2E); //INT_Enable Register Address
  Wire.write(0x40); //Enable single Shock Int
  Wire.endTransmission();
  /*END Enable Single Shock Interrupt*/
 
  /*START Assign Single Shock Interrupt*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x2F); //INT_Map Register Address
  Wire.write(0x40); //Assign single Shock Int
  Wire.endTransmission();
  /*END Assign Single Shock Interrupt*/  
  
  /*START Data Format*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x31); //DATA_FORMAT Reg
  Wire.write(0x0B); 
  Wire.endTransmission();
  /*END Data Format*/

  /*START Enable Trigger Mode*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x38); //FIFO_CTL Register Address
  Wire.write(0xEA); //Enable Trigger Mode, set samples = 10
  Wire.endTransmission();
  /*END Enable Trigger Mode*/

  /*START Offset Calibration*/
  // Scale Factor = 0.196g/MSB
  Wire.beginTransmission(Device_Address);
  Wire.write(0x1E); //OFSX Address
  Wire.write(0xFA); //OFSX offset 
  Wire.endTransmission();

  Wire.beginTransmission(Device_Address);
  Wire.write(0x1F); //OFSY Address
  Wire.write(0xFB); //OFSY offset
  Wire.endTransmission();

  Wire.beginTransmission(Device_Address);
  Wire.write(0x20); //OFSZ Address
  Wire.write(0xFF); //OFSZ offset
  Wire.endTransmission();
  /*END Offset Calibration*/

  /*Start Enable Measuring*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x2D); //POWER_CTL Register
  Wire.write(0x08); //Enable Measuring
  Wire.endTransmission();
  /*END Enable Measuring*/
  
  /*Attach Interrupt to Digital pin 2*/
  attachInterrupt(digitalPinToInterrupt(2), ISR_Func, RISING);

Here is how I am receiving the values:

int16_t data_x = 0, data_x_lsb = 0; 
int16_t data_y = 0, data_y_lsb = 0; 
int16_t data_z = 0, data_z_lsb = 0;

Wire.beginTransmission(Device_Address);
Wire.write(0x32); //read LSB
Wire.endTransmission();

Wire.requestFrom(Device_Address, 6);   
while (Wire.available()) {
   data_x_lsb = Wire.read();
   data_x = Wire.read();
   data_y_lsb = Wire.read();
   data_y = Wire.read();
   data_z_lsb = Wire.read();
   data_z = Wire.read();

    data_x = (data_x << 8) | (data_x_lsb);
    data_y = (data_y << 8) | (data_y_lsb);
    data_z = (data_z << 8) | (data_z_lsb);
}

data_x = (double)data_x*49/1000
data_y = (double)data_y*49/1000
data_z = (double)data_z*49/1000

Sample Output:

14:36:51.120 -> -0.072  -0.067  0.977
14:36:51.221 -> -0.087  -0.096  0.949
14:36:51.325 -> 0.010   -0.191  0.988
14:36:51.427 -> -0.062  -0.162  1.071
14:36:51.536 -> -0.010  -0.088  1.071
14:36:51.614 -> -0.015  -0.037  1.052
14:36:51.725 -> -0.022  -0.047  1.044
14:36:51.837 -> 0.062   -0.043  1.012
14:36:52.025 -> FIFO STATUS REG: A0
14:36:52.025 -> Shock Occured
14:36:52.062 -> ACT STATUS SHOCK REG: 1
14:36:52.062 -> INT_SOURCE: C3
14:36:52.137 -> 0.055   -0.081  0.997
14:36:52.252 -> 0.024   0.031   1.033
14:36:52.354 -> 0.011   -0.072  1.079
14:36:52.455 -> 0.022   -0.031  0.973
14:36:52.547 -> 0.014   -0.042  1.041
14:36:52.654 -> -0.062  -0.036  1.018
14:36:52.770 -> -0.080  -0.003  1.003
14:36:52.880 -> -0.081  -0.118  1.084
14:36:52.972 -> -0.080  -0.039  1.046
14:36:53.079 -> -0.109  -0.016  0

According to datasheet, it says that we need to reset trigger mode after each triggering event. I tried doing that but to no avail.

I am doing multibyte read using I2C and implemented moving average filter with the span of 4.

Diracx
  • 61
  • 10
  • 1
    Shock is usualy very short, it is unlikely to see it with 100 ms period. Try lowering the threshold and make a softer shock, like hold the board in your hand and shake it. – Flexz Jan 24 '23 at 12:57
  • 3
    If you intend to use math libraries and floating point for the calculations, then Arduino Uno is a bad choice for it. Use a modern 32 bit MCU instead, with FPU on-board. – Lundin Jan 24 '23 at 12:58
  • 1
    Supplementing @Lundin: Even better: Avoid floating point entirely, if possible. A typical approach for is doing calculation in sub-units (e.g. Cents or tenth of instead of Euros, mm or μm instead of m or mm, etc). – Aconcagua Jan 24 '23 at 13:09
  • Normal driving and braking is 0.1g. Your numbers don't seem low. – stark Jan 24 '23 at 13:20
  • @Lundin, My variables are of type int16_t. I am processing them in that data type only. The printed values are just typecasted and adjusted according to the sensitivity given in the datasheet. I appreciate your opinion; I'll try with different Microcontroller. – Diracx Jan 24 '23 at 13:21
  • @stark, the datasheet of ADXL375 says that in horizontal position, I should get X=0g, Y=0g, Z=1g which is approximately correct. and I am tapping the module in z-direction – Diracx Jan 24 '23 at 13:24
  • @Flexz, my application has specific need of threshold. So if I decrease the threshold, shock is registered even at lower shock waves, which is unwanted – Diracx Jan 24 '23 at 13:26
  • 1
    Your problem seems more related to Physics than programming. For example, mechanical damping would flatten and widen the signal giving you time to detect and process it. – stark Jan 24 '23 at 13:32
  • I think @Flexz nailed it. The shock happens so quickly, reading the values after is too late. You either trust the chip or you don't. – pmacfarlane Jan 25 '23 at 00:53
  • 1
    @pmacfarlane, Yes, I agree with you and Flexz, but the accelerometer stores the shock values in its FIFOs (There can be up to 32 FIFOs, I am using 10 here) so we just need to keep reading the FIFO to get the shock values. I have solved the problem please let me know it makes sense. – Diracx Jan 25 '23 at 10:55
  • @Diracx Yes I think your answer makes sense. – pmacfarlane Jan 25 '23 at 12:17
  • @Lundin, For the above question do you think this is the efficient way of handling I2C register setup. I have repeated code with just changing register addresses and values to be written in them. Can you please suggest how I can avoid repeating code but achieving same result? – Diracx Apr 25 '23 at 06:15
  • @Diracx Loops and arrays? – Lundin Apr 25 '23 at 06:44
  • @Lundin , Okay I can try that – Diracx Apr 25 '23 at 07:49

1 Answers1

1

Update: I am able to get the output values. All I had to do was resetting the trigger mode by entering into bypass mode in the initial setup. and resetting again after each shock event.

This is the code section I added in my setup and calling after each shock event.

  /*START Disable Trigger Mode/enable Bypass Mode*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x38); //FIFO_CTL Register Address
  Wire.write(0x2A); //Disable Trigger Mode, set samples = 10
  Wire.endTransmission();
  /*END Disable Trigger Mode/enable Bypass Mode*/

  /*START Enable Trigger Mode*/
  Wire.beginTransmission(Device_Address);
  Wire.write(0x38); //FIFO_CTL Register Address
  Wire.write(0xEA); //Enable Trigger Mode, set samples = 10
  Wire.endTransmission();
  /*END Enable Trigger Mode*/

As for the values remaining constant even after shock, I was resetting trigger mode after reading only the output FIFO [0]), when there are 10 FIFOs to collect data, as I have configured in register 0x38(samples = 10). So, the shock values were being stored in the later stages of FIFOs and not in FIFO [0]. Reading FIFO more than 10 times after shock event and then resetting the trigger mode solved the problem.

Sample Output(X Y Z in g):

0.000   0.000   0.196
-0.490  0.098   0.000
0.098   -0.392  0.980
Shock Occured
FIFO STATUS REG: A0
ACT STATUS SHOCK REG: 1
INT_SOURCE: C3
0.490   -0.098  2.156
0.490   -0.098  2.156
0.392   0.098   1.960
0.392   0.294   2.254
0.294   0.098   1.960
-0.784  -0.882  1.470
-0.686  -0.980  1.274
10.976  13.524  59.290
27.342  17.934  36.358
-13.034 -6.566  -1.666
-0.098  0.098   1.078
0.000   0.294   0.686
0.098   0.098   1.470
Diracx
  • 61
  • 10