H3LIS331 does not have 16 bit resolution
Opened this issue · 10 comments
H3LIS331 and LIS331 having same registers and has 12-bit resolution therefore, when reading data should shift left 4 bytes.
I was deceived by the ST datasheet. I needed a reasonable precision but after spend money and a lot of time I got noisy output in a static position. Any improvement like using low pass filter could be valuable.
Data retrives in this way:
x = dataLis[0] | dataLis[1] << 8;
x = x >> 4;
49mg/bit is not right. the full scale is +-400 g in 12 bit integer format (4096) means 195 mg.
I have made some modification in your code but I am not satisfied with the results:
getAres() {
switch (Ascale)
{
// Possible accelerometer scales (and their register bit settings) are:
// 100 Gs (000), 200 Gs (001),400 gs (010)
case AFS_100G:
aRes = 100.0/2048.0;// 12 bits 4096 16bits 32768.0;
break;
case AFS_200G:
aRes = 200.0/2048.0;
break;
case AFS_400G:
aRes = 400.0/2048.0;
break;
}
}
void readAccelData(int16_t * destination)
{
uint8_t rawData[6]; // x/y/z accel register data stored here
LIS331_read(0x28, &rawData[0],6); // &rawData[0]H3LIS331D_OUT_X_L Read the six raw data registers into data array
destination[0] = (int16_t) (((int16_t)rawData[1] << 8) | (rawData[0]>>4)) ; //12 bits data Form signed 16-bit integer for each sample
destination[1] = (int16_t) (((int16_t)rawData[3] << 8) | (rawData[2]>>4)) ;
destination[2] = (int16_t) (((int16_t)rawData[5] << 8) | (rawData[4]>>4)) ;
}
Whats the point when least 4 bits are always 0? Similar accelerometer is FXLS8471Q
https://github.com/YourproductSmarter/KISSLoRa-demo/blob/3d0cedb0694afa7b252aefb4dbae7a9ebd6745d2/Examples/Accelerometer/Accelerometer.ino
// Bit-shifting right does sign extension to preserve negative numbers.
x = ((short)(readAccelerometer(1)<<8 | readAccelerometer(2))) >> 4;
y = ((short)(readAccelerometer(3)<<8 | readAccelerometer(4))) >> 4;
z = ((short)(readAccelerometer(5)<<8 | readAccelerometer(6))) >> 4;
Hi Kriswiner. Please consider using these functions to improve calibration of H3LIS331 (Scale factor is not good option) and reading 12 bits. I recommend getting average of 3-10 samples to reduce RMS.
void readAccelData(int16_t * destination)
{
uint8_t rawData[6]; // x/y/z accel register data stored here
LIS331_read(0x28, &rawData[0],6); // &rawData[0]H3LIS331D_OUT_X_L Read the six raw data registers into data array
destination[0] = (int16_t) ( ((int16_t)rawData[1] << 8) | rawData[0] );
destination[1] = (int16_t) ( ((int16_t)rawData[3] << 8) | rawData[2] );
destination[2] = (int16_t) ( ((int16_t)rawData[5] << 8) | rawData[4] );
destination[0] /= 16;//12 bits
destination[1] /= 16;
destination[2] /= 16;
}
void accelcalH3LIS331D(float * dest2)
{
uint8_t data[6] = {0, 0, 0, 0, 0, 0};
int32_t accel_bias[3] = {0, 0, 0};
uint16_t samples = 50, ii;
Serial.println("Calibrating accel...");
Serial.println("One axis should be face UP or Down (-1 or +1 g)");
Serial.println(" Send a command to start when you are ready");
Serial.flush(); //flush all previous received and transmitted data
while(!Serial.available()) ; // hang program until a byte is received notice the ; after the while()
// now get the accelerometer bias
for(ii = 0; ii < samples ; ii++) {
int16_t accel_temp[3] = {0, 0, 0};
LIS331_read(0x28, &data[0], 6);//H3LIS331D_OUT_X_L
accel_temp[0] = (int16_t) ( ((int16_t)data[1] << 8) | data[0] );
accel_temp[1] = (int16_t) ( ((int16_t)data[3] << 8) | data[2] );
accel_temp[2] = (int16_t) ( ((int16_t)data[5] << 8) | data[4] );
accel_temp[0] /= 16;//12 bits
accel_temp[1] /= 16;
accel_temp[2] /= 16;
accel_bias[0] += (int32_t) accel_temp[0]; // Sum individual signed 16-bit biases to get accumulated signed 32-bit biases
accel_bias[1] += (int32_t) accel_temp[1];
accel_bias[2] += (int32_t) accel_temp[2];
delay(6);//3); // wait twelve milliseconds for next data at 1000 Hz sample rate
}
accel_bias[0] /= samples; // average the data
accel_bias[1] /= samples;
accel_bias[2] /= samples;
dest2[0] =(float)(2.f*(accel_bias[0]-Low[0])/(High[0]-Low[0]))-1.f;
if(dest2[0]<0)
{
if(abs(dest2[0])>0.5)
dest2[0] = dest2[0]- (-1);//-0.7-(-1)=0.3 -0.7 -(0.3)=-1
}
else
{
if(dest2[0]>0.5)
dest2[0] = dest2[0]- 1;//0.7-1=-0.3
}
dest2[1] =(float)(2.f*(accel_bias[1]-Low[1])/(High[1]-Low[1]))-1.f;
if(dest2[1]<0)
{
if(abs(dest2[1])>0.5)
dest2[1] = dest2[1]- (-1);//-0.7-(-1)=0.3 -0.7 -(0.3)=-1
}
else
{
if(dest2[1]>0.5)
dest2[1] = dest2[1]- 1;//0.7-1=-0.3
}
dest2[2] =(float)(2.f*(accel_bias[2]-Low[2])/(High[2]-Low[2]))-1.f;
if(dest2[2]<0)
{
if(abs(dest2[2])>0.5)
dest2[2] = dest2[2]- (-1);//-0.7-(-1)=0.3 -0.7 -(0.3)=-1
}
else
{
if(dest2[2]>0.5)
dest2[2] = dest2[2]- 1;//0.7-1=-0.3
}
Serial.print(" Offsetx = ");Serial.print(dest2[0],2);
Serial.print(" Offsety = "); Serial.print(dest2[1],2);
Serial.print(" Offsetz = "); Serial.print(dest2[2],2); Serial.println(" ");
}