cancel
Showing results for 
Search instead for 
Did you mean: 

how to calculate G-force using LIS331HH 3-axis accelerometer axes values ?

ABORR.1
Associate

Below are the settings used :

FS : +-6g

sensitivity : 3 mg/digit

here is the sampling code which i am working on reading the axes values.

uint16_t temp_x=0,temp_y=0,temp_z=0;

void Accel_Read_XYZ_Axis(void)

{

 uint8_t OUT_X_H=0,OUT_X_L=0;

 uint8_t OUT_Y_H=0,OUT_Y_L=0;

 uint8_t OUT_Z_H=0,OUT_Z_L=0;

  

  

 uint8_t command = 0xA8;

 uint8_t data=0; //0b11101000;

 //Reading Byte by Byte separately

 OUT_X_L = send_command(0xA8,data);

 OUT_X_H = send_command(0xA9,data);

 OUT_Y_L = send_command(0xAA,data);

 OUT_Y_H = send_command(0xAB,data);

 OUT_Z_L = send_command(0xAC,data);

 OUT_Z_H = send_command(0xAD,data);

  

 temp_x = (((OUT_X_H) << 😎 | (OUT_X_L));

 temp_y = (((OUT_Y_H) << 😎 | (OUT_Y_L));

 temp_z = (((OUT_Z_H) << 😎 | (OUT_Z_L));

 if(0x8000 & temp_x)           //Checking whether the number is negative or not

 {

  temp_x = ((~temp_x) & 0x0FFF)+1;    //Doing 2's complement to the 12 bit number of the read X-axis data

  x_axis = ((temp_x * 3.0f)/1000)*(-1.0);  //Multiplying the sensitivity in mG to raw value

 }

 else

 {

  temp_x = ((~temp_x) & 0x0FFF)+1;  

  x_axis = ((temp_x * 3.0f)/1000); //Multiplying the sensitivity in mG to raw value

 }

 if(0x8000 & temp_y)

 {

  temp_y = ((~temp_y) & 0x0FFF)+1;

  y_axis = ((temp_y * 3.0f)/1000)*(-1.0); //Multiplying the sensitivity in mG to raw value

 }

 else

 {

   temp_y = ((~temp_y) & 0x0FFF)+1; 

  y_axis = ((temp_y * 3.0f)/1000); //Multiplying the sensitivity in mG to raw value

 }

 if(0x8000 & temp_z)

 {

  temp_z = ((~temp_z) & 0x0FFF)+1;

  z_axis = ((temp_z * 3.0f)/1000)*(-1.0); //Multiplying the sensitivity in mG to raw value

 }

 else

 {

   temp_z = ((~temp_z) & 0x0FFF)+1; 

  z_axis = ((temp_z * 3.0f)/1000); //Multiplying the sensitivity in mG to raw value

 }

}

Check the if-else statements whether the process is correct or not. Suggest me if any changes needs to be done.

Note:: Please give me a solution in calucating the G_Force using these three axes values.

1 ACCEPTED SOLUTION

Accepted Solutions
niccolò
ST Employee

Hi @ABORR.1​ ,

to add on what @Eleon BORLINI​ said, if you want to utilize your custom functions to read the data, your method is almost right (if the send_command function returns the correct value), the only problem is that you supposed that the non significant bits of the data were in the high register, while they are in the LSBs of the low one.

(maybe because of the little endian / big endian difference -> this refers to the way the microcontroller detects multiple reads)

also, for simplicity, the code could be more compact:

int16_t temp_x=0,temp_y=0,temp_z=0; /// note the int16_t instead of uint16_t
 
void Accel_Read_XYZ_Axis(void)
{
 uint8_t OUT_X_H=0,OUT_X_L=0;
 uint8_t OUT_Y_H=0,OUT_Y_L=0;
 uint8_t OUT_Z_H=0,OUT_Z_L=0;
 
 uint8_t command = 0xA8;
 uint8_t data=0; //0b11101000 --> (?) I don't understand what this comment refers to
 
 //Reading Byte by Byte separately
 OUT_X_L = send_command(0xA8,data);
 OUT_X_H = send_command(0xA9,data);
 OUT_Y_L = send_command(0xAA,data);
 OUT_Y_H = send_command(0xAB,data);
 OUT_Z_L = send_command(0xAC,data);
 OUT_Z_H = send_command(0xAD,data);
 
 temp_x = (((OUT_X_H) << 8) | (OUT_X_L))>>4;
 temp_y = (((OUT_Y_H) << 8) | (OUT_Y_L))>>4;
 temp_z = (((OUT_Z_H) << 8) | (OUT_Z_L))>>4;
     /// this is your only real error: the shift by 4 is to get the MSBs in the right position (you thought that the MSBs were to discard and did a &&0x0FFF, but the LSBs are the ones to get rid of)
 
  // the check for positive/negative can be bypassed because temp is already with sign
  x_axis = ((temp_x * 3.0f)/1000);  //Converting the sensitivity in g  from raw value
 
  y_axis = ((temp_y * 3.0f)/1000); //Converting the sensitivity in g  from raw value
 
  z_axis = ((temp_z * 3.0f)/1000); //Converting the sensitivity in g  from raw value
  /// if you wanted mg, you should not divide by 1000
}

try to display the value in a static condition: when the sensor is horizontal, the outputs should be around 1g on one axis and around 0g on the others, to check if you read the right values.

is everything understandable?

View solution in original post

3 REPLIES 3
Eleon BORLINI
ST Employee

Hi @ABORR.1​ , I'm not sure to have understood if you are able to read the and you need to calculate only the the gravity vector. In the first case, if you are troubling with the drivers, I suggest you to check the online C examples on Github from a similar sensor (lis331dlh_read_data_polling.c:(

      acceleration_mg[0] =
        LIS331DLH_FROM_FS_2g_TO_mg(data_raw_acceleration.i16bit[0]);
      acceleration_mg[1] =
        LIS331DLH_FROM_FS_2g_TO_mg(data_raw_acceleration.i16bit[1]);
      acceleration_mg[2] =
        LIS331DLH_FROM_FS_2g_TO_mg(data_raw_acceleration.i16bit[2]);

where (lis331dlh_reg.c:(

float lis331dlh_from_fs8_to_mg(int16_t lsb)
{
  return ((float)lsb * 3.9f / 16.0f);
}

In the second case, if you are able to read the data but you want to calculate the overall g force, you simply have to sum the components (v = sqrt(x^2+y^2+z^2)). You can find more details in DT0105 design tip application note for an accurate sensor calibration.

Regards

niccolò
ST Employee

Hi @ABORR.1​ ,

to add on what @Eleon BORLINI​ said, if you want to utilize your custom functions to read the data, your method is almost right (if the send_command function returns the correct value), the only problem is that you supposed that the non significant bits of the data were in the high register, while they are in the LSBs of the low one.

(maybe because of the little endian / big endian difference -> this refers to the way the microcontroller detects multiple reads)

also, for simplicity, the code could be more compact:

int16_t temp_x=0,temp_y=0,temp_z=0; /// note the int16_t instead of uint16_t
 
void Accel_Read_XYZ_Axis(void)
{
 uint8_t OUT_X_H=0,OUT_X_L=0;
 uint8_t OUT_Y_H=0,OUT_Y_L=0;
 uint8_t OUT_Z_H=0,OUT_Z_L=0;
 
 uint8_t command = 0xA8;
 uint8_t data=0; //0b11101000 --> (?) I don't understand what this comment refers to
 
 //Reading Byte by Byte separately
 OUT_X_L = send_command(0xA8,data);
 OUT_X_H = send_command(0xA9,data);
 OUT_Y_L = send_command(0xAA,data);
 OUT_Y_H = send_command(0xAB,data);
 OUT_Z_L = send_command(0xAC,data);
 OUT_Z_H = send_command(0xAD,data);
 
 temp_x = (((OUT_X_H) << 8) | (OUT_X_L))>>4;
 temp_y = (((OUT_Y_H) << 8) | (OUT_Y_L))>>4;
 temp_z = (((OUT_Z_H) << 8) | (OUT_Z_L))>>4;
     /// this is your only real error: the shift by 4 is to get the MSBs in the right position (you thought that the MSBs were to discard and did a &&0x0FFF, but the LSBs are the ones to get rid of)
 
  // the check for positive/negative can be bypassed because temp is already with sign
  x_axis = ((temp_x * 3.0f)/1000);  //Converting the sensitivity in g  from raw value
 
  y_axis = ((temp_y * 3.0f)/1000); //Converting the sensitivity in g  from raw value
 
  z_axis = ((temp_z * 3.0f)/1000); //Converting the sensitivity in g  from raw value
  /// if you wanted mg, you should not divide by 1000
}

try to display the value in a static condition: when the sensor is horizontal, the outputs should be around 1g on one axis and around 0g on the others, to check if you read the right values.

is everything understandable?

ABORR.1
Associate

Thank you ! for your valuable time in answering the question, now we are getting correct values as we expected 🙏 👍