Communication between LSM6DSOX/MPU6500 and Raspberry PI through SPI

Aditya Prakash
7 min readFeb 22, 2024

--

LSM6DSOX is an IMU provided by STMicroelectronics which has 6 DOF — 3 degrees each of linear acceleration and angular velocity. It has both I2C and SPI communication. In this article, we discuss about how to communicate with the IMU from raspberry pi through SPI communication. One of the major reasons, I am writing this article is because of lack of resources on internet regarding the same.

Note: MPU6500 also provides I2C and SPI communication and similar process can be used for the communication between MPU6500 and Raspberry PI through SPI. However, the corresponding registers will change which can be checked from the register map provided along with the sensor.

Configuring Raspberry PI

I will be using Raspberry PI model 4B for the same. Before starting with the connection phase, we need to make sure that SPI communication is enabled in Raspberry PI.

To enable SPI on the Raspberry PI, one can use ``rasp-config``. Here is the link to help with it. After activating SPI on Raspberry PI, to make sure that SPI is working perfectly, follow the steps given in following link: spidev-test.

After successfully configuring the raspberry PI, we move for the connection.

Connection

To connect the LSM6DSOX IMU to the Raspberry PI through SPI, we will use the following pins for the SPI communication”

For the LSM6DSOX:

  • SDA ( Serial Data) pin, which acts as SDI (Serial Data In) when SPI is used.
  • SCL (Serial Click) pin for SPI clock
  • CS (Chip Select) pin
  • DO pin, for Serial Data output.

For Raspberry PI:

  • MOSI (Master Out Slave In): Pin 19 (MOSI0)
  • MISO (Master In Slave Out): Pin 21 (MISO0)
  • SCLK (Serial Clock): Pin 23 (SCLK0)
  • CS: Pin 24 (CE0)/Pin 26 (CE1) (we need to any one of them)

Here are the connections you need to make:

  • SDA (LSM6DSOX) — MOSI0 (Pi4)
  • DO (LSM6DSOX)— MISO0 (Pi4)
  • SCL (LSM6DSOX)— SCLK0 (Pi4)
  • CS (LSM6DSOX) — CE0/CE1 (Pi4)

With this the hardware setup is done. Note that similar connections happens for MPU6500.

Software

Based on the choice of programming language we can use different libraries. It is suggested that to check that communication is working perfectly between the raspberry pi and IMU, use ``spidev`` library of python as it provides an easy interface between the same. In this article, firstly I will help you verify with the help of ``spidev`` if everything is working perfectly and then we go to writing the complete using C++ to get the final output from IMU.

spidev

To give an overview of spidev library, it provides a class for changing the parameters of SPI communication and then function to read and write registers.

import spidev
spi = spidev.SpiDev()
spi.open(0,0) # Open SPI bus 0, device (CS) 0, here based on the CS pin you choose, the value of device changes between 0 and 1
spi.mode = 0b11
spi.max_speed_hz = 5000000

Here, not that the parameters varies for different IMU, the SPI mode for LSM6DSOX is 3 (0b11). Make sure to check the same for MPU6500. Also, the ``max_speed_hz`` is an important parameter. In the datasheet, the max value for LSM6DSOX is 10 MHz. However, using that value did not work for me. Therefore, I am using 5000000.

Reading a register

def read_register(spi, register):
response = spi.xfer2([register | 0x80, 0x00])
return response[1]

To read or write a register, we use ``xfer2()`` function provided by the ``spidev`` module. In the function, we pass a byte array. The first element of the array is register address with Bit 7 set to indicate read operation. The remaining size of the array defines how much data you want to read and is initialized with 0x00. Note that this kinda of setting is common in all languages. So, in C++ too, we will be using a function that takes a byte array and uses it in similar manner for communication.

Writing a register

def write_register(spi, register, value):
spi.xfer2([register, value])

Similar to read operation, we use ``xfer2()`` function to write to a register in which, the first element of byte array is the register address and the second element of write array is the value to write.

WHO_AM_I register

After setting up hardware, the first thing to do to check if the communication is working properly or not is to read the “WHO_AM_I” register. For LSM6DSOX, the register address is: 0x0F and the value we should get is 0x6C. Note that these values will be different for MPU6500 and can be accessed through the datasheet.

who_am_i = read_register(spi, 0x0F)
print("WHO_AM_I:", who_am_i)

If you are getting zeros or something other than 0x6C, then it means that the communication is not working properly. Check you hardware connection as well as check is the spi parameters are set correctly. Try playing with mode and speed parameters and find the correct through trial and error, in case the datasheet values are not working efficiently.

Configuring Gyro and Accelerometer Subsystem

To enable the gyroscope and accelerometer on the LSM6DSOX, we need to write to specific control registers of the LSM6DSOX. This also sets the different configuration of the gyroscope and accelerometer data.

Accelerometer Configurations
Gyroscope Configurations

Check the control registers and the value to be written from the datasheet. For LSM6DSOX:

  • Accelerometer Control register: 0x10 (CTRL1_XL)
  • Gyroscope Control register: 0x11 (CTRL2_G)

We write 0x40 to both the register, which means

  • Accelerometer: 104 Hz, 2g, no high-performance
  • Gyroscope: 104 Hz, 250 dps, no high-performance

This configuration value should be changed based on your need.

# LSM6DSOX registers
CTRL1_XL = 0x10 # Accelerometer control register
CTRL2_G = 0x11 # Gyroscope Control register

write_register(spi, CTRL1_XL, 0x40)
write_register(spi, CTRL2_G, 0x40)

#Verifying by reading back from the same registers
acc_settings = read_register(spi, CTRL1_XL)
gyro_settings = read_register(spi, CTRL2_G)
print(f"Accelerometer settings: {hex(acc_settings)}")
print(f"Gyroscope Settings: {hex(gyro_settings)}")

The above code writes and checks the control registers.

Reading Gyro and Accln values

Note that the gyro and accln values along each axes are obtained from two registers, one gives LSB (low significant bit) and the other gives MSB (most significant bit). And we combine the values to get the actual value.

To read the gyroscope z values, we use the registers: OUTZ_L_G (low byte) and OUTZ_H_G (high byte).

def read_gyro_z(spi):
OUTZ_L_G = 0x26
OUTZ_H_G = 0x27
z_low = read_register(spi, OUTZ_L_G)
z_high = read_register(spi, OUTZ_H_G)
z_combined = (z_high << 8) | z_low
return z_combined

The above function reads the value of the gyroZ. Note that this will not be in the unit of deg/s and will need to be scaled based on the datasheet. If you are not getting zeros at this point, everything is working perfectly and you are ready to use your IMU for getting the angle rates and accln values in actual units. That will be in the next part.

Setting different configurations of Gyroscope and Accelerometer

Accelerometer Configuration

Here as mentioned in the Table49, each bit decides different parameters. Second bit changes the LPF2_XL_EN, which decides the filtering we will choose. I have set it to 1, so I will be using LPF2 second filtering stage.

The full-scale selection bits (FS1_XL, FS0_XL) are important as it decides the range of the measurement. Note that the accelerometer data is measured in term of “g”. So, what range of acceleration we are dealing with decides these two bits. For normal use, 2g is sufficient. So, we will set this bit to 00 (which is default). For converting from the accelerometer data to “g”, we use the following sensitivity table:

The remaining 4 bits decides the sampling rate which you can choose based on your need. Based on this we write the value in binary form as:

0b10100010

This is easier than converting to hex or decimal cause we explicitly know what each bits are set to.

Note that MPU6500 acceleration config input is a bit different without this much complexity. Please consult the datasheet to check the proper bit types and the sensitivity.

Gyroscope Configuration

Similar to accelerometer control config, we can set the gyroscope configuration using the following. Set the second bit to 0 if you want to use range other than +-125 dps. The sensitivity table is given:

https://www.flux.ai/ is a very tool to use when working on Electronics. After searching endlessly on internet, I found the appropriate solution here.

The C++ code for the same has been discussed in another article.

Enjoy !!

--

--

No responses yet