Search code examples
avr

How to calculate g values from LIS3DH sensor?


I am using LIS3DH sensor with ATmega128 to get the acceleration values to get motion. I went through the datasheet but it seemed inadequate so I decided to post it here. From other posts I am convinced that the sensor resolution is 12 bit instead of 16 bit. I need to know that when finding g value from the x-axis output register, do we calculate the two'2 complement of the register values only when the sign bit MSB of OUT_X_H (High bit register) is 1 or every time even when this bit is 0.

From my calculations I think that we calculate two's complement only when MSB of OUT_X_H register is 1.

But the datasheet says that we need to calculate two's complement of both OUT_X_L and OUT_X_H every time.

Could anyone enlighten me on this ?

Sample code

 int main(void)
 {      
     stdout = &uart_str;            
     UCSRB=0x18; // RXEN=1, TXEN=1 
     UCSRC=0x06; // no parit, 1-bit stop, 8-bit data
     UBRRH=0;
     UBRRL=71; // baud 9600

     timer_init();

     TWBR=216; // 400HZ
     TWSR=0x03;
     TWCR |= (1<<TWINT)|(1<<TWSTA)|(0<<TWSTO)|(1<<TWEN);//TWCR=0x04;
     printf("\r\nLIS3D address: %x\r\n",twi_master_getchar(0x0F));  
     twi_master_putchar(0x23, 0b000100000);
     printf("\r\nControl 4 register 0x23: %x", twi_master_getchar(0x23));       
     printf("\r\nStatus register %x", twi_master_getchar(0x27));
     twi_master_putchar(0x20, 0x77);

     DDRB=0xFF;
     PORTB=0xFD;
     SREG=0x80; //sei();


     while(1)
     {              
         process();
     }
 }
 void process(void){
    x_l = twi_master_getchar(0x28);
    x_h = twi_master_getchar(0x29);
    y_l = twi_master_getchar(0x2a);
    y_h = twi_master_getchar(0x2b);
    z_l = twi_master_getchar(0x2c);
    z_h = twi_master_getchar(0x2d);
    xvalue = (short int)(x_l+(x_h<<8));
    yvalue = (short int)(y_l+(y_h<<8));
    zvalue = (short int)(z_l+(z_h<<8));
    printf("\r\nx_val: %ldg", x_val);
    printf("\r\ny_val: %ldg", y_val);
    printf("\r\nz_val: %ldg", z_val);
 }

I wrote the CTRL_REG4 as 0x10(4g) but when I read them I got 0x20(8g). This seems bit bizarre.


Solution

  • Do not compute the 2s complement. That has the effect of making the result the negative of what it was.

    Instead, the datasheet tells us the result is already a signed value. That is, 0 is not the lowest value; it is in the middle of the scale. (0xffff is just a little less than zero, not the highest value.)

    Also, the result is always 16-bit, but the result is not meant to be taken to be that accurate. You can set a control register value to to generate more accurate values at the expense of current consumption, but it is still not guaranteed to be accurate to the last bit.