Ubiquitous Successful Bus: Version 2

I’ve talked a fair bit about USB-C before, explaining how it all works, from many different angles. That said, USB-C is just the physical connector standard, plus the PD part that takes care of voltages and altmodes – things like data transfer are still delegated to the two interfaces you invariably end up using on USB-C ports, USB 2, and USB 3.

You might think USB 2 and USB 3 are tightly related, but in many crucial ways, they couldn’t be more different. I have experience working with both, and, as you might guess, I want to share it all with you. You might be surprised to hear there’s plenty to learn about USB 2 in particular – after all, we’ve had it hang around for 30 years now. Well, let’s make sure you’re fully caught up!

The Ingredients

USB 2 is a point-to-point link – one side is “host” and another is “device”, with the host typically being a PC chipset or a single-board computer. USB 2 relies on a single pseudodifferential pair. It’s “pseudodifferential” because the wires don’t just do differential signaling – they also use digital logic levels and pullup/pulldown resistors to signal device presence, especially in the beginning when the USB link is still getting established. Indeed, you can imitate a USB device’s presence with just a resistor.

This differential pair is half-duplex – it’s used for communications back and forth, but only one direction of data transfer at a time. Just like I2C, USB 2 requires the host to initiate all communications. The host has to poll the devices on a regular basis to receive data, a point that regularly gets brought up by defenders of PS/2 keyboards.

You know that USB ports come with a a 5 V power rail, but there are plenty of 3.3 V USB devices, too – in fact, most USB devices operate on 3.3 V internally. At its core, USB 2 requires 3.3 V-based signaling – which is why, when powering your RP2040 from 1.8 V, you must still provide 3.3 V if you want the USB peripheral to work.

An old flash drive, with a 12MHz crystal front and center. By [Tod Kurt], CC BY 2.0
You need reasonably accurate clocks to talk USB 2, which is why everyone ends up adding a 12 MHz crystal to their USB projects even when they have an internal RC oscillator. Some devices like cheap USB hub ICs boast an internal RC oscillator that supposedly works for USB transfers, but if you want to use it, you should test it well before you try and rely on it – it could be a path towards USB data transfer errors. Thankfully, 12 MHz crystals are more than abundant, and more than cheap enough.

In short – if you plan to put USB devices on your board, get some 12 MHz crystals and you’ll likely be well-prepared. Why the 12 MHz specifically? It’s directly related to a common USB 2 device speed, of which there are three.

The Three Generations

You might have heard of USB 1.1 and USB 2.0 standards, supposedly, being entirely different beasts – that’s true, but nowadays this distinction can be misleading. In practice, there are three versions of USB 2 you should actually distinguish.

These three versions are: low-speed at 1.5 Mbps, full-speed at 12 Mbps, and high-speed at 480 Mbps. The USB 1.1 standard only described the 1.5 Mbps “low-speed” and 12 Mbps “full-speed” devices. The USB 2.0 standard covers both of these modes, too, but also adds the 480 Mbps “high-speed” mode, which operates quite differently on the hardware level, and a number of other improvements.  Modern devices are most often USB 2.0, even if they’re 1.5 Mbps or 12 Mbps, which is why I don’t use USB 1 to refer to these kinds of devices – it’s rarely true.

Which speed is this “USB 2.0” hub? Well, it could be any of the three – plug it in and find out. In my experience, this particular hub is unlikely to be well-built. By [メイド理世], CC BY-SA 4.0
In fact, I’ve just checked, and all of my 12 Mbps USB devices report compatibility with USB 2.0 standard – my Logitech Unifying receiver, the internal Bluetooth adapter of my Intel WiFI card, and a USB-C 3.5 mm jack DAC from Apple. By the way, you can learn about your plugged-in USB devices and their speeds on Linux using lsusb -t and lsusb -v, and on Windows, you can use something like HWInfo. Bottom line is – the device speed is what matters, and the standard version doesn’t matter as much, whether it’s 1.0, 1.1, 2.0, or a secret fourth thing.

Flash drives and Ethernet or WiFi adapters are bound to be 480 Mbps, whereas devices like mice, keyboards, fingerprint readers, or USB-UART adapters are typically 12 Mbps. The three speed standards are expected to be compatible between each other – for instance, 480 Mbps devices are expected to be able to fall back to lower speeds if needed, and 480 Mbps hosts are designed to support 12 Mbps and 1.5 Mbps devices. The USB guarantee is that you can plug anything into anything, and generally, it works out.

Microcontrollers, sadly, rarely reach 480 Mbps on their USB peripherals, as much as that would make all our Pi Pico logic analyzers shine. There’s some fundamental reasons for this – 480 Mbps signaling is entirely different from 12 Mbps and 1.5 Mbps, with the 480 Mbps signal looking much more like a modern day differential pair, and 12 Mbps signal being firmly 3.3 V-referenced, in effect, a logic level signal a la UART. This is why you can easily capture lower-speed USB with a logic analyzer or a Pi Pico, but you can’t do that for 480 Mbps anymore.

Of course, some hosts don’t handle the inter-speed compatibility aspect well. This is generally a matter of driver support – famously, the Raspberry Pi 1 Model A, without the onboard USB hub and Ethernet chip, initially didn’t work well with mice and keyboards and other low-speed devices on its sole USB port. Specifically, its only USB port that was connected directly to the SoC. On the far more popular Model B, the onboard USB hub acted as a “proxy” of sorts, handling the lower-speed USB devices internally while keeping a full-speed link to the SoC, so the SoC on the Model B only actually talked to a single full-speed device and the driver issues never surfaced. The driver quality has come a long way, and the Pi Zero no longer experiences this problem, however, but other devices of yours might – if that’s the case, remember that you can always add a hub in between.

On the other hand, over a dozen years ago, when high-speed 480Mbps devices became more popular, PC front panel cabling was often designed for the somewhat more lax physical requirements of lower-speed USB, and even stretching those requirements. Remember the advice to plug your USB device directly into the motherboard port if it’s not working well? Often, the shoddily built front panel cable was the reason for that. Not to mention that most front panel boards never had any capacitors on them, something that dramatically helps your USB device stability when you’re adding a host port.

Oh, and the usual reminder, these data rate numbers are megabits (Mb) per second. If you want megabytes (MB) per second, you want to divide by 8, and then some more because of the data transfer overhead. In practice, if you have a 480 Mbps flash drive, expect transfer speeds of 30 MB per second or so; same goes for USB2 WiFi and Ethernet adapters, of course. This was another well-known problem with Raspberry Pi boards before Pi 4 – lowered transfer speeds when using Ethernet and USB devices at the same time, since all of them had to go through a single 480 Mbps link to the SoC. Then, with the Pi 4, the SoC acquired a PCIe link and a separate GMII link for Ethernet, and nowadays this complaint is history.

Conventions, Pinouts, Colours

Follow these colours and pinout as much as possible. Based on drawing by [Fred the Oyster], CC BY-SA 4.0
USB2 has a well defined standard for wire colours and connector pinout. You shall try and preserve both the colours and the pinout as much as possible, because such conventions help everyone involved. Debugging a device for hours because you confused ground with data, or burning up devices because you mixed up power wires – these scenarios are disastrous and entirely preventable if you stick to the colors that everyone uses!

Red and black are 5 V power and ground – a good ground connection is required for USB to work. Wondering just how much current you get? The answer is, 500 mA is guaranteed, and 1 A to 2 A is exceptionally likely; I’ve talked about it in more detail in this article.

Green and white are D+ and D-, the two pins in the diffpair. Again, preserve these colours where possible! Cables are very likely to follow these specifications, and if you memorize the colours, you can easily wire up your own tech in no time. You can remember the colours through a mnemonic – green is summer (life, +), and white is winter (death, -). The standard pinout for USB-A and MicroUSB/MiniUSB connectors is VCCD-D+GND, and it’s easy to remember too – you sit next to a fireplace (power) in winter, you go to the beach (ground) in the summer.

A USB standard, or a warcrime? Who’s to say. Though, maybe it’s my anti-HDMI bias speaking. By [C0nanPayne], CC BY-SA 4.0
MicroUSB (and MiniUSB) has an ID pin right next to GND, a pin originally intended for indicating whether your phone’s MicroUSB socket should switch into host mode, and later growing into a proprietary mess of a pin. In those dark times, it was used for video over MicroUSB standards like MHL, debug port summoning using bespoke resistor values, and even combined charging and host modes – none of it documented or prominent in any reasonable way. You rarely ever need to bother with the ID pin – nowadays, USB-C does that the ID pin ever could and way more, and it’s clear the primitive proprietary ID pin signaling standards have inspired the well-structured standard that is USB PD.

Unlike some nice standards like PCIe and USB 2, you have to connect + to + and - to -, no crossing wires. It won’t hurt anything electrically if you flip them, though, so if you’re reverse-engineering a device with USB 2 on a custom connector, feel free to connect it one way, plug it in, check dmesg or Device Manager. If you see enumeration faults, just unplug, flip the wires, and plug it in again. One warning, don’t solder on the data wires of a device plugged in, that can easily kill your device! A flipped connection where both wires still make contact is guaranteed to still result in enumeration, just that it will error out – you can use that as a way to check your connections, too.

Which connector do you use for USB2 on your own devices? Without a doubt, USB-C is the best and most universal choice; don’t be like Raspberry Pi Foundation with Pi Pico boards, forcing us to tap into our ever so dwindling supply of microUSB cables. Remember, you only need two 5.1 kΩ resistors (or 4.7 kΩ, or two pairs of 10 kΩ in parallel) to properly implement a USB-C device port, or two 51 kΩ resistors to implement a host port. Don’t be a fool, USB-C your tools.

What if you want an embedded USB port, in a low footprint? My advice: you should put USB on JST-SH sockets, just like QWIIC, which is an I2C-on-JST-SH connector and pinout standard that you should also use. I used to put USB on the JST-SH pins in a way that mimicks the USB-A pinout, but now, I use a riff on the QWIIC pinout – GNDVCCD+D-. Yes, I told you to use a pinout, but this one is for a good cause – it avoids killing devices if you accidentally plug a QWIIC device into a USB JST-SH port, or vice-versa.

Bringing USB2 Places

You can pull a USB 2 link for up to five meters, in theory, though three or four meters is way more likely. Two meters is the longest that you usually see in USB2 cables on the market. You’ll want seriously proper cables for five meters, of course, because that’s where things start to get touchy. When it comes to link quality, USB 2 can take a beating – until it can’t.

You might have seen USB 2 operate in some pretty bad conditions – dirt cheap USB hubs routed on a single-layer cardboard-backed PCBs, no impedance matching whatsoever. Indeed, you can get away with this more often than not. However, if you’re pushing USB 2 to its 480 Mbps limit, maybe you’re just putting a hub on your board and exposing some ports, beware – you might just get an unpleasant surprise in the shape of USB errors in your OS logs. By the way, on Linux, you can check for these errors by looking in dmesg – run dmesg -Hw to get a view on what’s happening with your kernel, including any USB errors that might occur.

The RP2040 with its 12 Mbps max speed might not have to impedance match, though the Pi Pico does, but if you’re designing a hub and you want stable 480 Mbps, you should certainly remove length differences between tracks in the USB 2 differential pair, and at least attempt to impedance match your tracks – again, treat your diffpairs with respect. Off the board, same goes for making sure your D+ and D- wires are a twisted pair.

That’s enough for today – next time, let’s talk about ESD diodes, USB2 hubs, connectors, debug tools, bitbanging, descriptors, and a fair bit more. At the same time, let’s explore USB3 – USB2’s younger sibling, so alike yet very different.

6 thoughts on “Ubiquitous Successful Bus: Version 2

  1. Warcrime is an understatement. Everything HDMI touches, tuns to sh…t.

    HDMI is such a pain. Got the datasheets and I2C register definitions?…then you cannot buy the chips. Found someone willing to sell you the chips?…good luck getting the I2C register definitions (sometimes you can get the datasheet though, but still completely useless without the I2C definitions).

  2. I never got around to writing firmware for micrcocontrollers on the USB Bus Bus… but I once did hook up the ubiquitous USD 10 Logic analzyer (Cypress CY7C68013) and sniffed some low-speed data going to/from a mouse, keyboard or UsbASP (Based on the bitbanging V-USB from Obdev) I guess that will be handled in more detail in the follow up. I was quite amazed about the details of low level signalling I was able to capture with Sigrok / Pulseview and that simple hardware. From T-states and checksums and keep alive messages, and other stuff that is completely necessary to debug a project, if USB does not work properly (yet) and thus your OS does not log any messages for it.

    As for USB 1.1. I thought it was fully obsolete / deprecated and superseded by the 1.5Mbps and 12Mbps versions of USB2

  3. “On the far more popular Model B, the onboard USB hub acted as a “proxy” of sorts, handling the lower-speed USB devices internally while keeping a full-speed link to the SoC, so the SoC on the Model B only actually talked to a single full-speed device and the driver issues never surfaced.”

    Except that this was also incredibly buggy at initial release. If I remember rightly, some of the time the Pi driver would split up the messages to the hub requesting translation to low or full speed in a way that wasn’t actually allowed by the spec, which would wedge the logic in the hub and cause USB devices to stop working. The Pi Foundation and the community blamed users for these problems originally, claiming that it must be caused by them using inadequate power supplies or the wrong keyboard and mouse when in reality it was simply unable to reliably talk to any keyboard, mouse or other low or full speed USB device via any high speed hub including the onboard chip in the Model B. Some member of the community with a USB analyzer eventually caught the problem.

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.