Yes, it is. It was intended to require as little silicon as possible to minimize the cost to the transistor budget. SPI doesn't contemplate power supply, hot-plug, discovery, bit errors, or any other of a host of affordances you get with USB.
I think there is some value for software developers to understanding SPI and the idioms used by hardware designers with SPI. Typically, SPI is used to fill registers of peripherals: the communication is not the sort of high level, asynchronous stuff you typically see with USB or Ethernet and all the layers of abstraction built upon them. Although there is no universal standard for SPI frames, they do follow idiomatic patterns, and this has proven sufficient for an uncountably vast number of applications.
You couldn't make it quite as simple as (a given flavor of) SPI, but something close to I²C should be feasible.
That'd be https://en.wikipedia.org/wiki/System_Management_Bus
Well, okay, I guess SMBus ARP kind of does. Thanks!
If you simply remove this restriction, bit-banging USB would become trivial, even with all the other protocol complexity.
Though, I think USB made the right call here. The requirement to support any clock speed the device requested would add a lot of complexity to both hosts and hubs.
Only supporting a few fixed clock-rates makes certification and inter-device compatibility so much easier, which is very important for an external protocol. Supporting bit-banging just isn't that important of a feature, especially when the fixed clock rates really are that hard to implement on dedicated silicon.
In V-USB, usbdrv/.[ch] contains 1440 unique lines. The bitbanging stuff is mostly in .S *.inc, so correct me if I'm wrong, but I think this is roughly the non-timing-related complexity imposed by USB protocol stack. (This division is not perfect, because there are things in e.g. usbdrvasm.S which have nothing to do with bitbang timing, but I feel like it's a reasonable approximation.) The remaining complexity in, say, examples/hid-mouse/firmware/main.c is only a few dozen lines of code.
And that's a USB device. Implementing a USB host is at least another order of magnitude more complexity.
You definitely don't need 1000+ lines of code to implement, say, the PS/2 mouse protocol. From either side.
So, while I agree that a lot of the difficulty of bitbanging USB results from its tight timing constraints, I don't agree that what's left over is "trivial".
I would love a protocol you outline, but could you use SPI as the physical layer and put the rest on top?
You could hypothetically use a really-really high bandwidth oscilloscope (like 2 GHz to view 480 MHz USB HS signals), but those are expensive. So you would have to resort to using external USB sniffer...out of curiosity I found someone made a sniffer that is basically a USB-capable microcontroller plus an FPGA and a USB PHY: https://hackaday.com/2023/06/13/cheap-usb-sniffer-has-wiresh...
I believe your confidence in the 16-bit CRC is excessive. There is a 1 in 65536 chance of a 16 bit CRC failing for certain types of corruption in 512 byte bulk USB packets, and there are about 2 billion packets in a 1TB transfer. If the BER is high, corruption of the transfer is not surprising.
A 6ft cable should be fine, assuming it is well designed, manufactured correctly, in good condition, and not in close proximity to high noise sources, such as SMPS. If any of those factors are compromised the BER will increase, and you will then be testing the rather limited capabilities of 16 bit CRC.
USB4 has 32 bit CRC for data payloads for a reason. In the mean time, the #1 thing you can do is use short, high quality cables.
Glad to see that USB4 is fixing things but one thing I worry about is if this 32 bit CRC is a mandatory part of the standard that cannot be turned off or ignored by manufacturers. Especially since it apparently is not transparent to users.
The reality is that the simple protocols like SPI and I2C just are not good enough. They aren't fast, the single-ended signal scheme makes them very sensitive to noise, and there is no error correction. These protocols make sense and work extremely well for their intended purpose: connecting ICs on a PCB. If you expose an unterminated port to the outside world, all bets are off.
These protocols and variations thereof are still in heavy use in modern PCs. But they're internal busses, as the protocols intend.
I haven't looked closely at the USB spec, but I imagine the main problem with bit-banging is simply the speed required. You have to have dedicated hardware because no microcontroller is fast enough to toggle the pins while also running the software stack to decode the protocol and manage error correction.
You can run into this exact problem bit-banging I2C. With a 20MHz CPU, the maximum clock speed you can get is about 250KHz. Just a bit more than half the typical maximum rate of 400KHz. You can absolutely forget about the 1MHz version.
PHYs exist for one very good reason: it is vastly cheaper to offload comms protocols to hardware. Without that, you have to over-spec your CPU by quite a lot to get enough resources to manually manage communication. This is why every modern microcontroller contains hardware for I2C, SPI, serial, etc.
In summary, the simple serial protocols like SPI and I2C and UART are just absolutely terrible choices for external peripherals. They can't operate at reasonable speeds, they can't tolerate long cables, they can't tolerate noise. The nature and design of these protocols (excepting RS232 which is not UART) means that they cannot be used this way. There's no change to the spec you could make to support this without reinventing USB.
(In my original comment I should have said to use differential signaling for going off-board.)
This was a bit of a surprise when I started, but then I realised that many installations are decades old, with components having been replaced individually.
Googling for "CH570" produces results about tractors. Got a link?
EDIT: found info here: https://www.cnx-software.com/2025/04/02/10-cents-wch-ch570-c...
8-pin part lacks USB AND only has 3 I/O pins. It would be disqualified due to being too I/O-poor. Wasting 5 pins out of 8 is a joke!
As for the old one, CH32V003: 48MHz is slower than the STM's 150MHz, half the flash, 1/4 the RAM. It is still not the best option.
I did update the article with them, though :)
But you get radio (BLE in the CH572 version), which means you don't need USB.
My comment was not that you didn't choose them but that you didn't consider them.
I just considered them and added them to my writeup :)
I'm more of a software guy. I guess my biggest hardware project (other than building a 3D printer from someone else's plans) was in 2012 or so making a PID-based home heating controller using an Uno with a custom perfboard shield with a thermistor for measuring the air temperature and a 433 MHz transmitter for talking to a set of Jaycar 240V remote controlled power outlets to control primarily a 2400W oil column heater, plus a fan pointing at it which I turned on when it was at a high duty cycle. Plus switching the home water heating on and off on a fixed schedule just as a side thing from the same board. I used that in Wellington for 3 winters before moving to Russia for a few years and saved NZ$500 per winter on electricity bills compared to previous years using a mechanical Honeywell thermostat to control the heater.
I was actually thinking of trying to make a product, especially once Flick Electric started up with electricity prices changing every 30 minutes based on the wholesale rate plus a 2c margin. You could (still can) get the current 30 minute wholesale price at your local substation from electricityinfo.co.nz with a simple http query, so you can build something to make intelligent decisions.
But then I got a job overseas and dropped the project...
I think it's compatible with the old nRF24 chips -- I'll test when mine arrives in a week or so. The CH572 version has BLE5 ... I think the same hardware but including a software stack.
In that sense it's like SPI, or perhaps more like CAN or SD: when you don't understand it, you reach for someone else to have done it for you, but you can choose to understand it and once you understand it you can implement it.
If you're the slave you have tight timing requirements but you only have to respond with certain fixed bit patterns to certain other bit patterns. If you're the master, you can do more things concurrently because the slave won't notice a little jitter in how often you poll it, but you have the problem of dealing with a wider variety of slaves that can be connected.
But there is more complexity on higher layers. USB HID (mice and keyboards) is often the first you'd want but it is special in that it allows a device to describe its own packet format in a tokenised data description language. The device only has to send an additional blob when asked, but the host has to parse the contents of that blob and use the result to parse the device's packets.
And of course, every time there is complexity in a protocol and there are multiple implementations of it, there is more opportunity for them to be incompatible in very subtle ways. This phenomenon has caused for example that some gaming keyboards with N-key rollover that work perfectly on MS-Windows without any special drivers have been rejected outright by Apple or Linux hosts. (I hope these issues have been fixed now, but I'm not sure).
Keyboard vendors catered to the lowest common denominator because it was essential that users be able to enter the PC BIOS at boot.
BTW. Apple chiclet keyboards (before the "Magic") got an interested workaround to this problem for its proprietary Fn key. It uses a variation of the boot protocol but only a 5-byte array (5KRO). When the Fn key is pressed, the sixth byte will contain a code that is otherwise an error code if interpreted as the boot protocol.
the name is escaping me