A very nice writeup and intro into USB, although - it's very focused on using an ST microcontroller, which is a lot more steps and toolchains compared the the recent ESP32 ecosystem that offers a number of easy plug-and-play ways to make USB devices work (for example, several projects from Adafruit's learning pages provide basic use cases). Another issue is differential pairs - having designed several working USB boards myself, this has not a concern for beginners, mainly relevant for doing high-speed work. USB controller ICs (as used typically with arduio/esp) can handle a lot of the details for you, so doing the calculations seems overkill, especially for someone making their first gadget.
I recently built a small hand-wired macro pad using an Arduino Pro Micro equipped with ATmega32U4, it's apparently quite popular amongst hobbyists building custom keyboards. Quick and fun project for a beginner, the most tedious part of this project was to carve the wooden case.
Do you have a link to a PCB/kit, preferably with LEDs? Does yours run QMK? It sounds like a nice project if it costs a few bucks to get the materials, though I don't know what I'd do with it.
I didn't used a kit, but bought the components separately (microcontroller, key caps, switches, wires). It runs custom code as it was sufficient to fit my use case, though QMK may be possible? The keys are mapped from F13 to F22 and can be use in some software that allow custom keybinds.
This is great, thanks! I had researched extra F keys when I was making my keyboard (exactly to use as macros) but I hadn't discovered F13 to F22, thank you! That's exactly what I needed.
I think it is nice to have a basic understanding of differential pairs and impedance, I will admit I never really had to do the calculations since the ecad software I use has several tools for routing differential pairs and even analyzing signals for impedance. But as long as you keep your traces really short it normally doesn't matter.
I just looked up the USB2514, and it would seem to not support PerPortPowerSwitching. (used by e.g. uhubctrl to toggle/switch power to individual USB ports). Am I not reading the specs correctly?
I was able to reset downstream USB devices using usbreset to the individual ports (or the entire hub) in my design, using usbreset. I did also have a hardware reset built in using the cfg_sel0 and cfg_sel1 pins 24 & 25 and RESET_N. I did not try to turn off power to those ports for any extended time so I am not sure if that works.
I used to test devices for USB compliance a long time ago. One of the things I often saw problems with was the inrush current test. Basically too much bypass caps on the 5v. I didn't see it mentioned in the article. It's really easy to get focused on the high speed digital design but for compliance it's sometimes the less sexy stuff that gets you. No idea how this stuff works with newer versions of the standard but it seems like there still is a test. Nice article though.
What devices do people use to limit inrush current? You can make a current limiter with a few transistors, but I'm guessing there must be better integrated solutions (e.g. with temperature protection, etc.)
I only saw this topic recently. Sorry for replying 2 days after everyone else has left...
------------
I like the pMOS constant-slew rate trick myself.
A number of voltage-regulators have soft-start ramp-up already built in. But if your project doesn't have one, you can build it out of pMOS pretty easily. With just a resistor + capacitor on the pMOS (serving as negative feedback, to slow down the start), you can arbitrarily slow-down inrush current to whatever values you wish.
Constant-slew rate voltage control vs a capacitive load effectively creates current-controlled startup functionality. So its "good enough" for most people's purposes (assuming capacitive loads are what's causing you to be worried).
So its a bit of an A-problem vs B-problem here. I'm giving you a slew-rate controlled soft start circuit when you asked for current control. But... its probably what you want?
> but I'm guessing there must be better integrated solutions (e.g. with temperature protection, etc.)
I believe the "proper" solutions are called a "load switch", of which there are a huge variety of integrated chips and MOSFETs with load-switch (constant slew rate + temperature control) solutions available.
Things get rather complicated as you edge into "proper" solutions. I'm just a hobbyist though, so I don't have much experience with these "proper" designs.
EDIT2: Maybe that NXP Load switch is a bit "too full featured" for most projects. This TI one I found seems to be more mainstream and simple. TPS22950CQDDCRQ1 (https://www.ti.com/product/TPS22950-Q1)
You can use inductors. Some USB cables have a choke on them. But basically the problem is when a large amount of circuitry all powers up at one when you plug in. So everything connected directly to USB 5v with a lot of large capacitors to filter the power. If you really need that then you can self power and avoid the problem.
If the answer to excessive in-rush current (due to capacitance) is to add series inductance, then: Isn't the more-efficient answer simply less capacitance?
I think the correct answer really depends upon what you are trying to do. Sometimes where board space and cost are not an issue people use a combination of larger and smaller bypass caps to reduce switching noise. I don't think there is a one size fits all solution because people power many different types of things from USB. It's more just a caution about USB power in general. Most people know the 500mA current limit, but in-rush compliance is something you don't really see in functional testing because typically you can get away with a violation and the board will still work.
AMC7135 might work: it's a linear LDO fixed current regulator designed for driving LEDs, which internally is basically an N-channel MOSFET which holds it's gate voltage in the linear region and actively adjusts it to provide constant current.
A note on USB-C, to augment the article's note: Wire the CC pins to appropriate resistors, or it probably won't work!
And a note on the differential routing and impedance: For USB 2.0, it's not a big deal. Keep the traces of similar length, and reasonably direct. Probably next to each other. You probably don't need to worry about fine-tuning the length and trace widths, impedance control, RF best practices etc. Just connect the nets.
480MBit/s is fast enough that you do need to worry about best practices and impedance matching within 10% or so. Many MCUs will also need series resistors between the USB PHY pins and the connector.
Will you need to respin a board because you needed to use a 20 mil trace instead of 24 mil? Probably not. All things considered, laying out a USB 2.0 differential pair is pretty low stakes. But you should still try and do it right - it's good practice.
But if you are worried about soldering more fiddly stuff like those ARM processors: It doesn't have to be that big, STM32 is nice if you need the power, but for smaller stuff smaller controllers can be preferrable.
Also very easy, if you are inclined towards Arduino style programming there are tons of boards you can just use as USB devices with the included libraries in very few lines of code, for example
https://www.az-delivery.de/en/products/digispark-board
Very similar to the NUCLEO-F103RB board the post author used, but as well as the USB connector at the top of the board for the built in programmer/debugger, it also has one at the bottom of the board, wired straight to the microcontroller.
You can also download the board's schematics, if you want to copy their choice of ESD protection and suchlike.
There's also things like the CH32V203 [1] which is a TSSOP-20 with hardware USB and costs around $0.81 in singles. The software side might be a little more ... challenging, though.
They offer some fairly usable example reference code for a lot of the on-chip functionality-- including USB peripherals. I was able to turn their CH32v3xx examples into a pretty capable custom-keyboard firmware.
Ive written bare-metal USB code on an MCU before, and I found it to be quite a shock compared to simple digital protocols like SPI or I2C. The physical and data link layers aren't much more complicated than, say, CAN, but beyond that you immediately run into a brick wall of descriptors, endpoints, and driver configuration. USB was designed from the ground up to be a plug-and-play ecosystem for PCs, and it really shows. Using the vendor-provided software as much as possible is definitely the way to go if you can.
Some half-remembered hints: You want bulk transfers for high throughput (don't even look at isochronous). USB is a master/slave protocol so if you're not getting peak throughput it's usually due to something on the host (PC) side. If the license (LGPL) is compatible with your needs, libusb is pretty easy to use. If you're not using the vendor driver, a hardware USB protocol analyzer is really helpful. USB in a NutShell[1] is a decent web reference for understanding the protocol.
OK, dumb question, but since we're talking USB on STM32: Does anyone know how to support receiving more than 64 bytes in a frame? I've been looping over 64 byte frames in software, but I know it's possible to go higher. (Up to 1Mbyte I think). The problem is, the Reference Manual lists settings for this that are not normal registers. They are a pseudo-register of some sort. Wondering if there is an easy workaround for this! (The non-OTG USB peripheral)
A single BULK USB endpoint can only support 64 bytes per transfer. You could make use of multiple endpoints (8 are available in total) or switch to isochronous endpoints which can support up to 1023 bytes per frame.
Most hardware support for isochronous transfers requires DMA on the MCU side, so it tends to be a pain unless your vendor has a library that handles it for you.
You can in general send up to 19 bulk transfers in a single frame (even on a single endpoint), but again, vendor libraries differ wildly in their support for this.
Note that isochronous transfers require kernel-mode drivers on the host side, so you won't be able to use libusb in that case. Bulk transfers are the way to go if you want high throughput.
Isn't the restriction just on the reception side? So, if you have a MCU talking to a PC or another MCU, you can send however many bytes you want, but not receive? I say this because A: The Reference Manual only indicates this limit for reception, and B: I only experienced this on reception: PCs seem capable of sending and receiving messages larger than 64-bytes, and STM32s seem capable of sending messages larger than 64-bytes, but not receiving (without isosynchronous, or anything special)
The limits on packet size are based on the transfer type (control, interrupt, isochronous, or bulk) and whether the connection is low speed (1.5 Mbps), full speed (12 Mbps) or high speed (480 Mbps). The USB module on the MCU will be designed for the largest possible packet, which IIRC is a full-speed 1023-byte isochronous packet. (MCUs usually aren't fast enough to reach high speed.)
Data larger than one packet can be sent as a multi-packet "transfer". This is where bulk transfers get their throughput -- at full speed, the largest bulk packet is only 64 bytes, but you can send 19 bulk packets per 1-millisecond frame, which gives 1216 bytes/millisecond, more than the 1023 bytes/millisecond possible with isochronous.
You might be able to force the hardware to send nonstandard packets, but then it's not really USB any more.
I use ESP32 mostly but I have a cheap hack that fits a lot of projects...
For super quick easy custom controllers, also consider pulling the control board from discarded USB keyboards. Use conductive glue instead of solder to attach wires to the contacts, and a helping of hot glue to keep them secured. I've made cheap but very robust 1-button game controllers with an arcade button that sends a space bar click. You get all the debounce etc, no code.
Are there any development boards with USB 3 support? I'm trying to prototype a USB C monitor sink but having trouble finding a board that has the power necessary to receive DisplayPort over USB.
There is not much power needed to receive DisplayPort over USB (assuming you already can receive displayport signals or just route them to an external monitor).
You just need to implement an USB billboard device (optional to make it work, but required by the spec IIRC) and signal the correct alternate function. Then DisplayPort signalling will be present on the USB-C plug. Then just connect the right AUX wires to the DisplayPort connector.
This device is not really suited, it is a high speed USB3.0 peripheral. You might be able to use it with the right software, but then you are just using the CPU in it.
The way how the Cypress FX series works (and for that matter majority of non-trivial USB-to-something chips do) is that there is a bunch of DMA-capable peripherals inside and the in fact ridiculously underpowered CPU core inside only sets up the required configuration for the DMA transactions to happen.
I've been using https://github.com/xairy/raw-gadget to create a virtual USB device on my raspberry pi I've got plugged into my PC.
I'm currently using It to emulate a MTP camera so I can spoof some proprietary software.
fwiw; I've prototyped some USB gadgets using Raspberry Pi Zeroes and Composite USB in the Linux Kernel. At least storage and serial devices were pretty easy to get going.
You'll need something like a shell script on the Raspberry to initialize the composite kernel module and you'll find the boildplate in the kernel docs.
I would love to play with pis and make virtual usb devices, like a webcam.
pikvm is an interesting project.
It will hook to a PC, and the USB connection can not only pretend to be a keyboard and mouse, but it can be a USB drive that you can boot the system with. Pretty interesting for installs.
For hobbyist use you can just pick a random value and it'll usually work. Open-source hardware can get a product ID for free from https://pid.codes. Small-run commercial hardware can usually get a free product ID from the maker of their USB-capable chip. And once you're big enough that you're designing your own chip, $6,000 isn't such a big deal anymore.
So yes, you are technically right, but it really doesn't matter all that much in practice. USB is by far one of the most accessible major hardware standards out there.
Many chip vendors will give you a PID under their VID if you're making a product. For example this blog post uses and ST chip, and they'll provide a PID if you request it [1] - free of charge, but subject to some conditions.
(Of course if your USB device needs Windows drivers, you'll still have to deal with things like code signing...)
The part that makes me feel most uncomfortable about usb VID/PIDs is that they are only 16bits each. While I don't think 4billion unique commercial USB devices is limit we will reach anytime soon, efficiently managing the available address space is a different question. And unlike IPv4 addresses a range of USB VID/PIDs can't be as easily reused without making the VID/PID meaningless.
By that time they'll just add an extra field to the protocol and assign a special "see other field" VID/PID pair.
For a lot of products the VID/PID combo isn't that important on a protocol level, and there's technically no reason why two completely unrelated products couldn't be using the same pair. In practice you're mainly going to use them for software to target a specific device, for example the Linux HID driver uses it to work around hardware/firmware bugs. But HID devices are self-describing, and that's the main mechanism used by the driver to figure out what has been attached and how to behave.
If modern OSes can do the same to distinguish hardware with the extra field, sharing the same value for backwards compatibility with legacy machines really isn't going to be a big deal. It's not like MAC or IPv4 addresses where a clash will essentially kill all communication.
The problem isn't the combined limit, it's the hard limit on Vendor IDs at 65,535.
Since very few companies have 65,535 products, almost all Product IDs in any given Vendor ID namespace are unused.
That is the maximum number of organizations on Earth that can be issued a USB Vendor ID until the spec is modified. They'll likely introduce a special Vendor ID that indicates to clients they should look elsewhere for the real (and longer) one.
While the rules were more lax many years ago, and some vendors are grandfathered in and can therefore share their Product ID allocation, these behaviors are explicitly prohibited by the USB-IF for newly issued Vendor IDs.
Yes, for a single-use hobby product it doesn't matter much and you can just risk the collision.
And yes, some vendors will generously let you have a Product ID under their Vendor ID, but then your product looks as if it was made by them when your customers plug it in.
If you plan to deploy more than a few devices you'll need a Vendor ID and people should know that there is a relatively large tax in front of that need.
Hard disagree on $6,000 not mattering. We build a small number of devices for severely disabled people and sell a few hundred a year. The USB IF was unwilling to budge at all on their prices and this was a large cost that we did not anticipate, and by the way, is technically shameful.
How much does a fucking number cost?
Well, it depends on how scarce you decide to make it, and of course, what the market will bear.
NXP runs a USB VID/PID Program [0] for small production designs (<10,000 units) that use their MCUs. They’ll give you 3 PIDs for free under one of their VIDs. I use this in my side projects (~200 units) and works pretty well!
.. or use someone else's. I believe there's a hobbyist VID under which you can reserve PIDs, or in many cases you can just copy an existing product if your device is generic enough and you're not planning to sell a big production run.
There's pid.codes which uses a vid of a defunct organization, but before that there was also the F055 vid. I still use that vid because no company will accept that vid, since it's commonly used by foss projects.
> I will think twice now before saying “why couldn’t they just use USB for this?”
I dunno, I think either you're doing a small run and you can just bake in a Teensy or whatever, or you're doing a big run and $6k is a drop in the bucket.
Yeah, I was going to ask about this. I think ST Micro will sublicense you a PID under their VID, but with restrictions, and companies attempting to buy a VID and sell PIDs as a service have been sued?
what about converting existing devices from USB-A to USB-C? I have a bunch of powerbanks lying around that I'd love to keep using but most of my devices now use a USB-C charging cable, would it be a simple case of replacing the ports and re-soldering or is there any extra component I need to add?
The wiring of the ports on a new design is straightforward; you are using the same pins if it's USB 2.0 (As the article says), plus two extra connections that go to a resistors. If you can find ports that use the same footprint, feasible, but probably not worth it. Desoldering a port is a pain because you have to get all the pins to melting temperature concurrently, and you'd have to figure out how to wire those CC pins.
I recently used CH340N (soic 8 virtual com port) and it was really easy. Easy soldering, no extra parts just directly connect to USB, works out of the box on Linux.