Skip to content

dwc2/host: attach debouncing fixes #3075

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

Merged
merged 6 commits into from
Apr 21, 2025

Conversation

maximevince
Copy link
Contributor

@maximevince maximevince commented Apr 11, 2025

Describe the PR
The DWC2 host can generate a lot of HPRTINT interrupts when a device is attached, due to electrical contact bounce.
All of these events were being forwarded to the TinyUSB host stack as new HCD_EVENT_DEVICE_ATTACH events, causing many issues:

  • rapid succession of ATTACH and REMOVE events, occurring in the middle of device enumeration
  • queue exhaustion because more events were generated than could be swallowed by the tuh_task()
  • many other weird combinations of code handling attachment and removal simultaneously

Additional context

  • I've made one change to the usbh.c (which I tried not to touch at all), becuase the hcd_event_handler has a special case for handling a combination of dev0 flags, which then forces _dev0.enumerating = 0. I do not fully understand the reason it's there, but I have found that every time this condition is triggered, it will crash the dwc2 drivers' process_enumeration() function thereafter. I have commented out this condition, and found no side-effect, but using the host directly and with a USB Hub connected.
  • I am clearing the attach_debounce flag in the hcd_port_connect_status() function implemented in the dwc2 driver, since this is being called after the ENUM_DEBOUNCING_DELAY_MS delay in usbh.c (and only from there).
    This is not the cleanest way, but I wanted to avoid creating a new callback from the usbh.c higher-level module into the dwc2 driver, just to clear the debouncing flag.

Result
I have found no more USB stack crashes due to rapidly connecting / disconnecting devices on the STM32F7xx w/ DWC2 USB IP Core. (Whereas there were MANY before)
The only issue I've still encountered is running out of channels (>16 used) when using a USB HUB and repeatedly connecting/disconnecting a device on one of it's ports. There must be a case where a channel is not properly deallocated after aborting due to some condition. This should probably get it's separate PR.

@HiFiPhile @roma-jam

@HiFiPhile
Copy link
Collaborator

HiFiPhile commented Apr 11, 2025

Indeed doing the debouncing at DCD layer is much simpler.

I was testing break down the 450ms debouncing delay into smaller chunks in order to let the event queue processed in time.
22ea6ee

_dev0.enumerating = 0 is trying to stop ongoing control transfer once the device is unplugged, then normally _ctrl_xfer will end up in idle state. However in some cases control transfer state get stuck.

I think a good fix is instead of _dev0.enumerating = 0 inhcd_event_handler():

@@ -606,6 +563,15 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
         TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
         process_removing_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);

+        if ((event.rhport == _dev0.rhport) && (event.connection.hub_addr == _dev0.hub_addr) &&
+            (event.connection.hub_port == _dev0.hub_port)) {
+          if (_dev0.enumerating) {
+            // device 0 is removed, stop enumeration
+            _dev0.enumerating = 0;
+            // clear control transfer stage in case it is failed
+            if (_ctrl_xfer.daddr == 0)
+            _set_control_xfer_stage(CONTROL_STAGE_IDLE);
+          }
+        }
         #if CFG_TUH_HUB

@maximevince
Copy link
Contributor Author

Where is the 450ms value coming from, btw? It seems quite high, IIRC USB standard recommends a 100ms debouncing time.

For the _dev0.enumerating = 0, I just noticed your PR: #3080 and that seems solid to me!

@HiFiPhile
Copy link
Collaborator

HiFiPhile commented Apr 14, 2025

Where is the 450ms value coming from, btw? It seems quite high, IIRC USB standard recommends a 100ms debouncing time.

I think we can reduce it and place tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); beforehcd_port_reset(_dev0.rhport); Actually Windows use 100ms delay.

But in case of enumeration failure Windows will retry the whole procedure so they don't need a high delay. For TUSB I'm afraid retry the whole procedure will have side effects unless asynchronous delay is implemented.

@maximevince
Copy link
Contributor Author

Can we merge this? Is there any more action required from my side?
@hathach @HiFiPhile

Copy link
Collaborator

@HiFiPhile HiFiPhile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hathach I've tested on h7rs and esp32-s3, both works well.

Copy link
Owner

@hathach hathach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for your PR. It is great idea, I think we will move the attach_debouncing flag and event igonored to usbh later, that would aplly the fix for all the hcd (later). Let just get this merged first.

I also update the usbh to prevent control stage locked up when device is unplugged while usbh trying to make the transfer.

@hathach hathach merged commit 18d7a99 into hathach:master Apr 21, 2025
108 checks passed
@maximevince
Copy link
Contributor Author

Thank you for the great interactions on this project and thanks for merging the PR(s) so fast!

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

Successfully merging this pull request may close these issues.

3 participants