Totally pedantic deep dive: the Pico has a USB FS PHY (the numbered versions don't directly correlate to line rate, and FS was defined in 1.0) - the signaling rate is 12Mb/s, but it's impossible to achieve sustained transfers at this data rate under any circumstance:
- USB FS has a 1ms frame limit (HS is 125µs)
- UBS FS Bulk is thusly limited to ~19 transactions x 64 bytes maximum (HS is 512)
- USB FS Isochronous can do 1023 byte transfers, but you can only fit one of those in a 1ms frame (resulting in a giant quantization hole in the packet)
- Focusing on bulk only: the token packet, ACK handshake, inter-packet bus turnaround time minimums, framing bits, CRC bits, and periodic FS SOF packets mean that the actual theoretical maximum data rate is ~81% of the signaling rate
- Bit stuffing optimality issues (required for clock recovery) eat an additional several percent on most data, up to ~17% on pathological data
Therefore: ~9.5Mb/s is the best theoretical data rate that can be obtained with optimal host and device IP and an ideal application layer.
Realistically, ~8Mb/s is the most one can expect on real hardware with an ideal application (and this is optimistically high in my experience.)
Author here: thank you for this deep dive. I saw peaks of 5.9 Mbps, it might be possible to increase throughput by allocating more memory. The link between the rp2040 and Infineon Wi-Fi device is 31.5 Mb/s. It might be possible to push that out over PIO to an external USB 2.0 PHY. Apparently the Wi-Fi device is capable of higher speeds. Who knows what will be the limiting factor. I'll leave it to someone else to experiment, my focus was the stock hardware without any modifications.
> It might be possible to push that out over PIO to an external USB 2.0 PHY.
I doubt you will be able to achieve USB HS via a ULPI PHY without an FPGA tunneling the USB SIE for you and handling the tight turnaround requirement (in which case, you might as well give it the entire MAC workload or just use an MCU with an integrated HS PHY.)
The ULPI clock is a 60MHz free-running PHY-sourced signal (typically - some PHYs allow MAC-sourced clocks and this would likely be a little easier), the PHY is entirely in control of when the MAC can transmit (DIR pin), and the protocol is unforgiving from a timing standpoint.