Reading output from Compaq keyboard (serial + clock) - Page 1
Forum section: electronics / general

author: katastic
author_rank: Contributor
timestamp: July 05, 2021, 07:20:35 am
content: [Ignore noise and voltages since I've got plenty of wires running around.]5-volt TTL. Top is data, bottom is clock. It appears to be lowering edge triggered, and you'll notice a longer delay at the start for a guard bit/time/thing. I don't know if this is a good/bad/great screencap / scope window.-> Data is only sent when keys are pressed or released.I'm trying to read it with an Arduino Uno-> it does NOT appear to be following IBM AT or PS/2 spec. Which should be 8-bits, a guard bit, and a parity bit, IIRC, so we're missing one. The last bit appears to flip on/off with the press vs release of keys.I "should" be using SPI for this, right? Because it has a clock? But if I do that with some example code I get a non-stop spam of data returning 255 over and over--even with no keyboard activity--which is clearly wrong.I tried a software (bit-banged?) serial port (because, AFIAK, the Uno uses the normal serial port RX/TX for programming). I got data. But the bits don't quite line up and ... I have a clock signal, which means UART would be the wrong place here and it'll have trouble detecting transitions for clocking unless there's enough of them.So, Q: If you were going to read this data on an arduino, what example/tutorial/thought process would you be using to accomplish it? Thanks. Okay, this is interesting and odd. While its for Duo, I imagine its setup the same way. ... using arduino spi.transfer()... drives the clock. As a bus master. So if I already have a clock, they might be smashing together.https://arduino.stackexchange.com/questions/24620/syncing-taking-external-clock-for-spi-on-arduino-duehmm... now this is interesting. the data and clock lines appear as nothing when the arduino is plugged in and running. Which means either something is miswired, or the keyboard was expecting a higher impedance? Or maybe it's expecting some kind of pullup/pulldown... hmm..... the more I read about SPI the less I think this is an SPI scenario. I'm thinking (assuming it can fire fast enough) I could fire an interrupt on every clock lowering edge and manually sample the bit values.

author: woofy
author_rank: Frequent Contributor
timestamp: July 05, 2021, 09:17:25 am
content: As you say, that's not PS2 spec. It looks like straight 8 bit clocked data with the data latched on the falling edge. So you have 10101000 or A8 (or 00010101 15).Check you have consistent results for the same key press and log the codes. You should then be able to create a translation table to get the key.As to actually getting the data in, you should be able to just use a shift register, or maybe just bit bang it in code.Ben eater's video might also help you, though its for the PS2 keyboard.

author: Benta
author_rank: Super Contributor
timestamp: July 05, 2021, 07:27:59 pm
content: SPI is the wrong interface for this. SPI is a master-slave system, where your MCU is the master. It'll keep reading the signal continously, which is why you're seeing 0xff all the time.A simple 8-bit SIPO shift register would do the trick: clock it from your keyboard clock negative edge to load the serial data.The starting edge data will "fall off the end" of your shift register, leaving you with the 8 data bits. This is really simple in software.You'll need to do some timing householding to identify the inactive cycles (clock=high for some time) so you don't start in the middle of a transmission and do a timely read of the data that's come in.

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 06, 2021, 04:05:28 am
content: ATmega32u4 (as used on Arduino Leonardo, Arduino Pro Micro, SparkFun Pro Micro, Pro Micro clones (of the SparkFun Pro micro, but using Arduino Leonardo bootloader), and Teensy 2.0 has 5V logic and SPI slave support (as in ATmega32u4 is the SPI slave), plus a native USB interface so you can make it into a native USB Keyboard, so you can plug it in to any computer and it will work without requiring any drivers or such nonsense.Unfortunately, it has only 8 bit SPI support, as do most devices I have.One exception among the MCUs I have is the $20Teensy 4.0, which has native USB and all that jazz, plus 3.3V logic, configurable-word-width (8 to 32 bits) slave SPI support, with SPI to boot. It's so much overkill here it is ridiculous, but with four resistors to drop the TTL logic to 3.3V, or with a couple of unidirectional voltage level translators (I like a pair of SN74LVC1T45 here, if you have a +5V from the keyboard, or if the keyboard can be powered from the +5 VUSB), and the rest is software.With the ATmega32u4 and other 8-bit MCUs, I think I'd reach for an 8-bit shift serial to parallel/serial shift register, where the outputs are always one cycle behind the internal state, resettable asynchronously, like 74HC595. Because '595 latches data on rising edge, the clock has to be inverted. Because the '595 is reset to logic low, and I want the start bit to be logic high, the data has to be inverted too. That way, when the ninth bit is received, that start bit turns the '595 serial output high, and I could use that with a rising edge interrupt pin to detect the completion of a 9-bit word, with the data bits in the shift register. Maybe a 74HC14 for the inversion? CD4069UB? I am a butterfinger with the electronics (lots of experience with software, though), so I tend to pick ICs than discrete logic, and err on the side of caution (like Schmitt triggers).To me, it really looks like the start bit followed by 8 data bits wasdesignedfor exactly this pattern: an 8-bit shift register is cleared to zero, then the inverted data is shifted in on each falling edge of the clock; the start bit being one now. The output of the shift register turns high when it contains the full 8-bit data word. The start bit doubles as the completion bit pushed out of the shift register!Perfectfrom a programmer point of view, as it can be used to trigger an interrupt to read the byte. The MCU only needs to service the interrupt before the next 8-bit data word starts, so interrupt latencies are not a problem.

author: CJay
author_rank: Super Contributor
timestamp: July 06, 2021, 04:17:59 pm
content: It looks like an XT keyboard.

author: SiliconWizard
author_rank: Super Contributor
timestamp: July 06, 2021, 05:30:14 pm
content: I do not exactly remember the details of PS/2, but it looks pretty similar, except that it only shows 8 clock pulses, whereas PS/2 had 10 or 11? But the clock pulses surrounded by a logic high idle state is typical of PS/2 IIRC. Am I missing anything?So, I guess you can start with any working code implementing PS/2 and adapt it, that's probably not much work.

author: katastic
author_rank: Contributor
timestamp: July 06, 2021, 05:38:58 pm
content: >It looks like an XT keyboard.ooooooooooh. GOOD. CALL!!!my Q key is similar to this waveform I found for an XT chipset page:except my data line is held HIGH until modified.And, I found this key bit of information that definitely sounds right (and also would be why my AT->USB adapter didn't work):https://ilkerf.tripod.com/c64tower/F_Keyboard_FAQ.html#KEYBOARDFAQ_021> The keyboards differ in at least the following ways:>The XT uses a make/break bit to indicate key up/down. The AT sends one byte for keydown and two bytes for keyup.[mine DEFINITELY flips a single bit for press/release]> The XT kb. generates 2 start bits, 8 data bits, make/break bit, and a stop bit. The AT kb. is 1 start bit, 8 data, 1 parity, and a stop bit. [this also looks correct]> The XT keyboard scan codes have different values than then AT keyboard make/break codes (for corresponding key locations).> The XT keyboard doesn't accept any of the command strings accepted by the AT keyboard.> The XT keyboard is reset by fiddling the clock and data lines; the AT keyboard accepts a reset command string.The physical layout of my keyboard also looks like an XT with the function keys on the far left side instead of along the top like an AT keyboard, as well as placement of alt and other keys.I had previously read a source that said the Compaq used a normal AT keyboard protocol and clearly, upon inspection, this source was wrong!https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol

author: katastic
author_rank: Contributor
timestamp: July 08, 2021, 12:33:22 am
content: So I got reasonable results with an arduino. but two keys weren't working so I popped the key holder off. oooooohh boy is this thing dead. It's amazing it worked at all.It's got foam "springs" with metal contacts. The foam is dead (common problem), and the metal circles are super corroded with a few having no chrome/metal left at all. Just lightly touching one of the foil pads completely collapsed it.There are replacement kits that go for ~$30 (+ship?) but it's literally just foam (7/16" radius?) of a certain depth, with a metal backing on one side, and a plastic backing on the other side to help snap into the keyboard tabs. I think I could make "good enough" replacements though. Someone else used a ~7/16 hole punch and some foam.

author: LM21
author_rank: Regular Contributor
timestamp: July 09, 2021, 06:15:33 pm
content: PC keyboard is electrically simple. Two open collector pins form a two way bus. You can Google AT or PS2 keyboard. Data format is not hard either but what I can remember, it is scan codes and not necessarily plain ascii. Google will tell.

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 09, 2021, 11:55:34 pm
content: I've written code (including 8086 assembly) for handling XT and AT keyboards, and know them (knewthem intimately two to three decades ago), but didn't recognize the electrical signalsat all.Funny thing is, I only got rid of my last XT/AT keyboard only four years ago. The kind with a selectable slide switch on the bottom to pick between the two, and with the bigger round DIN connector (before PS/2). Was in pretty much pristine condition, and okay to type on, but not a particularly desirable or interesting mechanically or otherwise; a Keytronic with Swe/Fin layout.

author: LM21
author_rank: Regular Contributor
timestamp: July 10, 2021, 03:11:22 am
content: 8086 was a nice chip to play with. But off-topic here of course.Edit: Key board sends scan codes. Key press and release have different scan code.

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 10, 2021, 11:21:41 pm
content: Page 33 ofKey Tronic KB101 User's Guide(courtesy of neurophysics.ucsd.edu) contains a typical set of XT scan codes.Most keypresses yield a single-byte code 0x01-0x5F, and key releases the same code with MSB set, 0x81-0xDF.0xE0 is a sort-of escape code, followed by a single "escaped" byte 0x01-0x5F for a press event, and 0x81-0xDF for a release event.Left Control emits 0x1D/0x9D, Left Alt 0x38/0xB8, and the ones on the right side the same but preceded by E0.Print Screen and Pause keys emit a "multi-key" code. Cursor keys and such also do when either Shift is pressed, and/or Num Lock is also on.0xE1 is used with the Pause key only, which generates 0xE1 0x1D 0x45 0xE1 0x9D 0xC5 when pressed and nothing when released (and will not auto-repeat either); which is best processed as a press E1 1D 45 immediately followed by release E1 9D C5.So, the logic with XT keycodes is something like this:01..5F: Standard key press event81..DF: Standard key release event, corresponding to previous standard key press event (code& 7F).E001..5F: Alternate key press eventE081..DF: Alternate key release event, corresponding to previous alternate key press event key E0 (code& 7F).E101..5F01..5F: Special key press event, both bytes significant.E181..DF81..DF: Special key press release, both bytes significant. Corresponds to previous special key press event E1 (code1& 7F) (code2& 7F).In my own code, I only handledE0code, and signoredE1code1code2, since the Pause key was the only one sending these, and did not generate a release code when the key was released. (I recall this, because I found it surprising and odd: why would this one key behave so differently from the others?)So, technically the key code space is about 2×95 entries, with one two-byte entry 1D 45 / 9D C5. However, to map them naturally to USB HID Keyboard codes, you'll need to track Left Shift (2A/AA), Right Shift (36/B6), Left Control (1D/9D), Right Control (E0 1D/E0 9D), Left Alt (38 B8), and Right Alt (E0 38/E0 B8) states separately, as these are provided as a (modifier) bit mask whenever reporting the up to six currently depressed keys (not including those modifier keys) in an 8-byte USB HID Keyboard Report. Such reports consist of the modifier key bit mask, zero, and an ordered set of up to six currently pressed keys. The 8-bit key codes are listed inUSB HID Usage Tables 1.22.The middle block of XT keys –– Cursor Keys, Page Up and Page Down and so on –– also generate E0 AA prefix when pressed and E0 2A suffix when released if Left Shift is also pressed; E0 B6/E0 36 while Right Shift is also pressed; and E0 2A/E0 AA while Num Lock is enabled. So, if you used the 7 low bits of the code, and the presence of an E0 prefix as the eighth, you'd have a mapping from 8 bits to 8 bits – a 256-byte array of bytes – mapping the keyboard key to USB HID key code. You do this mapping on both presses and releases, as internal state would be maintained in USB HID key codes, not XT key codes; basically in a single USB HID Keyboard report format. You maintain the state of the modifiers (one byte), and the currently pressed keys (at least six bytes), and whenever these change, or the HID Idle period has elapsed, you send them as an USB HID Report. (A release, therefore, just clears the corresponding key to zero.)The only reason you'd use larger than 6 bytes of an internal array to maintain the currently pressed USB key codes, is if you want to try to support more than 6 simultaneous keys being pressed, via rotating the codes emitted every report (sort of key arpeggio; instead of remaining down, you essentially emit repeated presses and releases), but you then also need to remember to send these reports every 1ms or so, to keep up the "arpeggio" effect. (DOS Mine Bombers was my favourite before the turn of the millenium, 1995-1999 or so.) Useful if you intend to play old games where two players use a different set of keys on the same keyboard, and you don't want key lock-out to occur, but pretty much useless otherwise.