Skip to content

enumerate one device at a time#1786

Closed
delan wants to merge 2 commits intohathach:masterfrom
delan:enumerate-one-at-a-time
Closed

enumerate one device at a time#1786
delan wants to merge 2 commits intohathach:masterfrom
delan:enumerate-one-at-a-time

Conversation

@delan
Copy link
Copy Markdown

@delan delan commented Dec 9, 2022

Special thanks to @ar1a for its help investigating this bug!

Describe the PR
Enumerating new devices starts with an HCD_EVENT_DEVICE_ATTACH event, but requires several more events to finish. If another HCD_EVENT_DEVICE_ATTACH event arrives before the current enumeration is complete, it will clobber _usbh_ctrl_buf and cause assertion failures. This can happen on a Raspberry Pi Pico with Pico-PIO-USB and multiple root hub ports.

This patch makes the host task enumerate one device at a time, by checking if there is a device already being enumerated before handling an HCD_EVENT_DEVICE_ATTACH event. If so, we send the attach event to the back of the queue.

Additional context
To reproduce on a Raspberry Pi Pico with Pico-PIO-USB, connect one device to GP2 (D+) and GP3 (D-) and another device to GP4 (D+) and GP5 (D-). Create a PlatformIO project with

[env:pico]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = pico
framework = arduino
board_build.core = earlephilhower
lib_deps =
    https://github.com/sekigon-gonnoc/Pico-PIO-USB.git
build_flags = -DUSE_TINYUSB -DCFG_TUH_ENABLED -DCFG_TUH_RPI_PIO_USB -DCFG_TUH_HID=4 -DCFG_TUSB_DEBUG=3 -DCFG_TUSB_DEBUG_PRINTF=serial1_printf
board_build.f_cpu = 120000000L
;; optional!
; build_type = debug
; debug_tool = picoprobe
; upload_protocol = picoprobe

and src/main.cc based on HID_device_report.ino with the following changes.

diff --git a/src/main.cc b/src/main.cc
index 121f482..b11863b 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -1,3 +1,5 @@
+#include <Arduino.h>
+
 /*********************************************************************
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
@@ -22,11 +24,13 @@
  */
 
 // pio-usb is required for rp2040 host
+extern "C" {
 #include "pio_usb.h"
+}
 #include "Adafruit_TinyUSB.h"
 
 // Pin D+ for host, D- = D+ + 1
-#define HOST_PIN_DP       20
+#define HOST_PIN_DP       2
 
 // Pin for enabling Host VBUS. comment out if not used
 #define HOST_PIN_VBUS_EN        22
@@ -86,6 +90,8 @@ void setup1() {
   // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
   // host bit-banging processing works done in core1 to free up core0 for other works
   USBHost.begin(1);
+
+  pio_usb_host_add_port(4);
 }
 
 void loop1()

The output on Serial1 (GP0), or the probe’s Serial (CDC) if using picoprobe with UART0 (GP0, GP1) connected to the probe’s UART1 (GP5, GP4), will be:

USBH init on controller 1
sizeof(usbh_device_t) = 58
sizeof(hcd_event_t) = 12
sizeof(_ctrl_xfer) = 24
sizeof(tuh_xfer_t) = 24
HID init
HUB init
[1:] USBH DEVICE ATTACH
Low Speed
[1:0] Open EP0 with Size = 8
Get 8 byte of Device Descriptor
[1:0] Get Descriptor: 80 06 00 01 00 00 08 00
[2:] USBH DEVICE ATTACH
Low Speed
[2:0] Open EP0 with Size = 8
Get 8 byte of Device Descriptor
process_enumeration 1237: ASSERT FAILED
on EP 00 with 8 bytes

After applying the patch, the output will be:

USBH init on controller 1
sizeof(usbh_device_t) = 58
sizeof(hcd_event_t) = 12
sizeof(_ctrl_xfer) = 24
sizeof(tuh_xfer_t) = 24
HID init
HUB init
[1:] USBH DEVICE ATTACH
Low Speed
[1:0] Open EP0 with Size = 8
Get 8 byte of Device Descriptor
[1:0] Get Descriptor: 80 06 00 01 00 00 08 00
[2:] defer attach until enumeration complete
on EP 00 with 8 bytes
[2:] defer attach until enumeration complete
on EP 80 with 8 bytes
[1:0] Control data:
  0000:  12 01 00 02 00 00 00 08                          |........|
[2:] defer attach until enumeration complete
on EP 00 with 0 bytes

Set Address = 1
[1:0] Set Address: 00 05 01 00 00 00 00 00
[2:] defer attach until enumeration complete
on EP 00 with 8 bytes
[2:] defer attach until enumeration complete
on EP 80 with 0 bytes

[1:1] Open EP0 with Size = 8
Get Device Descriptor
[1:1] Get Descriptor: 80 06 00 01 00 00 12 00
[2:] defer attach until enumeration complete
on EP 00 with 8 bytes
[2:] defer attach until enumeration complete
on EP 80 with 18 bytes
[1:1] Control data:
  0000:  12 01 00 02 00 00 00 08 61 04 23 4E 00 01 01 02  |........a.#N....|
  0010:  00 01                                            |..|
[2:] defer attach until enumeration complete
on EP 00 with 0 bytes

Get Configuration[0] Descriptor (9 bytes)
[1:1] Get Descriptor: 80 06 00 02 00 00 09 00
[2:] defer attach until enumeration complete
on EP 00 with 8 bytes
[2:] defer attach until enumeration complete
on EP 80 with 9 bytes
[1:1] Control data:
  0000:  09 02 22 00 01 01 00 A0 32                       |..".....2|
[2:] defer attach until enumeration complete
on EP 00 with 0 bytes

Get Configuration[0] Descriptor
[1:1] Get Descriptor: 80 06 00 02 00 00 22 00
[2:] defer attach until enumeration complete
on EP 00 with 8 bytes
[2:] defer attach until enumeration complete
[2:] defer attach until enumeration complete
on EP 80 with 34 bytes
[1:1] Control data:
  0000:  09 02 22 00 01 01 00 A0 32 09 04 00 00 01 03 01  |..".....2.......|
  0010:  02 00 09 21 11 01 00 01 22 2E 00 07 05 81 03 04  |...!....".......|
  0020:  00 0A                                            |..|
[2:] defer attach until enumeration complete
on EP 00 with 0 bytes

[1] HID opening Interface 0
  Open EP 81 with Size = 4
  HID opened
  Bind EP 81 to driver id 0
Set Configuration = 1
[1:1] Set Configuration: 00 09 01 00 00 00 00 00
[2:] defer attach until enumeration complete
on EP 00 with 8 bytes
[2:] defer attach until enumeration complete
on EP 80 with 0 bytes

Device configured
HID set config: itf = 0
HID Set Idle
[1:1] Get Interface: 21 0A 00 00 00 00 00 00
[2:] defer attach until enumeration complete
on EP 00 with 8 bytes
[2:] defer attach until enumeration complete
on EP 80 with 0 bytes

HID Set Protocol = 0
[1:1] Set Interface: 21 0B 00 00 00 00 00 00
[2:] defer attach until enumeration complete
on EP 00 with 8 bytes
[2:] defer attach until enumeration complete
on EP 80 with 0 bytes

HID Get Report Descriptor
[1:1] Get Descriptor: 81 06 00 22 00 00 2E 00
[2:] defer attach until enumeration complete
on EP 00 with 8 bytes
[2:] defer attach until enumeration complete
[2:] defer attach until enumeration complete
on EP 80 with 46 bytes
[1:1] Control data:
  0000:  05 01 09 02 A1 01 09 01 A1 00 05 09 19 01 29 03  |..............).|
  0010:  15 00 25 01 95 08 75 01 81 02 05 01 09 30 09 31  |..%...u......0.1|
  0020:  09 38 15 81 25 7F 75 08 95 03 81 06 C0 C0        |.8..%.u.......|
[2:] defer attach until enumeration complete
on EP 00 with 0 bytes

  Queue EP 81 with 4 bytes ... OK
[2:] USBH DEVICE ATTACH
Low Speed
[2:0] Open EP0 with Size = 8
Get 8 byte of Device Descriptor
[2:0] Get Descriptor: 80 06 00 01 00 00 08 00
on EP 00 with 8 bytes
on EP 80 with 8 bytes
[2:0] Control data:
  0000:  12 01 10 01 00 00 00 08                          |........|
on EP 00 with 0 bytes

Set Address = 2
[2:0] Set Address: 00 05 02 00 00 00 00 00
on EP 00 with 8 bytes
on EP 80 with 0 bytes

[2:2] Open EP0 with Size = 8
Get Device Descriptor
[2:2] Get Descriptor: 80 06 00 01 00 00 12 00
on EP 00 with 8 bytes
on EP 80 with 18 bytes
[2:2] Control data:
  0000:  12 01 10 01 00 00 00 08 61 04 24 4E 16 01 01 02  |........a.$N....|
  0010:  00 01                                            |..|
on EP 00 with 0 bytes

Get Configuration[0] Descriptor (9 bytes)
[2:2] Get Descriptor: 80 06 00 02 00 00 09 00
on EP 00 with 8 bytes
on EP 80 with 9 bytes
[2:2] Control data:
  0000:  09 02 3B 00 02 01 00 A0 32                       |..;.....2|
on EP 00 with 0 bytes

Get Configuration[0] Descriptor
[2:2] Get Descriptor: 80 06 00 02 00 00 3B 00
on EP 00 with 8 bytes
on EP 80 with 59 bytes
[2:2] Control data:
  0000:  09 02 3B 00 02 01 00 A0 32 09 04 00 00 01 03 01  |..;.....2.......|
  0010:  01 00 09 21 10 01 00 01 22 41 00 07 05 81 03 08  |...!...."A......|
  0020:  00 0A 09 04 01 00 01 03 00 00 00 09 21 10 01 00  |............!...|
  0030:  01 22 53 00 07 05 82 03 08 00 0A                 |."S........|
on EP 00 with 0 bytes

[2] HID opening Interface 0
  Open EP 81 with Size = 8
  HID opened
  Bind EP 81 to driver id 0
[2] HID opening Interface 1
  Open EP 82 with Size = 8
  HID opened
  Bind EP 82 to driver id 0
Set Configuration = 1
[2:2] Set Configuration: 00 09 01 00 00 00 00 00
on EP 00 with 8 bytes
on EP 80 with 0 bytes

Device configured
HID set config: itf = 0
HID Set Idle
[2:2] Get Interface: 21 0A 00 00 00 00 00 00
on EP 00 with 8 bytes
on EP 80 with 0 bytes

HID Set Protocol = 0
[2:2] Set Interface: 21 0B 00 00 00 00 00 00
on EP 00 with 8 bytes
on EP 80 with 0 bytes

HID Get Report Descriptor
[2:2] Get Descriptor: 81 06 00 22 00 00 41 00
on EP 00 with 8 bytes
on EP 80 with 65 bytes
[2:2] Control data:
  0000:  05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01  |..........)...%.|
  0010:  75 01 95 08 81 02 95 01 75 08 81 01 95 03 75 01  |u.......u.....u.|
  0020:  05 08 19 01 29 03 91 02 95 05 75 01 91 01 95 06  |....).....u.....|
  0030:  75 08 15 00 26 FF 00 05 07 19 00 2A FF 00 81 00  |u...&......*....|
  0040:  C0                                               |.|
on EP 00 with 0 bytes

  Queue EP 81 with 8 bytes ... OK
HID set config: itf = 1
HID Set Idle
[2:2] Get Interface: 21 0A 00 00 01 00 00 00
on EP 00 with 8 bytes
on EP 80 with 0 bytes

HID Get Report Descriptor
[2:2] Get Descriptor: 81 06 00 22 01 00 53 00
on EP 00 with 8 bytes
on EP 80 with 83 bytes
[2:2] Control data:
  0000:  06 01 00 09 80 A1 01 85 02 25 01 15 00 75 01 0A  |.........%...u..|
  0010:  81 00 0A 82 00 0A 83 00 95 03 81 06 95 05 81 01  |................|
  0020:  C0 05 0C 09 01 A1 01 85 01 95 01 75 10 15 00 26  |...........u...&|
  0030:  FF 02 19 00 2A FF 02 81 00 C0 06 00 FF 09 01 A1  |....*...........|
  0040:  01 85 05 15 00 26 FF 00 19 01 29 02 75 08 95 05  |.....&....).u...|
  0050:  B1 02 C0                                         |...|
on EP 00 with 0 bytes

  Queue EP 82 with 8 bytes ... OK

delan added a commit to delan/usb3sun that referenced this pull request Dec 9, 2022
delan added a commit to delan/usb3sun that referenced this pull request Dec 9, 2022
Copy link
Copy Markdown
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.

ah right, I remember putting the TODO expecting this issue in the future. Though I think we should use _dev0 e.g setting its rhport/speed to invalid as available instead of introducing a new variable.

@delan delan deleted the enumerate-one-at-a-time branch March 17, 2023 11:33
7FM pushed a commit to 7FM/tinyusb that referenced this pull request Aug 23, 2025
Use empty initializer list for struct clearing, avoiding a pedantic
warning from G++ 12 and 14.

Fixes hathach#1785
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

2 participants