STM32U5A5 USB OTG HS — Apparent Silicon Bug: TX FIFO Reports Zero Space and Can Deadlock
STM32U5A5 USB OTG HS — Apparent Silicon Bug: TX FIFO Reports Zero Space and Can Deadlock
I've been investigating a rather unpleasant problem with the USB OTG HS peripheral on the STM32U5A5, operating at Full Speed, and believe I've uncovered a silicon defect in the IN endpoint TX FIFO management.
This appears closely related to the issue previously reported by PhucXDoan in Another USB_OTG_FS Quirk — The 3-bit counter of IN endpoints.
My experiments provide some additional evidence, including synchronized USB bus measurements and a reproducible endpoint deadlock.
The problem
I'm using a custom USB Mass Storage implementation with the following configuration:
-
STM32U5A5, USB OTG HS peripheral operating at Full Speed
-
Bulk IN endpoint 5, 64-byte maximum packet size
-
TX FIFO allocated 256 × 32-bit words (1024 bytes)
-
Typical transfer: 512 bytes (128 words)
Despite the FIFO being twice the size of the transfer, DIEPTXFSTS.INEPTFSAV unexpectedly drops to zero after only a small number of FIFO writes.
More surprisingly, it sometimes spontaneously jumps back to nearly the full FIFO capacity without any intervening FIFO writes.
I've captured transitions from zero to over 240 available words.
It appears synchronized to USB bus activity
I instrumented the FIFO writer to record successive readings of INEPTFSAV and used a logic analyzer to measure how long the register remained at zero.
Observed intervals included 42, 55, and 91 µs.
Using a synchronized USB protocol analyzer, I found that recovery occurs almost immediately after an IN packet is acknowledged by the host.
One example:
| Event | Time |
|---|---|
| IN DATA1 packet begins | −3.08 µs |
| FIFO availability becomes zero | −0.48 µs |
| Host ACK | +42.74 µs |
| FIFO availability recovers | +44.00 µs |
In other words, the reported FIFO availability recovered just 1.26 µs after the host ACK.
This strongly suggests some interaction between the internal USB packet engine and the FIFO availability reporting.
Unfortunately, waiting doesn't always work
I tried removing the artificial delays between FIFO writes and simply waiting whenever INEPTFSAV reported zero.
Sometimes this worked. Sometimes it deadlocked indefinitely.
In one capture, the FIFO availability remained zero for approximately 88 µs, recovered immediately after an ACK, and then dropped back to zero just 320 ns later.
The second zero condition never recovered.
At the debugger breakpoint, the relevant registers were:
| Register | Value |
|---|---|
DIEPTSIZ5 | 0x00380000 |
DTXFSTS5 | 0x00000000 |
DIEPCTL5 | 0x81480040 |
DIEPINT5 | 0x00002010 |
Only 23 words (92 bytes) had been written during the instrumented FIFO-loading invocation.
The endpoint was still enabled, with seven packets outstanding, but the FIFO reported no available space.
DIEPINT5 also recorded an ITTXFE event (IN token received while TX FIFO empty), although this is a latched event and doesn't necessarily describe the instantaneous FIFO state.
A particularly disturbing timing dependency
Introducing approximately 900 ns between successive 32-bit FIFO writes makes the problem disappear in my testing.
At 700 ns, operation is intermittent.
Without sufficient delay, USB Mass Storage operation can fail, including apparent data corruption.
Increasing the allocated TX FIFO capacity also reduces the required delay.
So we have a USB controller whose correct operation appears to depend on how quickly software writes data into a FIFO that nominally has ample capacity.
That's not a particularly comforting situation for anyone developing a reliable USB device!
Questions for ST
I've submitted a detailed technical report to STMicroelectronics, including the register snapshots, experimental code, and synchronized USB measurements.
I'd particularly like to know:
-
Is there an undocumented internal packet-count limit independent of the configured FIFO depth?
-
Why does
INEPTFSAVabruptly report zero despite nominally available FIFO storage? -
Why does the condition sometimes recover following an ACK but sometimes persist indefinitely?
-
Is this the same underlying issue identified by PhucXDoan on the OTG FS implementation?
-
Is there a documented, reliable workaround that doesn't depend on arbitrary delays?
I'm particularly interested in hearing from anyone who has observed similar behavior on other STM32 families or has a deeper understanding of the Synopsys USB OTG controller internals.
I'd welcome an explanation from ST's USB silicon engineering team. If this is a known hardware constraint, it needs to be documented precisely. If it is a silicon defect, it deserves an erratum and a reliable workaround.
