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:

[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
//__________________________________________________________________[/code]

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

[code]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;
}
//__________________________________________________________________[/code]

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.