Skip to content
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

RP2040 PIO USB Host does not detect device unplug #2971

Closed
1 task done
rppicomidi opened this issue Feb 3, 2025 · 6 comments
Closed
1 task done

RP2040 PIO USB Host does not detect device unplug #2971

rppicomidi opened this issue Feb 3, 2025 · 6 comments
Labels

Comments

@rppicomidi
Copy link
Contributor

Operating System

Linux

Board

Feather RP2040 with USB A Host

Firmware

https://github.com/rppicomidi/usb_midi_host/tree/main/examples/C-code/usb_midi_host_pio_example

I think the version in GitHub may not have specific support for the Feather board yet, but it will shortly.

What happened ?

I have connected a powered USB 2.0 hub to the USB A port of the Feather board. If I plug a MIDI device to the hub, it enumerates correctly and starts working. If I unplug the hub from the Feather board, the software correctly detects the MIDI device is unplugged. If I plug the hub back in with the MIDI device still connected, it enumerates again and starts working again. However, if I leave the hub plugged in and unplug the device, the software does not detect the MIDI device was unplugged.

If I build firmware that uses the native RP2040 USB hardware for the USB host, I do not see this issue.

How to reproduce ?

  1. Build the firmware above for the Feather board
  2. Connect a USB C cable to the board and the build computer and load the firmware to the Feather board.
  3. Disconnect the Feather board from the computer.
  4. Connect a UART to USB serial adapter to the Feather board's ground pin and the Feather board's UART RX and TX pins
  5. Plug the serial adapter to the PC and launch a terminal program such as minicom.
  6. Plug the Feather board's USB C cable to a 5V power source.
  7. Observe the Pico MIDI Host Example message on the serial terminal
  8. Plug a powered hub with power applied to the Feather's USB A port.
  9. Plug a MIDI device to the USB hub. Observe the connection message on the serial terminal.
  10. Move a control, press a button, etc. on the MIDI device and confirm the serial terminal registers the MIDI events
  11. Unplug the powered hub with the MIDI device still plugged in.
  12. Observe the disconnect message on the serial terminal.
  13. Plug the hub and device back in to the Feather board's USB A port.
  14. Observe the connection message on the serial terminal.
  15. Move a control, press a button, etc. on the MIDI device and confirm the serial terminal registers the MIDI events
  16. Leave the hub connected to the Feather board's USB A port and unplug the MIDI device from the hub.
  17. Observe no disconnect message. Also observe plugging the device back in does not work.

Debug Log as txt file (LOG/CFG_TUSB_DEBUG=2)

I lost my log files, but logs showed first the bulk transfer failed from the MIDI device, which is expected, but then the interrupt IN transfer failed from the hub, which is not. The file hub.c is coded so that if the transfer result is not XFER_RESULT_SUCCESS, then the host stops polling the hub for status change.

bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
  (void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports
  (void) ep_addr;
  TU_VERIFY(result == XFER_RESULT_SUCCESS);

Screenshots

@hathach I can work around this issue with the following patch to hub.c, but I think that maybe this is not really fixing the bug. If you have advice where to look in the HCD for TinyUSB or in the low-level stuff in the Pico-PIO-USB project, I will try to make a pull request. If you want a pull request with fix below, I can do that too.

diff --git a/src/host/hub.c b/src/host/hub.c
index e97014443..daf036d60 100644
--- a/src/host/hub.c
+++ b/src/host/hub.c
@@ -334,7 +334,18 @@ static void connection_port_reset_complete (tuh_xfer_t* xfer);
 bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
   (void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports
   (void) ep_addr;
+
+  static uint8_t retries = 0;
+  if (result == XFER_RESULT_FAILED) {
+    // try again up to 3 times.
+    if (retries++ < 3) {
+      hub_edpt_status_xfer(dev_addr);
+      TU_LOG2("HUB Xfer failed; retry %u\r\n", retries);
+    }
+    return 0;
+  }
   TU_VERIFY(result == XFER_RESULT_SUCCESS);
+  retries = 0;
 
   hub_interface_t* p_hub = get_itf(dev_addr);

I have checked existing issues, dicussion and documentation

  • I confirm I have checked existing issues, dicussion and documentation.
@rppicomidi
Copy link
Contributor Author

I just re-checked my setup and now I cannot make my workaround work. See LOG=2 result.

hub_issue_log.txt

@rppicomidi
Copy link
Contributor Author

I pushed a change to the usb_midi_host application driver to stop all transfer requests once one transfer fails. For Pico-PIO-USB hosts with hub attached, it does not fix the issue. However, now workaround patch I proposed above works to fix the issue. I verified this on an Adafruit Feather RP2040 with USB A Host board.

@wiredopposite
Copy link

I tried to solve this in pico-pio-usb with d17f8ef, it would hang when certain devices were unplugged, but that probably didn't do enough. I added another timeout here: 5122927 which seemed to make things better but I'm not 100% on if that'll work in all cases. I think if there's nothing to read from ACK, the RX buffer index is never incremented so it can still hang there without a timeout.

@rppicomidi
Copy link
Contributor Author

@wiredopposite The fixes you mention probably helped with plug and unplug when the device is connected to the host directly. When the device is connected through a hub, the first transfer to the hub after a failed IN or OUT transfer to a device disconnected from the hub fails. At around line 297, I printed the return value from usb_in_transaction().

            if (ep->ep_num & EP_IN) {
              int ok = usb_in_transaction(pp, ep);
              if (ok != 0) {
                printf("IN transaction error %d\r\n",ok);
              }

I observe the transfer that fails because the device is not connected returns -2. The host poll of the hub IN interrupt returns -1. Does that point to a PIO state machine getting stuck after a failed transfer?

@rppicomidi
Copy link
Contributor Author

I observe that if I roll back the Pico-PIO-USB library to version 0.5.3, this problem goes away. I am closing this issue in this library.

@hathach
Copy link
Owner

hathach commented Feb 19, 2025

@rppicomidi #2994 improve hub driver with pio-usb, there is still more to push. Let me know if that helps with your issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants