Adafruit_CircuitPython_BusDevice icon indicating copy to clipboard operation
Adafruit_CircuitPython_BusDevice copied to clipboard

I2C init bug causes 10 seconds delay on the Jetson TX2 / Nano

Open tokiAi opened this issue 3 years ago • 1 comments

Issue:

I2C init bug causes 10 seconds delay on the Jetson TX2 / Nano. This problem is described on the following forums: https://forums.developer.nvidia.com/t/slow-initial-connection-to-i2c-sensor-from-python/161657 https://forums.adafruit.com/viewtopic.php?t=172811 https://forums.adafruit.com/viewtopic.php?t=180616

What is happening:

Logic Analyzer:

  • [write(address)+ ACK]
  • Nothing happens for about 10 seconds because the SCL is LOW (because of the ACK)
  • SCL is pushed up after about 10 seconds
  • a few milliseconds after that there is a [read (address) + ACK] [data + NAK]

Guess what happens:

  • Jetson receives a write command without data or with data that can be interpreted according to the system
  • Throws an error
  • Then continues with the read command

Code that causes this behavior: Adafruit_CircuitPython_BusDevice/adafruit_bus_device/i2c_device.py __init__ -> self.__probe_for_device() -> line 153 to 160

try:
                self.i2c.writeto(self.device_address, b"")
except OSError:
              # some OS's dont like writing an empty bytesting...
              # Retry by reading a byte
              try:
                    result = bytearray(1)
                    self.i2c.readfrom_into(self.device_address, result)

History of the write command

In order to understand whether this is necessary or useful:

  • commit fc7b8054663fb9a3a710c1339cc9b65bb13c8ccf adafruit_bus_device/i2c_device.py line 52 scan = i2c.scan() was added
  • commit 143df8695b2732cbd5d9c2dea60a5bd25ec8689b adafruit_bus_device/i2c_device.py changed in line 56 to i2c.writeto(device_address, b'') with the reason: Don't scan the whole bus to verify existence of i2c device -> A mistake happens here - but more on that later
  • commit 3a1339cb714abe559d69a5a3fbbac26c1e7fc849 solves the error on the BeagleBone Black with i2c.writeto(device_address, b'x') adafruit_bus_device/i2c_device.py in line 64
  • commit 796e0a1e357a609c4984cc827620b9b37ba28744 solves the error on the BeagleBone Black with dafruit_bus_device/i2c_device.py changed in line 67, 68 to
    result = bytearray(2) i2c.readfrom_into(device_address, result)
  • commit 793537e64bffcb005dda8de0f11f62bc72763b42 solves the error on the BeagleBone Black with adafruit_bus_device/i2c_device.py changed in line 67, 68 to result = bytearray(1)with the reason: it is not needed to read more than 1 byte -> This is probably also the best solution - but more on that later
  • commit aea9d07e8f60d79d5e5043a48b6b4f50e35dfc31 solves the error on the BeagleBone Black with adafruit_bus_device/i2c_device.py changed in line 67 - 76 to
            i2c.writeto(device_address, b'')
        except OSError:
            # some OS's dont like writing an empty bytesting...
            # Retry by reading a byte
            try:
                result = bytearray(1)
                i2c.readfrom_into(device_address, result)
  • From here on the code only changes in place and is now a part of the function self.__ probe_for_device()

Solution and the error that was overlooked

Error: The idea was good not to scan all addresses in commit 143df8695b2732cbd5d9c2dea60a5bd25ec8689b , but a false assumption was made that this is done with writing and not with reading. If you look at the scan() function you can see that it is done with read. For Linux is located in the blinka library https://github.com/adafruit/Adafruit_Blinka/blob/a79eb436569f2c4d1390571eba5779fc5aedf6db/src/adafruit_blinka/microcontroller/generic_linux/i2c.py : line 38 self._i2c_bus.read_byte(addr)

Solution: Back to the origin: Scan the necessary address. In other words, read 1 byte on the address.

tokiAi avatar Jun 30 '21 16:06 tokiAi

See comments in #70.

dhalbert avatar Jun 30 '21 16:06 dhalbert