cancel
Showing results for 
Search instead for 
Did you mean: 

LSM303DLHC compass

Mark van Matt
Associate II
Posted on May 22, 2018 at 12:59

I'm trying to do a compass using an LSM303DLHC sensor embedded in STM32F3 Discovery. I have prepared such a code which provides declaration and reading data from both accelerometer and magnetometer

void LSM303DLHCAcc_Config(void)

{

        

LSM303DLHCAcc_InitStructure.AccFull_Scale = LSM303DLHC_NORMAL_MODE;

        

LSM303DLHCAcc_InitStructure.AccOutput_DataRate = LSM303DLHC_ODR_200_HZ;

        

LSM303DLHCAcc_InitStructure.Axes_Enable = LSM303DLHC_AXES_ENABLE;

        

LSM303DLHCAcc_InitStructure.BlockData_Update = LSM303DLHC_BlockUpdate_Continous;

        

LSM303DLHCAcc_InitStructure.Endianness = LSM303DLHC_BLE_MSB;

        

LSM303DLHCAcc_InitStructure.High_Resolution = LSM303DLHC_HR_ENABLE;

        

LSM303DLHCAcc_InitStructure.Power_Mode = LSM303DLHC_BOOT_NORMALMODE;

        

LSM303DLHC_AccInit(&LSM303DLHCAcc_InitStructure);

}

void LSM303DLHCAcc_Read(float *convertedData_Acc)

{

        uint8_t i, XYZ[6] = {0};

        

LSM303DLHC_Read(ACC_I2C_ADDRESS,LSM303DLHC_OUT_X_L_A, XYZ, 1);

        

LSM303DLHC_Read(ACC_I2C_ADDRESS,LSM303DLHC_OUT_X_H_A, XYZ+1, 1);

        

LSM303DLHC_Read(ACC_I2C_ADDRESS,LSM303DLHC_OUT_Y_L_A, XYZ+2, 1);

        

LSM303DLHC_Read(ACC_I2C_ADDRESS,LSM303DLHC_OUT_Y_H_A, XYZ+3, 1);

        

LSM303DLHC_Read(ACC_I2C_ADDRESS,LSM303DLHC_OUT_Z_L_A, XYZ+4, 1);

        

LSM303DLHC_Read(ACC_I2C_ADDRESS,LSM303DLHC_OUT_Z_H_A, XYZ+5, 1);

        

for(i=0;i<3;i++)

        

{

        

        

convertedData_Acc[i] = (float) ((int16_t)((uint16_t)XYZ[2*i+1] << 8) + XYZ[2*i])/16;

        

}

}

void LSM303DLHCMag_Config(void)

{

        

LSM303DLHCMag_InitStructure.Temperature_Sensor = LSM303DLHC_TEMPSENSOR_DISABLE;

        

LSM303DLHCMag_InitStructure.MagFull_Scale = LSM303DLHC_FS_1_9_GA;

        

LSM303DLHCMag_InitStructure.MagOutput_DataRate = LSM303DLHC_ODR_220_HZ;

        

LSM303DLHCMag_InitStructure.Working_Mode = LSM303DLHC_CONTINUOS_CONVERSION;

        

LSM303DLHC_MagInit(&LSM303DLHCMag_InitStructure);

}

void LSM303DLHCMag_Read(float *convertedData_Mag)

{

        

uint8_t XYZ[6] = {0};

        

LSM303DLHC_Read(MAG_I2C_ADDRESS,LSM303DLHC_OUT_X_H_M, XYZ, 1);

        

LSM303DLHC_Read(MAG_I2C_ADDRESS,LSM303DLHC_OUT_X_L_M, XYZ+1, 1);

        

LSM303DLHC_Read(MAG_I2C_ADDRESS,LSM303DLHC_OUT_Y_H_M, XYZ+2, 1);

        

LSM303DLHC_Read(MAG_I2C_ADDRESS,LSM303DLHC_OUT_Y_L_M, XYZ+3, 1);

        

LSM303DLHC_Read(MAG_I2C_ADDRESS,LSM303DLHC_OUT_Z_H_M, XYZ+4, 1);

        

LSM303DLHC_Read(MAG_I2C_ADDRESS,LSM303DLHC_OUT_Z_L_M, XYZ+5, 1);

        

convertedData_Mag[0] = (float) ((int16_t)(((uint16_t)XYZ[0] << 8) + XYZ[1]))/16;

        

convertedData_Mag[1] = (float) ((int16_t)(((uint16_t)XYZ[2] << 8) + XYZ[3]))/16;

        

convertedData_Mag[2] = (float) ((int16_t)(((uint16_t)XYZ[4] << 8) + XYZ[5]))/16;

}

I'm not sure if I did the reading function properly. I'm getting data, but I don't know how to convert it further to be able to calculate the azimuth. Should I divide them by sensitivity or what? I can't find such an information in the datasheet

#lsm303dlhc
4 REPLIES 4
Miroslav BATEK
ST Employee
Posted on May 22, 2018 at 20:48

To convert raw data into acceleration in g and magnetic field in gauss you have use the sensitivity. defined in datasheet.

Basicaly for acceleration you multiply the raw value by sensitivity (LA_So) for magnetometer you divide the raw value (M_GN).

0690X0000060KtcQAE.png

To calculate heading to the magnetic North you can use our

http://www.st.com/resource/en/user_manual/dm00396079.pdf

library which you can find in

http://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-expansion-packages/x-cube-mems1.html

package.
Mark van Matt
Associate II
Posted on May 23, 2018 at 15:40

Thank you for your response.

I have divided the raw data from the magnetometer

convertedData_Mag[0] = (float) ((int16_t) ((XYZ[0] << 8) + XYZ[1]))/LSM303DLHC_M_SENSITIVITY_XY_1_9Ga;

convertedData_Mag[1] = (float) ((int16_t) ((XYZ[2] << 8) + XYZ[3]))/LSM303DLHC_M_SENSITIVITY_XY_1_9Ga;

convertedData_Mag[2] = (float) ((int16_t) ((XYZ[4] << 8) + XYZ[5]))/LSM303DLHC_M_SENSITIVITY_Z_1_9Ga;

and multiplied the raw data from accelerometer (I selected 2g sensitivity)

for(i=0;i<3;i++)

{

        convertedData_Acc[i] = (float) ((int16_t) ((XYZ[2*i+1] << 8) + XYZ[2*i])) * 2.0f;

}

and I'm getting such results

0690X0000060KuaQAE.png

I think there's something wrong with accelerometer. Magnetometers values seem to be good.

Posted on May 23, 2018 at 15:42

I've added another question below instead of adding it in reply to your comment

Posted on May 25, 2018 at 09:29

The accelerometer value need to be divided by 16, because it is 12-bit value left adjusted in 16-bit register.

And I see another problem in your latest code, you have case the type of XYZ to uint16_t before you do the shift (<<8) as you did it in the first version.