This is a really interesting thread. I am interested in developing a joystick port (up/down/left/right/space), that can also potentially act as a USB keyboard port, so I've been studying what everyone has said. I've spent some time over the last couple of days doing a further deep dive on this.
I've come up with a fancy way to do it, and the more obvious brute-force way. I have come to feel that the brute-force way is better, am interested in people's thoughts.
My goal is to provide a little board that interposes between the existing keyboard cable and the keyboard, that allows simultaneous use of either the stock keyboard or the external joystick and keyboard.
I'd like it to be microcontroller-based so that it can do things like acting like a keyboard, or dealing with other kinds of joystick encodings. One can also imagine automating test sequences that are more expansive than any one software package, like "Boot into this FreHD partition then..."
MT8088 Approach
The short summary is I think I'm going to go with the MT8808 approach:
- Pro: It has internal registers that remember the state of every switch. As mentioned by Eudimorphodon, this means that you don't have to time what you're doing to the keyboard scan.
- Con: When powered from 5V, the on resistance of the switches is quite high, as high as 225 ohms.
- Slight con: It's an older chip and is addressed in parallel (9 pins in all) rather then over I2C or SPI. That actually makes it a little easier to program at the expense of more pins.
The 225-ohm on resistance was a significant concern to me, but I think it's okay. Back to that in a moment.
RP2040 Approach
Using a Raspberry Pi Pico, or a RP2040 Zero or the like, there is plenty of horsepower to make all the decisions one needs to make in a fraction of a microsecond. The software part seems pretty easy (even for multiple simultaneius key presses), but the hardware is tricky.
The tricky part is, how does the RP2040 detect when the column scan lines go low? The problem is that, unless a key is pressed, the state of the scan lines is indeterminate, because they are driven by open-collector 74LS05's and there is no load resistor on the line unless a key is pressed.
So you can't simply hang a microcontroller off of them and read the scan lines. You have to add a pull-up resistor. Fine, the RP2040 has internal pull-ups. But they are in the 50K-80K range. If you assume perhaps as much as 100pF of capacitance on the line, you end up with an 8us time constant and 25us rise time, way too slow to meet the 1us requirement that Eudimorphodon has called out.
So you have to provide a strong pull-up. Not surprisingly, if you run the numbers, you end up at something like 1.5K being a good value, which turns out to the be the value that the TRS-80 actually uses in its design. But
- The stock pull-ups only are active and consuming power when an associated key is pressed
- If you have two 1.5K pull-ups, you're pulling 3.3mA through all of the LS05 outputs all the time, and 6.6mA when a key is pressed. The part is rated for 8mA max. So it's okay, but I'd rather not burn all that power all the time, and it's exercising the LS05 in a regime under which it was never tested in the TRS-80.
I decided on instead using 20K resistor together with a MAX20326 I2C bus accelerator (the LTC4311 is another option but is pricey). Each chip only does two pins, so you'd need four of them, but they are tiny. These are smart devices that sense the initial rising edge and then turn on an active pullup. Then you end up with this sort of thing. Assuming the RP2040 is powered from 3.3V, you'll need a diode to protect its input, but it's not bad.
So now you can scan the keyboard.
On the output side, at first I was just planning on driving the lines with open collector buffers, but you run into a second issue which is "when do you actually let go of the output scan line?" There's a possibility of driving it for too long. You need to first wait for your active pull-up to notice that the input scan line has been released, then for it to pull the line up, then for the software to notice it, then you have to turn off your gate. There might be a good fraction of a microsecond delay from when the LS05 releases the line to when our scan line driver actually releases it. Only then will the stock 1.5K pull-up begin its work of charging the line back to 5V.
So I tried adding my own active pull-up to the output of my open collector gate, and realized that I was actually building a CMOS gate out of parts. So I realized that what was wanted was a tri-state output instead. If one is using a 5V microcontroller, this can come from the micro itself. With a 3.3V device, one would use something like a 74HCT125. So just showing a couple of the output lines, it looks like this.
What happens here is that
- Normally all the Enables are off.
- When an input scan line goes low, we set the "Scan Drive" output to 0 and then assert whichever Enables are appropriate
- When the input scan line goes high, we set "Scan Drive" to 1 briefly. This is our "active pullup".
- After 250ns or so (or if we see a new scan line go low), we reset all Enables to off.
It gets a bit funky when multiple scan lines turn on at once. I think that might all work, but it's really pretty complicated.
Back to the MT8088
So after all that, I looked more deeply at the specs for the receiver chip. Curiously, the TRS-80 designers don't feed the keyboard matrix directly into the 74LS240 that buffers the results onto the data bus. Instead, they send the signals first through a MC14050B, a CMOS device.
One assumes that this is done for noise immunity reasons. The logic-low threshold for the device is 1.5V as opposed to TTL's 0.8V threshold.
That turns out to be good news for the MT8808 approach. Even with a 250-ohm on resistance, it should be capable of pulling the 1.5K pull-up down to 0.7V. That might be iffy with a TTL input, but is in the happy space for the CMOS device.
So, I'm thinking MT8808. It's an old device, but Digikey happens to have some stock right now, and Mouser as well. Those are PLCC's. DIP versions are available on AliExpress. There is a more modern device, the Analog Devices (Maxim) MAX14724ETP+. It's an 8x4 array not 8x8 so it would take two of them, but it is programmable via I2C or SPI and is easily ganged, and has a better on resistance. However, it's only available in TQFN, and it seems to really prefer to operate off a bipolar power supply.
Certainly the MT8808 makes the microcontroller a lot less busy. You don't need the horsepower of a RP2040 so could use a 5V device, which is kind of what you want to use with the MT8808 anyway.
UPDATE: I did a quick test and "shorted" two of the scan lines with a 300-ohm resistor. I got keypresses. So MT8808's on resistance should be fine.
Thoughts? Any reason to think that that's the wrong answer?
Thanks,
Brad