RetroUSB Happy Progress
Good news from my RetroUSB project! I finally have a working proof-of-concept, connecting a modern USB keyboard and mouse to a classic 1980s Macintosh SE computer. A microcontroller and small pile of related components perform the necessary conversion between USB and ADB, acting as a USB host and translating the input events into the Apple Desktop Bus protocol used by the Macintosh. It’s still a long way from being a finished design, but the hardest part is done, and I’ve proven that this approach can work.
Reading and writing ADB bus traffic is implemented entirely in software, checking and setting I/O pin values using hard-coded delays. The USB side of the converter uses the built-in USB functionality of the PIC32MX microcontroller. In order to avoid impacting the hard-coded delays in the ADB routines, interrupts are disabled whenever listening for or responding to ADB bus commands. These periods where interrupts are disabled can last for several milliseconds, and at first they caused major problems for USB communication, which I detailed in my previous post.
With the help of a logic analyzer, I eventually determined that the problem was caused by sending USB packets too late during the USB frame, so that they weren’t finished before the end of the frame. This was a side-effect of re-enabling interrupts midway through a USB frame, causing the PIC to start sending packets even though the 1 millisecond USB frame was almost over. Fortunately the PIC has a USB setting to handle this: U1SOF, the start-of-frame threshold. If the number of bit times remaining in the current USB frame is less than U1SOF, no new USB tokens will be started until after the next SOF has been transmitted. Through experimentation, I found that doubling or tripling the default U1SOF value eliminated the USB errors I was experiencing. Here’s a figure from the datasheet:
So the basic functions of a USB to ADB converter are now working, as you can see in the video. I can simulate multiple ADB keyboards and mice, complete with ADB collision detection and address remapping. And I can read up to eight USB keyboards and mice at the same time, directly connected or through a USB hub. I can also log traffic and statistics over the serial port for debugging. Now there are a million smaller details to address:
Brownouts. The ADB bus directly powers the whole collection of hardware, including the USB hub, keyboard, and mouse. It draws about 120 mA from the Macintosh SE, which is well within the 500 mA spec. Yet I measured the 5V line drooping as low as 4.3V, and the 3.3V supply for the PIC drooping as low as 2.6V. Sometimes the PIC’s supply voltage gets low enough to trigger a brownout reset. I’m not sure what’s going on here. Maybe my breadboard wires and hand-soldered ADB connector have a few ohms of resistance, causing a voltage drop.
Mouse Sensitivity. Initially the USB mouse was super sensitive, and only a tiny movement was needed to send the Mac’s mouse pointer all the way across the screen. I’m now dividing the mouse movement vectors by 4, but that makes motion less smooth.
Mouse Axis Mapping. An Amazon Basics brand optical mouse works fine, but a Dynex brand mouse appears to have its movement axes mapped weirdly. X and Y axis movements are combined and reported on the wheel axis, while wheel movements are reported on the X axis. This must be a software bug in the HID report parser.
Keypress Handling. I’m not truly handling USB keypresses properly, because a single USB key event is being translated into two separate down and up events for ADB. At present, it won’t correctly recognize when you press and hold a key.
Double Keypresses. Sometimes when I press a key once, it will be reported twice. Probably due to the dodgy keypress handling.
Power Button. Real ADB keyboards have a power button used to turn on the computer. This is a physical switch that completes a circuit between a dedicated ADB pin and ground. I’ll have to add a hardware button to my breadboard somewhere to act as the power switch.
Read 12 comments and join the conversation12 Comments so far
Leave a reply. For customer support issues, please use the Customer Support link instead of writing comments.
Very nice! I’ve been following this project for a while and glad you got it working. Hopefully you can sell a kit or adapter in a few months!
Nice work! I looked at the ADB protocol a long time ago and was intimidated enough not to even try anything like this…
Brownout: Adding some large caps often helps. Could also be caused by excess inrush current of the USB devices. Adding a small resistor or inductor in the +5V line of the USB port would limit the USB inrush current.
USB hub: Check for reverse supply – many cheap self-powered USB hubs simply connect external supply and +5V from the upstream port. The latter connection should be cut away. That would also explain a brown-out if the hub\’s power brick is disconnected.
Power button: Many USB keyboards (and several PS/2 ones) have buttons for Power, Sleep, and Wake-Up, with fixed scan codes. See https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html#ss1.9 Adding a simple FET to the PIC would at least allow to switch off via keyboard. Adding a small standby supply to the adapter would also allow switching on via keyboard.
Quick test for bad USB hubs: Connect anode of a cheap red LED to Pin 1 (VCC, red) of a USB type A female connector. Connect a resistor of 330 to 680 ohms, 0.25 watts, to the cathode of the LED. Connect the other end of the resistor to Pin 4 (GND, black) of the USB connector. Connect the USB hub to its power supply. Connect the LED circuit to the upstream USB port of the hub. If the LED lights up, the USB hub is reverse powering the upstream device and should be reworked or replaced.
I see low voltages even during steady-state operation, so I think it’s caps or wiring rather than inrush current. This particular USB hub doesn’t have a power supply. The odd thing is that both the 5V *and* the 3.3V measure low. I’m using an LDO 3.3V regular with a 250 mV drop, so even at 4.3V input it should have no trouble producing a solid 3.3V output. My wiring and capacitors are definitely substandard, so I’m not worrying too much about this problem yet. I’ll remeasure the voltages after I’ve transferred the circuit to a version 0.1 PCB.
Tux2000’s comment about misbehaving powered hubs feeding +5V back to the upstream USB port has got me thinking about some potential power configuration problems with the final hardware. Right now I’ve got ADB (source of +5V from the Mac), and USB-A (provides +5V to keyboard and mouse). I would also like to add USB-B, to allow for reverse ADB-to-USB mapping in the future, and also as an optional second source of +5V when the Mac is off to keep the PIC running in a sleep state. But I’ve realized I can’t simply connect together the +5V lines of these three, if I want to avoid possible reverse current flows that might damage something.
ADB powering PIC and USB-A is OK (and is what I’m doing now)
USB-A powering PIC (from a poorly-design USB hub or device) is unexpected, but probably OK
USB-A powering ADB is not OK. It might put +5V on the ADB supply when the Mac is off, which could damage something.
USB-B powering USB-A is OK. This would happen during my wake from sleep example.
USB-B powering ADB is not OK… unless doing reverse ADB-to-USB, and the ADB port has an ADB keyboard and mouse rather than a Mac
ADB powering USB-B is not OK.
I’m not sure how to guarantee the proper direction of current flow on these +5V lines. There are power switching and muxing ICs that might help, but I’d really like to keep this very simple and cheap, with a solution that costs only pennies or zero. I’m imagining something with a few diodes in the necessary positions and orientations, but that wouldn’t work due to their voltage drop and limited current-carrying capacity. Maybe something with a FET or power FET? Hmm…
Hi Steve,
Are you only doing keyboards and mice? Will you eventually do joysticks or flash drives? Are flash drives even possible?
The focus is keyboards and mice, which is everything that a vintage Mac or IIgs can readily make use of on its ADB port. Other input types might come later.
@Josh: I don’t think ancient Macs support any kind of mass storage device on the ADB out of the box. You may write some kind of device driver for ADB-based mass storage devices. But it will very likely be painful. ADB can transfer 125 kbit/s in therory. Practical data rates are half of that or less. That’s not even sufficient for ancient DD floppy drives (250 kbit/s). HD floppy drives transfer 500 kbit/s, and even that feels painfully slow. The slowest SD cards (class C2) can write at a minimum speed of 2 MByte/s, that’s 16 Mbit/s or about 16000 kbit/s. Reading is much faster, even for those slow cards. Using an USB 2.0 or newer flash stick in a USB 1.1 port would limit the data transfer rate to 12 Mbit/s, about 12000 kbit/s, or about 100 times faster than ADBs theoretical maximum. ADB is not even sufficient to drive a V.34 modem, that’s why Macs have a faster modem port that supports at least 230.4 kbit/s, up to 2 Mbit/s with external clock.
Well, yeah, I know that it doesn’t support mass storage out of the box but I’m thinking that if he’s willing to this far maybe he will write a driver of some sort. It would be slow but useful in many cases.
Josh, if you need fast mass storage, consider using FloppyEmu.
Another possible way is to use SCSI, if present. Add something like the SCSI-to-IDE adapter used in http://www.os2museum.com/wp/booting-is-hard/, and a compact flash card, and your old Mac should see an insanely fast hard disk. I don’t know if old Macs can handle MBR harddisks with FAT partitions, but on the PC side, Linux can at handle Mac partition maps and Mac filesystems. Linux does not care about the media, so you can use a simple USB-connected card reader on the PC.
This is fantastic progress Steve. Thank you so much for putting your time into this. I can’t wait to be able to order the final product.