Description
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.