-
Notifications
You must be signed in to change notification settings - Fork 354
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improvements to the mcp2221.py
module
#536
Comments
I created #540 to address the first point. I haven't made much progress on the second point. It seems that with the native In addition, the devices sometimes becomes "slow", and the only way I found to fix that is causing a crash/segfault to reset it (once it gets slow the problem persists even after restarting Python). I also noticed that when it's slow, attempting to close it generates a new line in If I run this, >>> import hid, time; h = hid.device(); h.open(0x04D8, 0x00DD)
>>> h.close() # the device is closed correctly without delay
>>> import hid, time; h = hid.device(); h.open(0x04D8, 0x00DD)
>>> h.close() # and these don't add any output to dmesg If I try to send a reset, this happens: >>> import hid, time; h = hid.device(); h.open(0x04D8, 0x00DD)
>>> report = b"\x70\xAB\xCD\xEF"; h.write(b"\0" + report + b"\0" * (64 - len(report)))
65
>>> h.close() # this still returns immediately -- probably a no-op since the device is gone
>>> # the device is not accessible for a while
>>> import hid, time; h = hid.device(); h.open(0x04D8, 0x00DD)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "hid.pyx", line 113, in hid.device.open
OSError: open failed
>>> # after a few seconds it can be opened again
>>> import hid, time; h = hid.device(); h.open(0x04D8, 0x00DD)
>>> h.close() # but this is now slow (~16s)
>>> import hid, time; h = hid.device(); h.open(0x04D8, 0x00DD)
>>> h.close() # and keeps being slow even after closing Python
>>> import hid, time; h = hid.device(); h.open(0x04D8, 0x00DD)
>>> h.close() # and each of these now adds a line to dmesg
>>> Just after doing the reset, [659138.741983] usb 5-1: USB disconnect, device number 76
[659139.233178] usb 5-1: new full-speed USB device number 77 using xhci_hcd
[659139.432800] usb 5-1: New USB device found, idVendor=04d8, idProduct=00dd, bcdDevice= 1.00
[659139.432808] usb 5-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[659139.432811] usb 5-1: Product: MCP2221 USB-I2C/UART Combo
[659139.432813] usb 5-1: Manufacturer: Microchip Technology Inc.
[659139.448967] cdc_acm 5-1:1.0: ttyACM0: USB ACM device
[659139.457208] mcp2221 0003:04D8:00DD.0076: hidraw1: USB HID v1.11 Device [Microchip Technology Inc. MCP2221 USB-I2C/UART Combo] on usb-0000:00:10.0-1/input2 Afterwards, each [659169.812569] mcp2221 0003:04D8:00DD.0077: hidraw1: USB HID v1.11 Device [Microchip Technology Inc. MCP2221 USB-I2C/UART Combo] on usb-0000:00:10.0-1/input2
[659260.278641] mcp2221 0003:04D8:00DD.0078: hidraw1: USB HID v1.11 Device [Microchip Technology Inc. MCP2221 USB-I2C/UART Combo] on usb-0000:00:10.0-1/input22
[659689.375741] mcp2221 0003:04D8:00DD.0079: hidraw1: USB HID v1.11 Device [Microchip Technology Inc. MCP2221 USB-I2C/UART Combo] on usb-0000:00:10.0-1/input2 One interesting thing to notice is that these messages include [659907.319058] usb 5-1: USB disconnect, device number 77
[659907.810670] usb 5-1: new full-speed USB device number 78 using xhci_hcd
[659908.010875] usb 5-1: New USB device found, idVendor=04d8, idProduct=00dd, bcdDevice= 1.00
[659908.010889] usb 5-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[659908.010894] usb 5-1: Product: MCP2221 USB-I2C/UART Combo
[659908.010898] usb 5-1: Manufacturer: Microchip Technology Inc.
[659908.027085] cdc_acm 5-1:1.0: ttyACM0: USB ACM device
[659908.035545] mcp2221 0003:04D8:00DD.007A: hidraw1: USB HID v1.11 Device [Microchip Technology Inc. MCP2221 USB-I2C/UART Combo] on usb-0000:00:10.0-1/input2
[661371.207608] mcp2221 0003:04D8:00DD.007B: hidraw1: USB HID v1.11 Device [Microchip Technology Inc. MCP2221 USB-I2C/UART Combo] on usb-0000:00:10.0-1/input2
[661402.623018] python3[180397]: segfault at 200 ip 00007f7fc731a28b sp 00007f7fc5c1dd20 error 4 in libusb-1-150b88da.0.so.0.1.0[7f7fc7310000+17000] Here the device 77 is closed (by the reset), and once the mcp reconnects it gets assigned 78 as a new device number. However the line at I suspect that when a reset signal is sent to the mcp, it disconnects from the mcp side in a way that is not detected by the In addition, I noticed that in the I tried to find the source of the I was also able to track the source of the crash to an assertion in the libusb_linux repo (even though I'm not sure I got the right repo/fork). This failed assertion could also be explained by the aforementioned theory: if during a reset the mcp disconnects without telling the driver, the device might not be removed, and the number of devices might end up being wrong. It seems to me that the problem with the slow device is caused by the driver and should be fixed upstream. The mcp2221.py module could avoid the reset, but since it was added to solve another issue (on Windows IIRC), maybe it could be skipped conditionally, either based on the platform, or perhaps even on the driver being used -- at least until the problem is fixed upstream. Note that the reset can already be avoided by setting However there are other situations where the device might become "slow" (for example if it gets unplugged and plugged back in again, possibly while it's open), so avoiding the |
What is the motivation for this? |
A few reasons, but mostly I'm trying to simplify the setup/installation. I'm currently using an SCD30 sensor connected to an MCP2221 connected to a Linux machine and I would like to be able to just plug the USB on a Linux machine, install the program I wrote to read data from the SCD30 (which will automatically install the dependencies from Currently this is not possible, because it's also necessary to make some system-wide changes, such as setting up the udev rules and removing/blacklisting the In addition, there might be other connected devices that might need the If the issues are caused by a bug in the It also seems that by removing the Finally, while discuss the issue with a friend, he brought to my attention the fact that from adafruit_blinka.microcontroller.generic_linux.i2c import I2C
i2c = I2C(bus_num)
scd = adafruit_scd30.SCD30(i2c) to talk directly to the SCD30, letting the |
What would be the solution for Mac and Windows users? The current approach works on linux/mac/windows. |
Hi @ezio-melotti. You seem to have dived deep down with mcp2221. I am facing an issue where by using adafruit blinka i am not able to collect data from accelerometer, connected over i2c, at higher data rate. The max it goes to is 45Hz~ |
@BhupiMAD, I would recommend asking on the Discord server and/or on the Adafruit forum. |
Suggest closing this issue in favor of #603. |
As a follow-up to #535, I'm doing more tests and tweaks to the mcp2221.py file, in particular:
I've added
self._hid.close()
in a few places to ensure the device is closed correctly, avoiding segfaults upon exit (see also Assertion `ctx->pollfds_cnt >= internal_nfds' failed. signal11/hidapi#397).I'm trying to make the native
hid_mpc2221
driver work out of the box, without having to replace it with thehid_generic
driver throughrmmod
/blacklisting:5
to20
at line 123 seems to solve theOSError: open failed
reported inimport board
with MCP2221 fails withOSError: open failed
#535, without having to rely on a forcedsleep()
at line 121:Adafruit_Blinka/src/adafruit_blinka/microcontroller/mcp2221/mcp2221.py
Lines 119 to 125 in 8a25ee4
I would replace the hardcoded
5
withMCP2221_RESET_DELAY
, remove thesleep
, and increase the default value ofMCP2221_RESET_DELAY
to 20/30s.open
at line 125 still takes several seconds with the nativehid_mpc2221
driver. I tried to close the device before theopen
and also to create a separate device instance, but it's always slow. This seems to be caused by the reset, but I couldn't find any documentation about that reset byte sequence, nor a way to make it fast. A minimal reproducer is:I feel that the reset might not be necessary if we can ensure the device is closed properly and left in a consistent state (see 1. above), and skipping it should solve the problem altogether, however I'm not familiar with all the cases where the reset might be needed, and removing it might be backward incompatible. The
_reset
method could also be exposed publicly, so that users can still call it if necessary.Another forced
sleep
might be removed here:Adafruit_Blinka/src/adafruit_blinka/microcontroller/mcp2221/mcp2221.py
Lines 66 to 71 in 8a25ee4
device.read()
accepts a timeout_ms argument that could replace thesleep
, but I haven't been able to test if it works (theread
always returned immediately during my tests). However it's not immediately clear if fhesleep
is there to wait before theread
(in that case it should be replaced withtimeout_ms
or moved inside theif
), or before thereturn
(in that case a comment should be added to clarify).I can submit one or more PRs once I complete my tests. The changes suggested in 1. are pretty straightforward; 2. could implemented regardless, since it works with both drivers, but I would still like to find a way to make the code fast with
hid_mcp2221
; 3. also seems pretty straightforward, but it should be tested before being changed and it depends on what thesleep
is trying to fix (the explanation on #243 is a bit vague).The text was updated successfully, but these errors were encountered: