1

I am trying to debug why the magnetic sensor of my MPU9250/6500 9-Axis 9 DOF 16 Bit Gyroscope Acceleration Magnetic Sensor IIC/SPI won't connect to my Raspberry Pi 4+, but all the other sensors will. I am using the MPU-9250-Sensors-Data-Collect API which is a wrapper for the SMBUS2 package. Given that there seems to be only one master address and only two wires connecting things, I would think that if the problem was something physical, it would either work or not work, except that this sensor is a multi-chip module consisting of two dies integrated into a single QFN package. I did a bad soldering job on my first one of these sensors and it just wouldn't connect. I got a new one and it is detected by my RPi and works except for the magnetic sensor (the most relevant part of my project).

So. my question is, is this a hardware thing after all, or is there the possibility of it being a software problem?

I can't see any problems with the physical unit:

Photo of my setup

Code

    import sys
    sys.path.append('/home/tor/robot/MPU-9250-Sensors-Data-Collect/MPU-9250-Sensors-Data-Collect/mpu9250_jmdev')
    from registers import *
    from mpu_9250 import MPU9250
    import time
    import logging
    ##################################################
    # Create                                         #
    ##################################################
    mpu = MPU9250(
        address_ak=AK8963_ADDRESS, 
        address_mpu_master=MPU9050_ADDRESS_68, # In 0x68 Address
        address_mpu_slave=None, 
        bus=1, 
        gfs=GFS_1000, 
        afs=AFS_8G, 
        mfs=AK8963_BIT_16, 
        mode=AK8963_MODE_C8HZ)
    ##################################################
    # Configure                                      #
    ##################################################
    mpu.configure() # Apply the settings to the registers.
    ##################################################
    # Show Values                                    #
    ##################################################
    while True:
        print("|.....MPU9250 in 0x68 Address.....|")
        print("Accelerometer", mpu.readAccelerometerMaster())
        print("Gyroscope", mpu.readGyroscopeMaster())
        print("Magnetometer", mpu.readMagnetometerMaster())
        print("Temperature", mpu.readTemperatureMaster())
        print("\n")
        time.sleep(1)

Results

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 97, in configure
    self.configureAK8963(self.mfs, self.mode)
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 233, in configureAK8963
    self.writeAK(AK8963_CNTL1, 0x00, 0.1)
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 1013, in writeAK
    self.bus.write_byte_data(self.address_ak, register, value)
  File "/usr/local/lib/python3.8/dist-packages/smbus2/smbus2.py", line 458, in write_byte_data
    ioctl(self.fd, I2C_SMBUS, msg)
OSError: [Errno 121] Remote I/O error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 97, in configure
    self.configureAK8963(self.mfs, self.mode)
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 233, in configureAK8963
    self.writeAK(AK8963_CNTL1, 0x00, 0.1)
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 1013, in writeAK
    self.bus.write_byte_data(self.address_ak, register, value)
  File "/usr/local/lib/python3.8/dist-packages/smbus2/smbus2.py", line 458, in write_byte_data
    ioctl(self.fd, I2C_SMBUS, msg)
OSError: [Errno 121] Remote I/O error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "sensorTest.py", line 13, in <module>
    mpu.configure() # Apply the settings to the registers.
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 102, in configure
    self.configure(retry - 1)
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 102, in configure
    self.configure(retry - 1)
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 105, in configure
    raise err
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 97, in configure
    self.configureAK8963(self.mfs, self.mode)
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 233, in configureAK8963
    self.writeAK(AK8963_CNTL1, 0x00, 0.1)
  File "/usr/local/lib/python3.8/dist-packages/mpu9250_jmdev/mpu_9250.py", line 1013, in writeAK
    self.bus.write_byte_data(self.address_ak, register, value)
  File "/usr/local/lib/python3.8/dist-packages/smbus2/smbus2.py", line 458, in write_byte_data
    ioctl(self.fd, I2C_SMBUS, msg)
OSError: [Errno 121] Remote I/O error

If I put try/except blocks around smbus2.py (ioctl(self.fd, I2C_SMBUS, msg)), I can get data for the other three sensors:

|.....MPU9250 in 0x68 Address.....|
Accelerometer [-1.210205078125, -8.0, -8.0]
Gyroscope [43.9453125, -1.373291015625, -21.270751953125]
[OSError(121, 'Remote I/O error'),
 <smbus2d.SMBus object at 0xffff8d0f20a0>,
 12,
 3,
 7,
 None]
Magnetometer [0.0, 0.0, 0.0]
Temperature 24.258753407014705

What the offending function looks like:

    def read_i2c_block_data(self, i2c_addr, register, length, force=None):
        """
        Read a block of byte data from a given register.

        :param i2c_addr: i2c address
        :type i2c_addr: int
        :param register: Start register
        :type register: int
        :param length: Desired block length
        :type length: int
        :param force:
        :type force: Boolean
        :return: List of bytes
        :rtype: list
        """
        if length > I2C_SMBUS_BLOCK_MAX:
            raise ValueError("Desired block length over %d bytes" % I2C_SMBUS_BLOCK_MAX)
        self._set_address(i2c_addr, force=force)
        msg = i2c_smbus_ioctl_data.create(
            read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_I2C_BLOCK_DATA
        )
        msg.data.contents.byte = length
        try:
            ioctl(self.fd, I2C_SMBUS, msg)
        except Exception as e:
            if hasattr(e, 'message'):
                print(e.message)
            pprint([e, self, i2c_addr, register, length, force])
        return msg.data.contents.block[1:length + 1]

The sensor is readable, however:

tor@tor:~/robot$ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --        

Thanks!

New contributor
SomeoneElse is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
3
  • Could you clarify. Does the sensor appear on the bus? If so what number? If so have you tried an alternative method of reading the sensor? – joan May 4 at 15:20
  • As I show in my question, the sensor is being picked up because when I do i2cdetect -y 1, it is #68. – SomeoneElse May 4 at 17:53
  • So I just got another sensor just like the one I had and it has the same problem, I'm pretty sure it is a software problem but I am new to using I2C and so, as of yet, I have yet to have worked out what the problem is. – SomeoneElse May 4 at 19:50
1

Question

Problem on using smBUS 2 block read/write functions.


Answer

1. Discussion on I2C reading/writing a block of data, smbus and smbus2, etc

Ah, your remind me one important thing. Some two years ago when I tried to use smBus block read/write (in my MCP23017 Micky Mouse toy project), I found the "bus stretch" thing is not implemented, so block read/write won't work.

One quick and dirty workaround is to lower i2c bus speed to as low as 50kHz (as recommended by one MagPi writers.

The same MagPi issue also recommends to use Borsh 9-DOF, not sure if also built in the Rpi's official Sensor Hat.

One other thing is that I don't seem to find you importing smbus. Are you using AdaFruit's libraries? I heard that AdaFruit Circuit Python is not 100% compatible to Rpi, so their might be teething problems not yet solved.

Another suggestion is to use 1-DOF Magneto modules, then at least you won't have three separate I2C devices (and perhaps more?) sitting on the same bus, overloading bus beyond the smbus 400pF limit.


References

(1) Intelligent-Vehicle-Perception - MPU9250 (MPU6500 + AK8963) I2C Driver in Python for Raspbery PI

(2) AliExpress Magnetometer Catalog

(3) LSM303DLHC Ultra-compact high-performance eCompass modu le 3D accelerometer and 3D magnetometer - ST

(4) GY-511 LSM303DLHC 3-DOF Magnetometer / Digital Compass sensor - ¥14

(5) GY-271M 3-DOF Magnetometer (replace HMC5883L HMC5983 GY-282 283 GY-273) - ¥19


Appendices

Appendix A - List of MMES Magnetometer Modules

  1. HMC5883L GY-271/273 Magnetometer Compass Module

  2. LSM303DLHC GY511 Magnetometer Compass Module

  3. HSCDTD008A Magnetometer Compass Module

  4. RM3100 Magnetometer Compass Module


13
  • 1
    I'm using the API mentioned in the beginning, which in turn uses the python SMBus2 package ( pypi.org/project/smbus2 ). I might just cut my losses from my time spent debugging this unit and take your suggestion to get something that is just a magnetic sensor because that is really all I think I need for my use case. – SomeoneElse May 4 at 21:10
  • 1
    @SomeoneElse, OMG, I was not aware that you are using smBus2. Actually when I found the limitation of smBus of no bus stretching and therefore no block read/write, and that for Rpi3B+ stretch, there is a Rpi Foundation system bug that you cannot adjust I2C bus speed up or down (contrary to official document) except the flat rate of 100kHz. I was very disappointed and so googled for a turnaround. So I found smBUS2, and I thought that it might save my life. So I evaluated smBUS2, / to continue, ... – tlfong01 May 5 at 0:42
  • 1
    Before I let you know my evaluation results of smBUS2, can you first tell me (1) Why you use smBUS2 and not standard default smBUS? (3) Have you tried other SPI alternatives, such as SPIpy? (3) What was your general feeling or first impress when switching to smBUS2, and how you feel about their mnaual? – tlfong01 May 5 at 0:46
  • 1
    Oh, I'm using smBUS2 because that is what is used by the API I am using ( github.com/Intelligent-Vehicle-Perception/… ) I am going to try another API, if I can find one that seems complete. I'm fairly new to I2C, so I think I will need to read up more on how it works. The issue is that there is still the chance that it is a physical problem (it could be the connecting wires for example). Anyway thanks for your suggestions! – SomeoneElse May 5 at 2:32
  • 1
    (1) Thank you for your clarification and confirmation on smBUS2. (2) Your IVP(Intelligent-Vechicle-Perception)API wraps on smBUS2 and it is very likely that they also solves any teething problem about smBUS2, but not sure if they are compatible with Rpi4B buster python 3.7.3. (3) Your mpu9050 9-DOF with 4 MEMS sensor on one module is too complicated for newbies to debug. The magnetometer is decoupled from the other 3 sensors, so for newbies I would recommend to start off with the very popular 1-DOF HMC5883L Magnetometer Module for which you can find many Arduino references and tutorials. – tlfong01 May 5 at 3:12

Your Answer

SomeoneElse is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.