LSM303D acceleration readings problem

I have got an LSM303D PCB, to replace the previous LSM303DLM, which suffered from magnetisation. However, the accelerometer worked correctly, after I got the data order and right-shifting correct!

In the LSM303D PCB, I am using I2C communications and can successfully load the following values into CTRL0 to CTRL7, using C:

#define CTRL0 0b00000000 //for normal mode, filters by-passed
#define CTRL1 0b01001111 //update after read, and all axes of acceleration enabled at 25Hz
#define CTRL2 0b11000001 //50Hz anti-alias, +/- 2g, no self-test, (SPI 3-wire) - is ignored because the CS pin is tied high.
#define CTRL3 0b00000000 //No INT1 actions
#define CTRL4 0b00001000 //accelerometer data ready on INT2.
#define CTRL5 0b00001110 //No temperature, low-res magnetic, 25Hz, latch interrupt on INT2
#define CTRL6 0b00000000 // +/-2 gauss sensitivity.
#define CTRL7 0b00100000 //normal high-pass acceleration filter, no Temp, magnetic always on, continuous conversion mode

They load correctly, and I have checked by reading them back. When I run the unit, I check the magnetometer data valid flag before reading the magnetometer values. The magnetometer returns sensible readings, with acceptable levels of noise.
But the accelerometer is not working at all in any axis. Random values are being returned. I check the INT2 pin high before reading the accelerometer values. (I’ve also tried checking the ZYXADA bit in STATUS_A before reading the accelerometer, but get the same faulty data.)

Can anyone suggest a solution, please?

Hello.

I am sorry you are having problems using your LSM303D carrier. Could you tell us more about your setup? What are you using to communicate with the sensor? Could you post your code and an example of the bad output you are getting?

- Jeremy

A typical (bad!) output (with the z acceleration axis vertical) is this, where the six readings are Ax,Ay,Az,Mx,My,Mz.

+0032,+0000,+0000,-3193,+0054,+5070
+0032,+0000,+0000,-3196,+0051,+5080
+0032,-0032,+0000,-3196,+0047,+5055
+0000,+0000,+0032,-3163,+0006,+5059
+0000,+0000,+0000,-3209,+0019,+5090
-0032,+0000,+0032,-3144,+0059,+5077
-0032,+0000,-0032,-3179,+0022,+5051
+0000,+0000,-0032,-3172,+0043,+5075
-0032,+0000,+0000,-3170,-0037,+5050
+0032,+0000,+0032,-3209,+0051,+5081
+0032,+0000,+0000,-3191,-0037,+5049

You can see that the magnetometer values look good, whereas all the accelerometer values are wrong - there is no z-axis value, for example.
The I2C is running at 100kHz, and I can send you the I2C driver code if it helps, but I know the I2C is working because I can read back the CTRL registers after loading them.

These are the constants I use in the code:

#define SAD_WRITE	0b00111010	//The slave address ID for high SD0/SDA
#define SAD_READ	0b00111011	//for reading (after a repeated start)

#define CTRL0_ADD	0x9F	//the address of CTRL0 (0x1F) with bit 7 set for auto-increment

#define CTRL0		0b00000000	//for normal mode, filters by-passed
#define CTRL1 		0b01001111	//update after read, and all axes of acceleration enabled at 25Hz
#define CTRL2 		0b11000001	//50Hz anti-alias, +/- 2g, no self-test, (SPI 3-wire)
#define CTRL3 		0b00000000	//No INT1 actions
#define CTRL4 		0b00001000	//accelerometer data ready on INT2.
#define CTRL5		0b00001110	//No temperature, low-res magnetic, 25Hz, latch interrupt on INT2
#define CTRL6 		0b00000000	//+/-2gauss sensitivity.
#define CTRL7		0b00100000	//normal high-pass acceleration filter, no Temp, magnetic always on, continuous conversion mode
//#define STATUS_REG_A 0b00000000	//ditto?

//the first address for six bytes of magnetic data:
#define OUT_X_L_M	0x88	//the address of the low byte of the x magnetic, bit 7 set = autoincrement.
//then 9, A, B, C, D, are the high/low/high/low/high addresses of X, Y, Z magnetic sensors
#define STATUS_M	0x07
#define MASK_ZYXADA 0b00000111

//the first address for six bytes of acceleration data:
#define OUT_X_L_A	0xA8	//bit 7 is set = auto-increment
#define STATUS_A	0x27
#define MASK_ZYXMDA	0b00000111
//__________________________________________________________________

This is the code which reads the accelerometers (written in Hitech C for Microchip 16F1824):

unsigned char read_status_A(void)	{

unsigned char temp;
	send_start();
	write_byte(SAD_WRITE);	//to write to the accelerometer registers.
	write_byte(STATUS_A);	//no repeat
	send_start();				//repeated start for reading
	write_byte(SAD_READ);	//switch device to read from the magnetometer registers.

	temp = read_byte_no_ACK();	//all the bits, no ACK
	send_stop();

	temp &= MASK_ZYXADA;
	return temp;
}
//__________________________________________________________________

void read_accelerometers(void)	{	//sends the three magnetic configuration bytes

	PORTC = 0;//Make sure all the port latches are low before we get going:

	while(INT2 == 0)	{	//check data valid
//	while(read_status_A() == 0)	{	//check data valid
		if(TEST_OUT == 0)
			TEST_OUT = 1;
		else
			TEST_OUT = 0;
		CLRWDT();
	}
	TEST_OUT = 0;

	send_start();
	write_byte(SAD_WRITE);	//to write to the accelerometer registers.
	write_byte(OUT_X_L_A);	//write first byte address to read from (with bit 7 set set to auto-increment).
	send_start();			//repeated start for reading
	write_byte(SAD_READ);	//switch device to read from the accelerometer registers.

	ax[0] = read_byte();	//LSByte
	ax[1] = read_byte();	//MSByte
	ay[0] = read_byte();
	ay[1] = read_byte();
	az[0] = read_byte();
	az[1] = read_byte_no_ACK();
	send_stop();

	x_acc = ax[1];
	x_acc <<= 8;
	x_acc |= ax[0];
//	x_acc >>= 4;	//acceleration values are sent left-shifted!
	x_acc_value = (double)x_acc;

	y_acc = ay[1];
	y_acc <<= 8;
	y_acc |= ay[0];
//	y_acc >>= 4;	//acceleration values are sent left-shifted!
	y_acc_value = (double)y_acc;

	z_acc = az[1];
	z_acc <<= 8;
	z_acc |= az[0];
//	z_acc >>= 4;	//acceleration values are sent left-shifted!
	z_acc_value = (double)z_acc;
}
//__________________________________________________________________

Could you post a complete program that demonstrates the problem (you can use the “Upload attachment” feature if the code is too long)? Could you also post pictures of your setup?

- Jeremy

The complete program? Do you want the source code or the compiled object code? Do you have a Hitech C compiler?



The PCB 16F1824 underside has pin 1 at the top left-hand corner (the one with the added 1k resistor)

This is the code:

polulu.zip (11.1 KB) (corrected since earlier)
It is for compilation using Hitech C compiler from MPLAB 8.76
polulu.zip (10.6 KB)

We were able to reproduce your results by using the same register settings you used. We noticed that when we shook the sensor, we were able to read an acceleration. It looks like the high-pass filter on the chip filters out the acceleration due to gravity. If this is something you do not want, you should change the AFDS bit in CTRL7 to 0.

By the way, your print function might not work properly for 5 digit numbers (the LSM303D has a 16-bit data output).

- Jeremy

:smiley:
That’s the problem! Thanks very much for your help. I’ve got correctly-orientated static acceleration outputs from all three axes.

The data sheet is not clear what the difference between AHPM1:APHM0 = 00 and AHPM1:APHM0 = 10, but either seems to work with AFDS = 0.

The ASCII output data does indeed overflow now I’ve got the accelerometer working, but the program was only for demonstrating the fault - and it’s served its purpose.

So thank you again.