| Posted: 06:40am 07 May 2026 |
Copy link to clipboard |
 Print this post |
|
Given the pain this problem caused me, I am posting here in the off chance that if someone else has the same issue, it can be solved.
The Cherry USB is not well adapted to USB_FS and needed two changes to make a mouse work.
Change 1: usb_hc_dwc2.c
#if 0 // TODO: AI
This fix worked:
The STM32H7 internal FS PHY requires a strict configuration that generic DWC2 drivers often break when handling Low-Speed devices. The final working state relies on three explicit hardware overrides:
Bit-Rate Throttling: Forcing LSDEV = 1 physically throttles the hardware to send 1.5 Mbps pulses instead of 12 Mbps.
PHY Timebase: Locking FSLSPCLKSEL to 48 MHz (Selection 1) ensures the internal digital sampling logic remains synchronized with the H7's core USB clock domain.
Frame Boundaries: Locking HFIR to 48000 prevents the driver from incorrectly calculating an 8ms frame. It guarantees the hardware scheduler maintains strict 1ms periodic boundaries for the Interrupt pipe.
The Host Controller is now firing the End-of-Frame Keep-Alives and sampling the mouse's response at the correct frequency.
Correct code in ELSE block
if ((hprt0 & USB_OTG_HPRT_PENA) == USB_OTG_HPRT_PENA) { regval = USB_OTG_HOST->HFIR; regval &= ~USB_OTG_HFIR_FRIVL; regval |= dwc2_calc_frame_interval(bus) & USB_OTG_HFIR_FRIVL; USB_OTG_HOST->HFIR = regval;
if (g_dwc2_hcd[bus->hcd.hcd_id].user_params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { if ((hprt0 & USB_OTG_HPRT_PSPD) == (HPRT0_PRTSPD_LOW_SPEED << 17)) { if ((USB_OTG_HOST->HCFG & USB_OTG_HCFG_FSLSPCS) != USB_OTG_HCFG_FSLSPCLKSEL_6_MHZ) { regval = USB_OTG_HOST->HCFG; regval &= ~USB_OTG_HCFG_FSLSPCS; regval |= USB_OTG_HCFG_FSLSPCLKSEL_6_MHZ; USB_OTG_HOST->HCFG = regval; } } else { if ((USB_OTG_HOST->HCFG & USB_OTG_HCFG_FSLSPCS) != USB_OTG_HCFG_FSLSPCLKSEL_48_MHZ) { regval = USB_OTG_HOST->HCFG; regval &= ~USB_OTG_HCFG_FSLSPCS; regval |= USB_OTG_HCFG_FSLSPCLKSEL_48_MHZ; USB_OTG_HOST->HCFG = regval; } } } } #else if ((hprt0 & USB_OTG_HPRT_PENA) == USB_OTG_HPRT_PENA) { if (g_dwc2_hcd[bus->hcd.hcd_id].user_params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { if ((hprt0 & USB_OTG_HPRT_PSPD) == (HPRT0_PRTSPD_LOW_SPEED << 17)) { /* Low Speed: 6 MHz clock requires exactly 6000 ticks for a 1ms frame */ regval = USB_OTG_HOST->HCFG; regval &= ~USB_OTG_HCFG_FSLSPCS; regval |= USB_OTG_HCFG_FSLSPCLKSEL_6_MHZ; USB_OTG_HOST->HCFG = regval; USB_OTG_HOST->HFIR = 6000; } else { /* Full Speed: 48 MHz clock requires exactly 48000 ticks for a 1ms frame */ regval = USB_OTG_HOST->HCFG; regval &= ~USB_OTG_HCFG_FSLSPCS; regval |= USB_OTG_HCFG_FSLSPCLKSEL_48_MHZ; USB_OTG_HOST->HCFG = regval; USB_OTG_HOST->HFIR = 48000; } } else { /* Non-FS PHY fallback logic */ regval = USB_OTG_HOST->HFIR; regval &= ~USB_OTG_HFIR_FRIVL; regval |= dwc2_calc_frame_interval(bus) & USB_OTG_HFIR_FRIVL; USB_OTG_HOST->HFIR = regval; } }
#endif
Change 2: same file in dwc2_chan_char_init
/* LS device plugged to HUB */ if ((speed == USB_SPEED_LOW) && (usbh_get_port_speed(bus, 0) != USB_SPEED_LOW)) { regval |= USB_OTG_HCCHAR_LSDEV; }
// TODO: (over-ride above code) if (speed == USB_SPEED_LOW) { regval |= USB_OTG_HCCHAR_LSDEV; }
Getting keyboards to work on the STM32H743 was not too much of a problem, but mouse was a bitch. Anyway hope this helps someone.
And yes, I used AI to help work this out but sometimes I wonder if AI is more trouble than its worth. If all else fails, remain flexible and maintain a sense of humour |