2014-10-27 01:50 PM
Hello all, i started a while ago some IMU project... but i have some doubts about reading the correct data from my accelerometer, wich is LSM303DLHC
Acording to my code, i setup the following registers CTRL_REG1_A 0x77 set 400hz data rate CTRL_REG4_A 0x00 2g, little endian When i set the MSB of the first register to be read ( 0x28, with msb set results 0xA8) then acording to the LSM datasheet it continues to send me data from all 6 register in the following order: uint8_t dataBuffer[6]; 1st dataBuffer[0] X_LSB ( address 0x28) 2nd dataBuffer[1] X_MSB ( address 0x29) 3rd dataBuffer[2] Y_LSB ( address 0x2A) 4th dataBuffer[3] Y_MSB ( address 0x2B) 5th dataBuffer[4] Z_LSB ( address 0x2C) 6th dataBuffer[5] Z_MSB ( address 0x2D) then i integrate the MSB`s and the LSBs in 16bit integer like this: int16_t Buf[3]; Buf[0]=((dataBuffer[1]<<8)+dataBuffer[0])/16; Buf[1]=((dataBuffer[3]<<8)+dataBuffer[2])/16; Buf[2]=((dataBuffer[4]<<8)+dataBuffer[4])/16; The /16 division is for 4 bit right shift since LSM303DLHC outputs on accelerometer only 12bit values from the 16bit register and after this i divide by the 2g factor, wich acording to the datsheet is 1 for 2g, ending in 1LSB/mg float x,y,z; x=Buf[0]/1 y=Buf[1]/1 z=Buf[2]/1 I want to know, at this poit did i interpret the data corectly? And these final values are somehow doubtfull to be corectly, the values where printed directly troug serial port X:4.00 Y:36.00 Z:0.00 X:4.00 Y:40.00 Z:0.00 X:4.00 Y:36.00 Z:2056.00 X:4.00 Y:20.00 Z:1028.00 X:8.00 Y:36.00 Z:3084.00 X:4.00 Y:40.00 Z:3084.00 X:4.00 Y:32.00 Z:2056.00 X:8.00 Y:28.00 Z:0.00 X:0.00 Y:28.00 Z:0.00 X:12.00 Y:20.00 Z:1028.00 X:16.00 Y:24.00 Z:2056.00 X:4092.00 Y:20.00 Z:2056.00 X:16.00 Y:32.00 Z:3084.00 The end result is in miliG`s? or LSB`s ?2014-10-27 05:00 PM
The user's manual doesn't provide bit definitions for data out registers, so one has to guess if divide by 16 is correct.
Your problem looks greater than a wrong 4 bit shift. First send MSB and LSB registers to the serial port and see if those values looks correct. If not, I suspect problems in the setup or I2C interface, which are not shown. Does the I2C interface have the required pullup resisters ? Cheers, Hal2014-10-27 10:00 PM
Hello, i dont know how much is this problem related to the i2c comunication wich from my point of view seems to work ok, see bellow the LSM initialization registers where :
0x32 is the write adress of the LSM CTRL_REG1_A (20h) 0x37 - data for setting up CTRL_reg1 with 25hz output data rate, xyz enable axes, normal mode CTRL_REG4_A (23h) 0x00 - sets +/- 2G range, little endian (BLE bit is set 0 ) ''data LSB @ lower address'' Bellow is the i2c reading of the 6 axis registers x32 is LSM write address A8 (binary1
0101000) is 0x28 with the msb set ( 0x28 -0
0101000) After this i send the x33 LSM read command and the chip starts to ouput every acc register values starting with x_lsb ( 0x00) x_msb(0xFD) y_lsb ( 0x00 ) y_msb(0x02) z_lsb(0x80) and the last is z_msb (0x3e ) Regarding the >>4 or /16 i saw that this is used in the ST LSM303dlhc library wich was my reference for the setup code here is my code and i2c functionsvoid LSM303_init(){
i2c_send_cmd(awAddr, CTRL_REG1_A, 0x37); // 25hz ODR
i2c_send_cmd(awAddr, CTRL_REG4_A, 0x00);//+2g, little endian
}
void lsm_readAccRaw(int16_t* tempBuf){
uint8_t dataBuffer[6];
i2c_readBuffer(awAddr,dataBuffer,OUT_X_L_A,6);
tempBuf[0]=((dataBuffer[1]<<8)+dataBuffer[0])/16;
tempBuf[1]=((dataBuffer[3]<<8)+dataBuffer[2])/16;
tempBuf[2]=((dataBuffer[4]<<8)+dataBuffer[4])/16;
}
void lsm_readAcc(float* tempBuf){
int16_t aData[3];
lsm_readAccRaw(aData);
tempBuf[0]=aData[0]/1.0; // x axis
tempBuf[1]=aData[1]/1.0; // y axis
tempBuf[2]=aData[2]/1.0; // z axis
}
And my main program
int main(void){
system_init(); // cals for i2c initialization and for other periphs setups
LSM303_init();
float ccc[3];
char txtx[20]
char txty[20]
char txtz[20]
while(1){
lsm_readAcc(ccc);
sprintf(txtx,''%f'',ccc[0]);
sprintf(txty,''%f'',ccc[1]);
sprintf(txtz,''%f'',ccc[2]);
lcd_char(1,1,txtx);
lcd_char(1,1,txty);
lcd_char(1,1,txtz);
delay_ms(200); // 200 ms aprox delay
}
}
Regarding usage of USART module, the results are the same even displayed on a plain 20x4 LCD
the datsheet is here
http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM000275pdf
2014-10-28 10:35 AM
The logic analyzer trace shows the I2C interface is working correctly.
The reason for displaying the register values is to verify that the accelerometer outputs look reasonable. Doing the math manually: X = FD00. Shift right 4 bits = minus 0x2F = -47. Accel is -47/1024 = -46 mg. Y = 0200. Shift right 4 bits = 0x20 = 32. Accel is 32/1024 = 31 mg. Z = 3E80. Shift right 4 bits is 0x3E8 = 1000. Accel is 1000/1024 = 977 mg. Considering that the unit typically has a 60 mg offset in any axis, the results are acceptable. Check the post conversion code. A routine is called to place raw assembled register values in the tempbuf table, then this table is overwritten by the aData table. Cheers, Hal2014-10-28 11:14 AM
4
]<<8)+dataBuffer[4])/16; And stil i had wrong values . I did a little trick, by declaring all the lsb`s and msb`s as fixed value like bellow uint8_t dataBuffer[6]; dataBuffer[0]=0x00; dataBuffer[1]=0xfd; dataBuffer[2]=0x00; dataBuffer[3]=0x02; dataBuffer[4]=0x80; dataBuffer[5]=0x3e;//i2c_readBuffer(awAddr,dataBuffer,OUT_X_L_A,6);
tempBuf[0]=((dataBuffer[1]<<8)+dataBuffer[0])/16; tempBuf[1]=((dataBuffer[3]<<8)+dataBuffer[2])/16; tempBuf[2]=((dataBuffer[5]<<8)+dataBuffer[4])/16; After this, the readings are X: 4048 Y: 32 Z: 1000 Then i tryied declare dataBuffer as SIGNED INT, and the values are like yours,namely X: -48 Y: 32 Z: 984 What i dont understand here is why in the ST standard libraries and in ST`s app note AN3182the MSB`s and the LSB`s alone are declared asUNSIGNED
int ?2014-10-28 01:26 PM
Probably because deep in the bowels of the device, the value is built as a signed twos complement 16 bit number, then split for storing in the output registers. The most significant bit of the LSB is not a sign bit. When the bytes are reassembled into a signed word, the twos complement representation is preserved.
Now you can tackle the magnetic output with confidence. Cheers, Hal