pyftdi
pyftdi copied to clipboard
Unable to open two pyftdi spi instances even though they are both listed using ftdi_urls.py
Hi, I am encountering a strange issue.
I have two discrete (separate) FT232H devices, here is the output of ftdi_urls.py -d -v:
Available interfaces:
ftdi://ftdi:232h:1/1 ()
ftdi://ftdi:232h:2/1 ()
If I have both plugged in, I can only open the one enumerated on ftdi://ftdi:232h:1/1.
Opening on ftdi://ftdi:232h:2/1 will reported "OSError: No such device".
I can plug each one in one at a time so they both exist on ftdi://ftdi:232h:1/1 at different times and I am able to open the connection. The problem is even though after I plug the 2nd one in, and it comes back on ftdi_urls.py I am unable to open on the ftdi://ftdi:232h:2/1.
Unfortunately neither of them have a serial number, and they have identical VID and PID. I wonder if this is somehow the part of the issue.
Is there some way I can give them a serial number? I know I can specify the serial number in the ftdi url string if they had one.
I use the FT Prog tool to give both of them serial numbers, and ftdi_urls.py now returns those instead:
Available interfaces:
ftdi://ftdi:232h:FT4YSHD2/1 (USB <-> Serial Converter)
ftdi://ftdi:232h:FT5B0PCB/1 (USB <-> Serial Converter)
If I use those returned urls both open successfully. Not sure why not having a serial number would return a bad URL before.
For reference, part used is from a https://www.adafruit.com/product/2264 breakout board. Not sure why they didn't have serial numbers.
similar to https://github.com/adafruit/Adafruit_Blinka/issues/260
the OS simply needs a way to ID one device from the other, otherwise the OS sees both devices as the same device. Not a problem with any of the libraries as far as I can tell.
Opening a USB port from an index was a very bad idea from the early beginning of PyFtdi, over 10 years ago. Simply because this indexing is not reproducible from one session to another.
There is an on-going (but stalled due to lack of spare time) effort to change the syntax for this deprecated index-based addressing mode.
When several FTDI devices are connected to the host, you can open a USB / PyFtdi device with either:
- Its serial number, which is the safer way and only 100% reproducible way to select a device, or
- Its bus/address identifier, with the alternate syntax
ftdi://vendor:product:bus:address/port
, i.e. 3:
in the host part of the URL.
The second mode is ok as long as you always plug the device on the very same USB port / hub topology (which is a mess under Windows, as usual :-))
Most FTDI devices (but the newest one) required an external EEPROM to store/retrieve their configuration, among which the serial number is encoded. Therefore, it is possible that some cheap boards cannot be programmed to use a serial number, if the EEPROM is missing.
AnnaGiasson created an init for us to use this library with. In it, she found this technique:
from io import StringIO from contextlib import redirect_stdout
in the init:
if isinstance(ftdi, (I2cController, Use_Ftdi)): # use existing i2c
if isinstance(ftdi, I2cController):
self.i2c_master = ftdi
else:
self.i2c_master = ftdi.i2c_master
# this assumes its the first dongle found
idn = self.i2c_master.ftdi.list_devices()[0][0]
self.ftdi_url = 'ftdi://{}:{}:{}/{}'.format(idn.vid, idn.pid,
idn.sn, idn.address)
else: # make a new connection
self.i2c_master = I2cController()
if ftdi is None: # url was not passed
# gets first found
try:
self.ftdi_url = get_available_ftdi_urls()[0][0]
except IndexError:
raise OSError('No FTDI device connections were found, '
'unable to connect')
else:
self.ftdi_url = ftdi
"""We will probably publish this repo soon. Just have to sanitize a few more internal names off the code. Basically what occurs, is that the dongles / FTDI devices are in the system with the libusb already setup for each. Now when our code runs, we do something like this"""
try: i2cURL = get_available_ftdi_urls()[0][0] # ...urls()[dongle position in the list, 0 if only one][dongle url is # element 0] except IndexError: print('No FTDI Devices Found, plugged in? Check USB connections...') print('If it is plugged in, did you change the driver for THIS dongle?')
""" make an instance of the i2c dongle and hunt for addresses""" try: i2c = Use_Ftdi(ftdi=i2cURL, **ftdi_options) except FtdiError: input('is there an i2c device connected or powered? press any key...') """ now we pass i2c as the instance of the dongle to whatever functions we need to use it. your system would find two URLs.. so you want to assign them.
Good luck. p.s. triple quotes etc used to make this more readable without the font and bold coming and going. ""'