Skip to content

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

Closed
@tokiAi

Description

@tokiAi

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 fc7b805 adafruit_bus_device/i2c_device.py line 52 scan = i2c.scan() was added
  • commit 143df86 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 3a1339c solves the error on the BeagleBone Black with i2c.writeto(device_address, b'x') adafruit_bus_device/i2c_device.py in line 64
  • commit 796e0a1 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 793537e 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 aea9d07 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 143df86 , 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions