summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-07-08 07:32:49 +0700
committerhathach <[email protected]>2026-07-08 07:32:49 +0700
commit9d51270f7bb1d70978e2b4abb672d0fe930fb68d (patch)
treec8953fbab4f935ab3d0c868c64170dbe2def9760
parent206e63349199e34047486d3dba3f2c8972aae5f2 (diff)
Retry CH569 SuperSpeed training and fix net_lwip_webserver EP0 size
Two fixes found bringing up SuperSpeed on a Renesas uPD720201-based hub: - dcd_ch56x_usb30: retry link training with a fresh detect cycle every second fallback-timer tick (4 ticks total) before switching to the USB2 fallback. Some hubs only complete Polling on a re-attempt; with a single continuous attempt the link reached U0 rarely and the port fell back to high speed almost every boot. - net_lwip_webserver: CFG_TUD_ENDPOINT0_SIZE was left at plain 64, so usbd chunked EP0 data at 64 bytes; on a 512-mps SuperSpeed control endpoint the first chunk is a short packet, the host ends the data stage early and the status stage deadlocks until timeout ("can't read configurations, error -110"). Use the SuperSpeed-aware size and clamp the device-qualifier bMaxPacketSize0 like the other examples. Validated on HydraUSB3: NCM enumerates at 5000M reliably across warm reboots; lwiperf over SuperSpeed measures 51 Mbit/s device RX (TCP window bound; 33 Mbit/s on the high-speed fallback), MSC 169/136 MB/s. Full example sweep, 65/65 unit tests, pre-commit clean. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019MRGjBT2NBkCoWwyDT4LaE
-rw-r--r--examples/device/net_lwip_webserver/src/tusb_config.h2
-rw-r--r--examples/device/net_lwip_webserver/src/usb_descriptors.c2
-rw-r--r--src/portable/wch/dcd_ch56x_usb30.c16
3 files changed, 16 insertions, 4 deletions
diff --git a/examples/device/net_lwip_webserver/src/tusb_config.h b/examples/device/net_lwip_webserver/src/tusb_config.h
index 2ff68a356..ef5d5f622 100644
--- a/examples/device/net_lwip_webserver/src/tusb_config.h
+++ b/examples/device/net_lwip_webserver/src/tusb_config.h
@@ -149,7 +149,7 @@ extern "C" {
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
- #define CFG_TUD_ENDPOINT0_SIZE 64
+ #define CFG_TUD_ENDPOINT0_SIZE (TUD_OPT_SUPER_SPEED ? 512 : 64) // SuperSpeed EP0 is fixed at 512
#endif
//------------- CLASS -------------//
diff --git a/examples/device/net_lwip_webserver/src/usb_descriptors.c b/examples/device/net_lwip_webserver/src/usb_descriptors.c
index 10c003c75..a5c2da6ab 100644
--- a/examples/device/net_lwip_webserver/src/usb_descriptors.c
+++ b/examples/device/net_lwip_webserver/src/usb_descriptors.c
@@ -346,7 +346,7 @@ static tusb_desc_device_qualifier_t const desc_device_qualifier = {
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
- .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+ .bMaxPacketSize0 = EP0_SIZE_FSHS,
.bNumConfigurations = CONFIG_ID_COUNT,
.bReserved = 0x00
};
diff --git a/src/portable/wch/dcd_ch56x_usb30.c b/src/portable/wch/dcd_ch56x_usb30.c
index f9c7fded7..cc14a86ce 100644
--- a/src/portable/wch/dcd_ch56x_usb30.c
+++ b/src/portable/wch/dcd_ch56x_usb30.c
@@ -103,6 +103,7 @@ static volatile bool _lmp_pending; // send LMP PORT_CAPABILITY at next li
// timer. One way: returning to SuperSpeed after fallback requires a new dcd_init (or power cycle).
enum { FB_USB3_TRAINING = 0, FB_USB3_OFF, FB_USB3_UP, FB_USB2_ACTIVE };
static volatile uint8_t _fb_state;
+static uint8_t _fb_train_ticks; // training timer expiries; a fresh detect cycle every 2nd tick
static void fallback_timer_stop(void) {
R8_TMR0_INTER_EN = 0;
@@ -111,9 +112,10 @@ static void fallback_timer_stop(void) {
}
static void fallback_timer_start(void) {
+ _fb_train_ticks = 0;
R8_TMR0_CTRL_MOD = RB_TMR_ALL_CLEAR;
// TMR0 counts 26 bits: CNT_END must stay below 2^26 (67108864). 0.55 s per expiry at
- // 120 MHz, ~1.1 s total before USB2 comes up
+ // 120 MHz; training gets several expiries (with re-attempts) before USB2 comes up
R32_TMR0_CNT_END = 66000000;
R8_TMR0_INT_FLAG = RB_TMR_IF_CYC_END;
R8_TMR0_INTER_EN = RB_TMR_IE_CYC_END;
@@ -543,7 +545,17 @@ void dcd_int_handler(uint8_t rhport) {
if (R8_TMR0_INT_FLAG & RB_TMR_IF_CYC_END) {
R8_TMR0_INT_FLAG = RB_TMR_IF_CYC_END;
if (_fb_state == FB_USB3_TRAINING) {
- // first expiry: shut USB3 down so the host sees a disconnect
+ // Retry SuperSpeed training with a fresh detect cycle a few times before giving up:
+ // some hubs (e.g. Renesas uPD720201's) only complete training on a re-attempt
+ _fb_train_ticks++;
+ if (_fb_train_ticks < 4) {
+ if ((_fb_train_ticks & 1u) == 0) {
+ usb30_hw_deinit();
+ usb30_hw_init();
+ }
+ return;
+ }
+ // training window exhausted: shut USB3 down so the host sees a disconnect
PFIC_DisableIRQ(USBSS_IRQn);
PFIC_DisableIRQ(LINK_IRQn);
usb30_hw_deinit();