LSM303 accelerometer issues

Hello all,

I have been spending A LOT of time trying to get this tilt adjusted compass going, i have been changing over RyanTM’s code so it can compile on MikroC.

I have got the magnetometer working what seems to be 100%, it generally gives a heading ±2 degrees. I have also implemented all of the maths for the tilt adjustment and checked all the calcs in spreasheet.

But where i am having issues is with the accelerometer. It reads the registers but the data doesnt seem to make sense to me.

Attached is the image of the raw data outputted every 1 second through serial.

I would of expected the output to be around 0 for 2 axis and ± 1g for the other direction.

I have CTRL_REG1_A set to 27 currently.

I have tried adjusting CTRL_REG4_A aswell to ±8g, and tried averaging 20 times over 1 second to see if it changed much but with no luck.

Below is my reading in code.

void I2C_read_Accelerometer(void)
{

 I2C_Start();            delay_ms(1); //send START
     I2C_Wr(0x30);           delay_ms(2); //Write device address to bus for Write mode  ACCEL_ADDR from Arduino ex
     I2C_Wr(0x28);           delay_ms(2); //Write desired address bits                  x axis MSB
     I2C_Repeated_start();   delay_ms(1); //send repeated start
     I2C_Wr(0x31);           delay_ms(2); //Write device address to bus for Read mode   taken from MikroC I2C example
     ACC_data[0]=I2C1_Rd(0);  delay_ms(1); //Read in data from register
 //    ACC_data[1]=I2C1_Rd(0);  delay_ms(1); //Read in data from register
 //    ACC_data[2]=I2C1_Rd(0);  delay_ms(1); //Read in data from register
 //    ACC_data[3]=I2C1_Rd(0);  delay_ms(1); //Read in data from register
 //    ACC_data[4]=I2C1_Rd(0);  delay_ms(1); //Read in data from register
 //    ACC_data[5]=I2C1_Rd(0);  delay_ms(1); //Read in data from register
     I2C_Stop();             delay_ms(5); //send STOP

     I2C_Start();            delay_ms(1); //send START
     I2C_Wr(0x30);           delay_ms(2); //Write device address to bus for Write mode
     I2C_Wr(0x29);           delay_ms(2); //Write desired address bits                  x axis LSB
     I2C_Repeated_start();   delay_ms(1); //send repeated start
     I2C_Wr(0x31);           delay_ms(2); //Write device address to bus for Read mode
     ACC_data[1]=I2C1_Rd(0);  delay_ms(1); //Read in data from register
     I2C_Stop();             delay_ms(5); //send STOP

     I2C_Start();            delay_ms(1); //send START
     I2C_Wr(0x30);           delay_ms(2); //Write device address to bus for Write mode
     I2C_Wr(0x2A);           delay_ms(2); //Write desired address bits                  y axis MSB
     I2C_Repeated_start();   delay_ms(1); //send repeated start
     I2C_Wr(0x31);           delay_ms(2); //Write device address to bus for Read mode
     ACC_data[2]=I2C1_Rd(0);  delay_ms(1); //Read in data from register
     I2C_Stop();             delay_ms(5); //send STOP

     I2C_Start();            delay_ms(1); //send START
     I2C_Wr(0x30);           delay_ms(2); //Write device address to bus for Write mode
     I2C_Wr(0x2B);           delay_ms(2); //Write desired address bits                  y axis LSB
     I2C_Repeated_start();   delay_ms(1); //send repeated start
     I2C_Wr(0x31);           delay_ms(2); //Write device address to bus for Read mode
     ACC_data[3]=I2C1_Rd(0);  delay_ms(1); //Read in data from register
     I2C_Stop();             delay_ms(5); //send STOP

     I2C_Start();            delay_ms(1); //send START
     I2C_Wr(0x30);           delay_ms(2); //Write device address to bus for Write mode
     I2C_Wr(0x2C);           delay_ms(2); //Write desired address bits                  z axis MSB
     I2C_Repeated_start();   delay_ms(1); //send repeated start
     I2C_Wr(0x31);           delay_ms(2); //Write device address to bus for Read mode
     ACC_data[4]=I2C1_Rd(0);  delay_ms(1); //Read in data from register
     I2C_Stop();             delay_ms(5); //send STOP

     I2C_Start();            delay_ms(1); //send START
     I2C_Wr(0x30);           delay_ms(2); //Write device address to bus for Write mode
     I2C_Wr(0x2D);           delay_ms(2); //Write desired address bits                  z axis LSB
     I2C_Repeated_start();   delay_ms(1); //send repeated start
     I2C_Wr(0x31);           delay_ms(2); //Write device address to bus for Read mode
     ACC_data[5]=I2C1_Rd(0);  delay_ms(1); //Read in data from register
     I2C_Stop();             delay_ms(5); //send STOP
     
//   early debug
     testa=ACC_data[0];
     testb=ACC_data[1];
	   setTX();
           Usart_Write(testa);
           delay_ms(1);
           Usart_Write(testb);
           delay_ms(1);
            setRX();
     

     Ax_raw = (int)(((ACC_Data[0] << 8) + ACC_Data[1])>>4);
     if (Ax_raw > 2047) {Ax_raw = ((Ax_raw-2048)+1)*-1;}

    Ay_raw = (int)(((ACC_Data[2] << 8) + ACC_Data[3])>>4);
     if (Ay_raw > 2047) {Ay_raw = ((Ay_raw-2048)+1)*-1;}

     Az_raw = (int)(((ACC_Data[4] << 8) + ACC_Data[5])>>4);
     if (Az_raw > 2047) {Az_raw = ((Az_raw-2048)+1)*-1;}

  

   
  }

I was hoping someone might be able to offer some insight.

Thankyou

Hi,

Why are you not using the multiple-byte-reading feature? Also, I think those delays are unnecessary, and it appears that you have flipped the high and low bytes in your calculations of the raw values.

I don’t have a device or compiler for testing this, but I would write the function more like this:

void I2C_read_Accelerometer(void)
{
	I2C_Start();            //send START
	I2C_Wr(0x30);           //Write device address to bus for Write mode  ACCEL_ADDR from Arduino ex
	I2C_Wr(0x28 | (1 << 7));//Write desired address bits x axis MSB with 7th bit set to enable multi-byte read
	I2C_Repeated_start();   //send repeated start
	I2C_Wr(0x31);           //Write device address to bus for Read mode   taken from MikroC I2C example
	ACC_data[0]=I2C1_Rd(1); //Read in data from register master ack after each byte read except the last one
	ACC_data[1]=I2C1_Rd(1); //Read in data from register
	ACC_data[2]=I2C1_Rd(1); //Read in data from register
	ACC_data[3]=I2C1_Rd(1); //Read in data from register
	ACC_data[4]=I2C1_Rd(1); //Read in data from register
	ACC_data[5]=I2C1_Rd(0); //Read in data from register, the last byte read should not acknowledge
	I2C_Stop();             //send STOP
	
	//early debug
	testa=ACC_data[0];
	testb=ACC_data[1];
	setTX();
	Usart_Write(testa);
	delay_ms(1);
	Usart_Write(testb);
	delay_ms(1);
	setRX();
     
	Ax_raw = (int)(((ACC_Data[1] << 8) + ACC_Data[0]) >> 4);
	Ay_raw = (int)(((ACC_Data[3] << 8) + ACC_Data[2]) >> 4);
	Az_raw = (int)(((ACC_Data[5] << 8) + ACC_Data[4]) >> 4);
}

- Ryan

Hello Ryan,

You have been such a great help with this project, i am really appreciative.

The reason why i was getting such a varying number and accelerometer outputs that didnt make sense to me was the silly mix up of the read in bytes. I dont think i would of noticed for another 50 hours of programming.

If i could just bug you for one more thing could you please confirm that all normalised values should be between -1 and +1?
This is what i expect but i just want to make sure, as my compiler seems to handle negative numbers a touch differently to what you designed yours for.

I have done some tesing whilst trying to hold the cct level and rotate it. If i ouput the basic heading (tan(x,y)) it works great. The tilt adjust output as your code is designed to do outputs a number within the range of 0-360 but doesnt seem to go linearly around when rotated and is offset from the basic heading calc. Is this something that could be normal and just needs calibrating?

Thankyou for all your help it is greatly appreciated

Yes. A normalized vector has a magnitude of 1.

I don’t know how non-linear the headings you are getting are but it sounds normal. You might be able to improve it by doing the more complex calibration that ST describes in their app note.

- Ryan