This guide to the LSM9DS1 was written with help of the datasheet, offical STMicro driver source, and other libraries. It is for low level troubleshooting and use of this sensor. Gemini 2.5 pro was used to help summarize and cross-check.
(A Merged Technical Reference Based on the Official ST Driver and Community Examples)
This guide provides a robust, end-to-end technical reference for Arduino developers who wish to perform a direct I2C implementation of the LSM9DS1. It combines the safety patterns from the official STMicroelectronics C driver with practical code examples and register maps, creating a single, authoritative resource for your project.
Getting the hardware right is the first and most critical step. Incorrect wiring is the most common source of initialization failure.
-
I2C Addresses: The LSM9DS1 acts as two independent I2C devices. The addresses are set by the
SDO_A/G
andSDO_M
pins.- Accelerometer/Gyroscope (AG):
0x6A
ifSDO_A/G
is connected to GND (default on many boards).0x6B
ifSDO_A/G
is connected to VDD.
- Magnetometer (M):
0x1C
ifSDO_M
is connected to GND (default on many boards).0x1E
ifSDO_M
is connected to VDD.
- Accelerometer/Gyroscope (AG):
-
Essential I2C Enable Pins: To use the I2C interface, the SPI Chip Select (CS) pins must be pulled HIGH to disable SPI mode.
CS_A/G
-> connect to VDD (3.3V).CS_M
-> connect to VDD (3.3V).- Troubleshooting: If you get no response on the I2C bus, this is the most likely cause. Most breakout boards handle this for you, but it is mandatory if you are using the bare chip.
-
Voltage: The LSM9DS1 is a 3.3V device. Do not connect its
VDD
,VDDIO
,SCL
, orSDA
pins to 5V. This can permanently damage the sensor. Use a logic level shifter if you are using a 5V microcontroller like an Arduino Uno. -
I2C Pull-up Resistors: While the Arduino
Wire
library has internal pull-ups, they are often too weak for reliable communication. For stable operation, it is highly recommended to use external 4.7kΩ pull-up resistors on theSCL
andSDA
lines, connected to your 3.3V supply.
Here are the essential registers you will interact with.
Accelerometer and Gyroscope (AG) - I2C Addr: 0x6A
or 0x6B
Name | Address | Description |
---|---|---|
WHO_AM_I |
0x0F |
Device ID. Reads 0x68 . |
CTRL_REG1_G |
0x10 |
Gyroscope control (ODR, Full-Scale). |
STATUS_REG |
0x17 |
Data-ready flags for AG. |
OUT_X_L_G |
0x18 |
Gyroscope X-axis low byte. |
CTRL_REG6_XL |
0x20 |
Accelerometer control (ODR, Full-Scale). |
CTRL_REG8 |
0x22 |
BDU, Reset, and other controls. |
OUT_X_L_XL |
0x28 |
Accelerometer X-axis low byte. |
FIFO_CTRL |
0x2E |
FIFO control and mode settings. |
FIFO_SRC |
0x2F |
FIFO status (unread samples, full, empty). |
Magnetometer (M) - I2C Addr: 0x1C
or 0x1E
Name | Address | Description |
---|---|---|
WHO_AM_I_M |
0x0F |
Device ID. Reads 0x3D . |
CTRL_REG1_M |
0x20 |
Magnetometer control (ODR, performance). |
CTRL_REG2_M |
0x21 |
Full-Scale, Reset. |
CTRL_REG3_M |
0x22 |
Operating mode (Continuous, Power-down). |
CTRL_REG5_M |
0x24 |
Block Data Update (BDU). |
STATUS_REG_M |
0x27 |
Data-ready flags for M. |
OUT_X_L_M |
0x28 |
Magnetometer X-axis low byte. |
Follow this official driver-based sequence in your setup()
function to guarantee the sensor starts in a known, stable state.
Step 1: Verify Communication with WHO_AM_I
This is your first-pass diagnostic. Before any configuration, confirm you can talk to both devices.
// In your setup()
Wire.begin();
// Check Accel/Gyro WHO_AM_I
uint8_t who_am_i_ag;
readRegister(LSM9DS1_AG_ADDRESS, LSM9DS1_WHO_AM_I, &who_am_i_ag);
if (who_am_i_ag != 0x68) {
Serial.println("AG WHO_AM_I check failed. Halting.");
while(1);
}
// Check Mag WHO_AM_I
uint8_t who_am_i_m;
readRegister(LSM9DS1_M_ADDRESS, LSM9DS1_WHO_AM_I_M, &who_am_i_m);
if (who_am_i_m != 0x3D) {
Serial.println("Mag WHO_AM_I check failed. Halting.");
while(1);
}
- Troubleshooting: If this fails, your circuit is wrong (check I2C addresses, CS pins, wiring) or the I2C bus is non-functional.
Step 2: Reset The Device (Driver Best Practice) The ST driver resets the device to ensure a clean state. You must wait for the reset bit to clear itself to confirm completion.
- Accel/Gyro Reset: Set
SW_RESET
bit inCTRL_REG8
(0x22), then poll until it reads0
. - Magnetometer Reset: Set
REBOOT
bit inCTRL_REG2_M
(0x21), then poll until it reads0
.
Step 3: Enable Block Data Update (BDU) This is critical for data integrity. BDU prevents the sensor's high and low output bytes from being updated mid-read, which would corrupt your data. Always enable this.
// Enable BDU for Accel/Gyro
writeRegister(LSM9DS1_AG_ADDRESS, LSM9DS1_CTRL_REG8, 0x44); // BDU enabled, register auto-increment enabled
// Enable BDU for Mag
writeRegister(LSM9DS1_M_ADDRESS, LSM9DS1_CTRL_REG5_M, 0x40); // BDU enabled
Step 4: Configure and Enable Sensors The sensors are off by default. To enable them, you must configure their Output Data Rate (ODR) and operating mode.
// Example: Enable Gyro at 119 Hz, 245 dps
writeRegister(LSM9DS1_AG_ADDRESS, LSM9DS1_CTRL_REG1_G, 0x60); // 119 Hz ODR, 245 dps
// Example: Enable Accel at 119 Hz, 2g
writeRegister(LSM9DS1_AG_ADDRESS, LSM9DS1_CTRL_REG6_XL, 0x60); // 119 Hz ODR, 2g
// Example: Enable Mag at 80 Hz, continuous mode
writeRegister(LSM9DS1_M_ADDRESS, LSM9DS1_CTRL_REG1_M, 0x1C); // Temp comp disabled, high-perf mode, 80 Hz ODR
writeRegister(LSM9DS1_M_ADDRESS, LSM9DS1_CTRL_REG3_M, 0x00); // Continuous-conversion mode
The most robust way to get live data is to separate checking for new data from reading the data.
Part A: Poll the Status Register for Data-Ready Flags Do not read the output registers blindly. First, check the status register to see if a fresh sample is available.
XLDA
bit (bit 0) inSTATUS_REG
(0x17) -> New Accelerometer dataGDA
bit (bit 1) inSTATUS_REG
(0x17) -> New Gyroscope dataZYXDA
bit (bit 3) inSTATUS_REG_M
(0x27) -> New Magnetometer data
Part B: Read the Multi-Byte Sensor Data Once a data-ready flag is confirmed, read all 6 bytes for that sensor in a single I2C transaction.
// In your loop()
uint8_t status_ag;
readRegister(LSM9DS1_AG_ADDRESS, LSM9DS1_STATUS_REG, &status_ag);
if (status_ag & 0x01) { // Check XLDA bit
uint8_t data_buf[6];
readRegisters(LSM9DS1_AG_ADDRESS, LSM9DS1_OUT_X_L_XL, 6, data_buf);
int16_t ax = (int16_t)(data_buf[1] << 8 | data_buf[0]);
int16_t ay = (int16_t)(data_buf[3] << 8 | data_buf[2]);
int16_t az = (int16_t)(data_buf[5] << 8 | data_buf[4]);
// Now convert raw data to g's
}
if (status_ag & 0x02) { // Check GDA bit
// ... similar read from OUT_X_L_G (0x18) ...
}
uint8_t status_m;
readRegister(LSM9DS1_M_ADDRESS, LSM9DS1_STATUS_REG_M, &status_m);
if (status_m & 0x08) { // Check ZYXDA bit
// ... similar read from OUT_X_L_M (0x28) ...
}
- Troubleshooting:
- Data never updates: You are not polling the status registers.
- Data is
0
or-1
: This signals a failed I2C read. Check wiring and addresses. - Data is nonsensical: You forgot to enable BDU, or you are misinterpreting the two's complement data.
The raw int16_t
values must be scaled by their sensitivity to get meaningful units like g
, dps
, and gauss
. The sensitivity depends on the full-scale range you configured.
Accelerometer Sensitivity (mg/LSB)
Full-Scale | Sensitivity |
---|---|
±2 g | 0.061 |
±4 g | 0.122 |
±8 g | 0.244 |
±16 g | 0.732 |
float acceleration_g = raw_value * sensitivity / 1000.0; |
Gyroscope Sensitivity (mdps/LSB)
Full-Scale | Sensitivity |
---|---|
245 dps | 8.75 |
500 dps | 17.50 |
2000 dps | 70.00 |
float angular_rate_dps = raw_value * sensitivity / 1000.0; |
Magnetometer Sensitivity (mgauss/LSB)
Full-Scale | Sensitivity |
---|---|
±4 gauss | 0.14 |
±8 gauss | 0.29 |
±12 gauss | 0.43 |
±16 gauss | 0.58 |
float magnetic_field_gauss = raw_value * sensitivity / 1000.0; |
The LSM9DS1 includes a 32-slot FIFO buffer that can store accelerometer and gyroscope readings. This is extremely useful for power saving, as the microcontroller can sleep and wake up only when the buffer is full or reaches a certain threshold, then read all the samples in a burst.
- To Enable: Set the
FIFO_EN
bit inCTRL_REG9
(0x23). - To Configure: Use the
FIFO_CTRL
register (0x2E) to set the mode (e.g., Bypass, FIFO mode, Continuous mode) and the watermark threshold. - To Check Status: Read the
FIFO_SRC
register (0x2F) to see how many unread samples (FSS
bits) are in the buffer. TheFTH
bit will be set when the number of samples meets your watermark threshold. - To Read: Read from the same output registers (e.g.,
OUT_X_L_G
). Each read from the output registers will pull the next value from the FIFO instead of the live sensor value.