2017-04-19 05:25 AM
Hi all,
I'm trying to interface a LSM303AGR, to get the magnetometer and accelerometer values in I2C.
The component is responding well to whoami requests (both compass and magnetometer parts), I manage to get mag values but the accelerometer values seems to be stuck.
Here are my init parameters:
/*
REBOOT
ACCELEROMETER
MEMORY
CONTENT
*/
I2C_Write_reg
(
I2C2
,
I2C_LSM3_ACC_ADRESS
<<
1
,
I2C_LSM3_CTRL_REG5_A
,
0x80
);
RTC_wait_ms
(
6
);
/*
REBOOT
MAGNETOMETER
MEMORY
CONTENT
*/
I2C_Write_reg
(
I2C2
,
I2C_LSM3_MAG_ADRESS
<<
1
,
I2C_LSM3_CFG_REG_A_M
,
0x40
);
RTC_wait_ms
(
6
);
(
void
)
I2C_Read
(
I2C2
,
I2C_LSM3_ACC_ADRESS
<<
1
,
0
,
I2C_LSM3_WHO_AM_I_ACC
,
&
whoamiacc
,
1
);
if
(
whoamiacc
!=
0x33
)
FAIL(
'LSM303AGR
accelerometer
side
isn't
responding'
);
else
{
/*
ACCELEROMETER
INITIALIZATIONS
*/
I2C_Write_reg
(
I2C2
,
I2C_LSM3_ACC_ADRESS
<<
1
,
I2C_LSM3_CTRL_REG1_A
,
0x57
);
I2C_Write_reg
(
I2C2
,
I2C_LSM3_ACC_ADRESS
<<
1
,
I2C_LSM3_CTRL_REG2_A
,
0x00
);
I2C_Write_reg
(
I2C2
,
I2C_LSM3_ACC_ADRESS
<<
1
,
I2C_LSM3_CTRL_REG3_A
,
0x00
);
I2C_Write_reg
(
I2C2
,
I2C_LSM3_ACC_ADRESS
<<
1
,
I2C_LSM3_CTRL_REG4_A
,
0x98
);
//BDU
ON
+/-4G
Range
and
High
res
ON
I2C_Write_reg
(
I2C2
,
I2C_LSM3_ACC_ADRESS
<<
1
,
I2C_LSM3_CTRL_REG5_A
,
0x00
);
}
(
void
)
I2C_Read
(
I2C2
,
I2C_LSM3_MAG_ADRESS
<<
1
,
0
,
I2C_LSM3_WHO_AM_I_MAG
,
&
whoamimag
,
1
);
if
(
whoamimag
!=
0x40
)
FAIL(
'LSM303AGR
magnetometer
side
isn't
responding'
);
else
{
/*
MAGNETOMETER
INITIALIZATIONS
*/
I2C_Write_reg
(
I2C2
,
I2C_LSM3_MAG_ADRESS
<<
1
,
I2C_LSM3_CFG_REG_A_M
,
0x8C
);
//
I2C_Write_reg(I2C2,I2C_LSM3_MAG_ADRESS
<<
1,I2C_LSM3_CFG_REG_B_M,0x02);
}
My reading fonction for the accelerometer is the following:
uint8_t
drdy
=
0
;
uint8_t
x_accel
[
2
]
=
{
0
};
uint8_t
y_accel
[
2
]
=
{
0
};
uint8_t
z_accel
[
2
]
=
{
0
};
I2C_Read
(
I2C2
,
I2C_LSM3_ACC_ADRESS
<<
1
,
0
,
I2C_LSM3_STATUS_REG_A
,
&
drdy
,
1
);
if
((
drdy
&
0x01
)
==
0x01
)
I2C_Read
(
I2C2
,
I2C_LSM3_ACC_ADRESS
<<
1
,
0
,
I2C_LSM3_OUT_Y_L_A
,
y_accel
,
2
);
if
((
drdy
&
0x02
)
==
0x02
) I2C_Read
(
I2C2
,
I2C_LSM3_ACC_ADRESS
<<
1
,
0
,
I2C_LSM3_OUT_Z_L_A
,
z_accel
,
2
);
if
((
drdy
&
0x04
)
==
0x04
)
I2C_Read
(
I2C2
,
I2C_LSM3_ACC_ADRESS
<<
1
,
0
,
I2C_LSM3_OUT_X_L_A
,
x_accel
,
2
);
I get the exact same answer at every reading:
x_accel
[
0
]
= 0xA0
x_accel
[
1
]
= 0xA0
y_accel
[
0
]
= 0xC0
y_accel
[
1
]
= 0xC0
z_accel
[
0
]
= 0x40
z_accel
[
1
]
= 0x40
Am I doing something wrong in the initializations? I would like the accelerometer to be in +/-4G range, 100Hz, without FIFO and in High res mode.
The I2C_Read function seems to work well, my function reading the magnetometer works fine.
Thank you!
2017-04-19 12:25 PM
I think, the address of output registers is not automaticaly incremented, when you are reading multiple bytes. So you are reading only the low byte and due to enabled BDU, the data are not updated. Please check chapter 6.1.1 in datasheet.
If the MSb of the
register address
is ‘1’, the register address is automatically increased to allow multiple data read/writes.You can also check only the ZYXDA bit in status register a then read data for all axis in one multiple read, read 6bytes starting from OUT_X_L_A (28h).
2017-04-20 01:03 AM
I think if the High and Low bytes are the same, then you are reading the same register.
Can you please set the MSB bit of registers address to one, so I2C_LSM3_OUT_X_L_A = 0xA8, I2C_LSM3_OUT_Y_L_A = 0xAA, I2C_LSM3_OUT_Y_L_A = 0xAC to be sure the address will be incremented.
Another option how to confirm my theory is disable BDU in CTRL_REG4, then the values should change even if you don't read High byte of output register.
2017-04-20 02:32 AM
Hi Miroslav,
Thank you for your time. My function to read the magnetometer values is very similar to the one I use for the accelerometer:
void
read_LSM303AGR_mag
(
float
*
MAG_XYZ_AXIS
){
int16_t
MAG_XYZ_AXIS_raw
[
3
]
=
{
0
};
uint8_t
drdy
=
0
;
uint8_t
x_mag
[
2
]
=
{
0
};
uint8_t
y_mag
[
2
]
=
{
0
};
uint8_t
z_mag
[
2
]
=
{
0
};
I2C_Read
(
I2C2
,
I2C_LSM3_MAG_ADRESS
<<
1
,
0
,
I2C_LSM3_STATUS_REG_M
,
&
drdy
,
1
);
if
((
drdy
&
0x01
)
==
0x01
){
I2C_Read
(
I2C2
,
I2C_LSM3_MAG_ADRESS
<<
1
,
0
,
I2C_LSM3_OUTX_L_REG_M
,
x_mag
,
2
);
MAG_XYZ_AXIS_raw
[
0
]=
(
x_mag
[
1
]
<<
8
)
|
x_mag
[
0
];
/*
Convert
to
Gauss
*/
MAG_XYZ_AXIS
[
0
]
=
(
float
)
MAG_XYZ_AXIS_raw
[
0
]*
1.5
/
1000
;
}
if
((
drdy
&
0x02
)
==
0x02
){
I2C_Read
(
I2C2
,
I2C_LSM3_MAG_ADRESS
<<
1
,
0
,
I2C_LSM3_OUTY_L_REG_M
,
y_mag
,
2
);
MAG_XYZ_AXIS_raw
[
1
]=
(
y_mag
[
1
]
<<
8
)
|
y_mag
[
0
];
/*
Convert
to
Gauss
*/
MAG_XYZ_AXIS
[
1
]
=
(
float
)
MAG_XYZ_AXIS_raw
[
1
]*
1.5
/
1000
;
}
if
((
drdy
&
0x04
)
==
0x04
){
I2C_Read
(
I2C2
,
I2C_LSM3_MAG_ADRESS
<<
1
,
0
,
I2C_LSM3_OUTZ_L_REG_M
,
z_mag
,
2
);
MAG_XYZ_AXIS_raw
[
2
]=
(
z_mag
[
1
]
<<
8
)
|
z_mag
[
0
];
/*
Convert
to
Gauss
*/
MAG_XYZ_AXIS
[
2
]
=
(
float
)
MAG_XYZ_AXIS_raw
[
2
]*
1.5
/
1000
;
}
}
This one is working perfectly, the address is auto-incremented and I get correct results. I tried to only read once the ZYXDA bit, and do one reading per byte as it wasn't auto-incremented, and I get the same result as above (same value for H & L bytes of each axis). I don't really get what's happening there, it looks like the sensor is stuck and always send the same value, but it should be at least a different values for High and Low bytes.