I am slowly appreciating your 16*16 keyboard design. I also had plans for a 16*16 keyboard matrix. However, my design decisions are almost diametrically opposed to yours. Regardless, I can appreciate the consistently of your choices. For example, I greatly appreciate the symmetry you have chosen for backspace and delete.
I explained your design to a friend. Specifically, that it is the main cluster of a PC keyboard design, a mirror image of the main cluster for specialist functions (such as copy and paste) and further keys to the lower right. I presume it would be used with the first space-bar aligned to the user. Indeed, I presume this is primarily a programmer's keyboard or power user's keyboard where 105 keys or so is a limiting factor. In such case, you don't care if your design dislodges the dominant design. You merely want it for your own productivity. Indeed, I may be able to help you and others in this quest.
While considering a
miscellany of clocked and unclocked serial protocols (which omitted SNES joypad protocol),
jmthompson's proposed input devices and your 16*16 matrix keyboard design, it occurred to me that our common constraints can be solved with a small circuit. Indeed, with about 20% of the effort of implementing PS/2 protocol or ADB protocol, it is possible to obtain about 80% of the reward. Most immediately, it would be possible to connect your keyboard design (or any keyboard matrix) to a NES, SNES or Gigatron using six discrete logic chips.
I'm not a dedicated gamer and therefore I was unaware of the differences between Atari/Commodore joysticks and Nintendo joypads. I was aware of Atari paddle controllers and the annoying, minor incompatibility between Atari and Commodore mice. However, if you had pressed me on the issue, I would have wrongly assumed that Nintendo joypads used something like a
Charlieplexing diode matrix to implement additional buttons. It would not have occurred to me that the original NES joypad has five wires and eight buttons because this maximizes use of one 4021 eight bit shift register while providing upward compatibility with no additional cabling. (By the time that the SNES joypad began production, economies of scale allowed COB [Chip On Board] to shift 12 bits.) Indeed, I'm not the only one who hadn't considered NES/SNES joypad protocol in detail. In the highly recommended
one hour Hacker Hotel presentation about the Gigatron's design choices, it is admitted that such oversight was discovered after designing the Gigatron and purchasing joypads.
A 4021 requires power and ground. It provides one bit of serial data. It is operated with "latch all bits" followed by repeated application of "clock all bits by one position". A NES (with 6502) or SNES (with 65816) can read three serial channels of data from each of its two joypad ports. In the trivial case, only one channel is used. The second channel is used by a joypad multiplexing unit called the FourScore. (Unfortunately for the puerile among us, the marketing department decided against calling it the FourPlay.) Presumably, the third channel is used to identify extended uses. The FourScore and several other protocol extensions (light gun, Mattel Power Glove) are supported by a subset of games. Actually, full support for the protocol was quite strained. For example, the Mattel Power Glove operates in 22 modes to ensure that it can be used effectively with the broad software catalog; much of which pre-dated the peripheral.
Although I only made a cursory search, I was not able to find technical specifications for the light gun or Mattel Power Glove. In ignorance, I have forked the NES/SNES protocol with the assumption that only the joypads will be supported and that more exotic devices, such as the Mattel Power Glove, will only work in a compatibility mode, if at all.
My insight for a NES/SNES/Gigatron keyboard protocol is that several serial protocols (RC5, CAN bus)
retroactively add address bits with a non-contiguous field. Further insight comes from ADB's 4 bit device type and 4 bit register number. From reading details about expected operation of the 8 button NES joypads or the downwardly compatible 12 button SNES joypads, it is apparent that a continuous stream of zero or one bits is presented when the shift register runs dry. All of Nintendo's official controllers default to a stream of ones. Some of the clone controllers default to a stream of zeros.
Some of Nintendo's legacy software is wilfully incompatible with some of the imitation controllers. This is not a side-effect of relying upon undefined behavior because the Nintendo port is read one bit at a time. Furthermore, Nintendo's internal standards disallowed, for example, use of undefined opcodes. Additional buttons are useful during development. However, for a released product, all of this functionality should be removed and there is no technical reason to test or discriminate against imitation joypads. My opinion on the matter involves the C-word - and I don't mean CMOS. If you're a fan of Doug Stanhope, the collective noun is bucket.
Unlike Nintendo, the functionality where a joypad emits a constant stream of bits may be used in a productive manner - and this may be applied to a keyboard or other input peripheral. Specifically, a field of any size beyond the first 12 bits may be retroactively treated as a device type field. In the case of legacy NES/SNES joypads, all zeros or all ones will appear in this field. Within reasonable bounds, we may define the size and position of this field in the manner which is most convenient. For example, if we define a 4 bit field for device type, 14 other types are available for our use. Furthermore, with the exception of legacy cases, it is possible to define a device type with the
top bit set for any device which daisy-chains and a device type with the
top bit clear as a leaf node. This allows host implementations to spend less time shifting bits (or scan at higher frequency) - even in the case when unknown devices are present.
I'm quite keen about three byte Device-Command-Data serial protocols (as noted in
Cell Networking Protocol) and I am pleased resurrect some otherwise unused ideas. Unfortunately, the major problem with simplistic Device-Command-Data protocols is the large scope for mangling data which is not restricted to a complete lack of integrity checking, bit slip or other scope for mis-framed data. Nintendo games solve the problem of bit slip by not acting upon input until it is consistently read twice. Indeed, similar practice had been established on 6502 systems from the beginning. Specifically, from the Aug 1976 KIM-1 User Manual, Chapter 3: "Key validation is performed during an additional scan cycle." Obviously, this incurs latency. It otherwise allays my concerns regarding a simplistic protocol. Indeed, NES/SNES joypad protocol does not suffer from
stuck keys and in this regard is superior to PS/2 and USB.
There are other limitations but I pursued the idea further. This was in part due to
BigEd noting that uni-directional streams of data simplifies development:
BigEd on Thu 6 May 2021 wrote:
if the keyboard CPU only produces keystrokes (and doesn't need to be told to light LEDs), and if the graphics CPU only produces video (and is not queried for what's in the buffer or where the cursor is.)
I recommend the traditional solution of a physically locking caps-lock key. I also recommend distinctly textured meta keys - which is trivial to achieve if you're
3D printing key caps. As a further mechanism to increase productivity, I considered
serial digital LEDs within a
Lego enclosure with holes for the joypad connectors and transparent Lego for a cluster of LED indicators. One of the LEDs may be configured as a caps-lock light. An element on a display may also be configured as a caps-lock indicator. Both of these options incur less eye movement when typing.
If you are devising
your own keyboard matrix then you are strongly recommended to wire each meta key separately or use
switch matrix diodes to prevent key aliasing. Poor choice of diodes may incur voltage drop which is incompatible with 3.3V operation or daisy-chaining over long runs of thin wire. For economy, switch matrix diodes can be omitted from the majority of keys, although such a keyboard will not be suitable for gaming. I don't believe this is a major impediment when the keyboard protocol extends a joypad protocol and the joypads cost USD4 including shipping. I plan to make a full "
space cadet keyboard" with six or more types of shift key. This will include shift lock, Greek lock and Cyrillic lock. STEM often uses Greek script and Cyrillic is not a particularly large step beyond Greek. Initially, I planned to implement a 4*4 matrix of switches with diodes for the meta keys and a 12*12 matrix without diodes for keys which should not be pressed in combination. However, I may have to adjust this design.
I have yet to specify an actual serial stream which is suitable for a keyboard or any other device. It is desirable to obtain 16 bits or more of data within one latching operation. It is also very desirable to provide some context for the latched data. The latter may be provided with a one nybble row number (which increments or otherwise changes with each read) and a one nybble device type (which does not change) where 0000 or 1111 indicates a joypad. The interface circuitry for a keyboard consists of one 4 bit counter (decimal or binary), one or two 74HC238 decoders to activate one row of the switch matrix (with maximum size 16*16) and three 4021 shift registers such that the first 16 bits provide raw key presses, the next 4 bits provide the device type and the next 4 bits provide the counter's output. I believe these fields are suitably dimensioned on the basis that Apple Desktop Bus has fields of similar size and type.
The counter (typically 74HC161) may be configured to scan any quantity of rows. The negative edge of the "latch all bits" signal is inverted with a 2222A NPN transistor. This is used to advance the 4 bit counter when timing is not critical. The 4 bit count may be fully decoded with two 74HC238 chips. One of these 16 outputs energizes one row of the keyboard. The positive edge of the "latch all bits" signal causes the 4021 chain to retain one row of the keyboard (16 bits), the keyboard device's number (4 bits) and the row number (4 bits). These 24 bits may be shifted up the device chain to the host. This may be used in conjunction with the simplistic "sample twice, act once" technique to overcome switch bounce and bit slip. Unfortunately, this circuitry has the minor energy inefficiency of leaving one keyboard row energized after key sampling. However, this wastes the most energy when keys are depressed on a trivial discrete logic implementation. This is not a consideration when keys are not depressed. Likewise, it is not a consideration when the keyboard uses a one chip microcontroller implementation. Traditionally, 8051 has been used for PS/2 peripherals an small PIC devices (with 512 instruction words) have been used for ADB peripherals. However, you are strongly advised to pursue other options.
In the manner that
sburrow came to the conclusion that a 20 key interface would be useful and similarly in ignorance of the KIM-1's 7*3 switch matrix (combined with a 7*6 display matrix), I have for many years thought that it would be prudent to start with a small cluster of keys. However, rather than discarding the hexadecimal keypad when a full keyboard is supported, I wanted to support an optional hexadecimal keypad as a numeric keypad. Indeed, rather than being a banker's keypad affixed on the right with zero at the bottom, it would be a programmer's keypad affixed on either side with zero at the top. It is for this reason that I only purchased 30 key switches. 20 will be used in one keypad and the remainder will be used for miscellaneous purposes or lost to my incredibly bad soldering. Purchasing 100 or more keyboard switches would not be my most bombastic move. However, I presently have 30 switches without hardware or software support and it is not worthwhile to multiply this mismatch by a factor of three or more.
A lack of fixed goals and no deadline can be deadly to a personal project. Such working practice can also be the best form of vertical integration. In this case, I found that a trivial change greatly increased the utility of a NES/SNES/Gigatron keyboard interface. Specifically, while designing the layout for a six discrete chip keyboard interface, I found that it is trivial to
daisy-chain peripherals.
Basic functionality of many shift register implementations allows daisy-chaining. Likewise, it is fairly conventional to
daisy-chain across boards or peripherials. However, what I propose is a fixed size 24 bit cell structure which retroactively includes a common subset of legacy devices which do not obviously fit this pattern. My original use case was a full keyboard with an optional hexadecimal keypad. Originally, the full keyboard was intended to use a
bi-directional 256 bit cell networking protocol covering LAN and magnetic storage where joysticks were a separate legacy case. However, the joystick protocol is sufficiently powerful to cover the most typical Apple Desktop Bus configuration of mouse connected to keyboard and keyboard connected to host. Alternatively, when extending SNES joypad protocol, it would be very fitting for joypad to connect to keyboard and keyboard to connect to host. This does not cover obscure cases, such as Apple Desktop Bus modem or Apple Desktop Bus webcam. However, given available bandwidth and bus contention, these cases are best forgotten.
The extended NES/SNES joypad protocol does not work with any legacy software but it is relatively simple to adapt a SNES joypad library to read, for example, 48 bits rather than the default 12 bits. Obviously, another layer of software is required on top of the serial shifting to handle the more diverse range of peripherals. In particular, keyboard support requires row de-multiplexing, key position to character set mapping and key repeat. Regardless, this is preferable to the double mapping of PS/2 switch matrix to keycode mapping and then keycode to charset mapping. Likewise, it sidesteps complications commonly found on Z80, such as CollapseOS's use of PIC to bridge PS/2 keyboard protocol to Sega joypad protocol - and CollapseOS's support for a PIC assembler and a PIC programming utility which is primarily to self-host its own keyboard firmware. In the worst case, to make a SNES protocol keyboard work on 6502, it is possible to hack off one PS/2 or USB keyboard controller, extract 4021 shift register chips from three NES joypads and incorporate miscellaneous parts, such as pull-up resistors. No peripheral microcontroller is required. More importantly, no peripheral microcontroller *firmware* is required. A microcontroller is only required to reduce cost, size and energy. It is strictly optional.
Overall, we get most of the benefit of an 8 bit home computer with directly attached keyboard matrix combined with the common cases of a desktop peripheral network. In particular, a subset of practical peripherals is already widely available and supported on a variety of 6502, 65816 and 6502 inspired platforms.
There is much scope for reading
inverted bits. However, in all cases, this is easier to resolve than the inefficiencies of PS/2 protocol, ADB protocol or USB protocol. In particular, implementation of NES/SNES protocol is least likely to require an oscilloscope. For joypads, it is most convenient to have pull-up resistors and then have each active switch pull signal to ground. This inverted signal is itself held within 4021 in its inverted form, emitted to the host (with a single inversion) and then inverted by a NES/SNES such that the programming model is zero for dormant switches and one for active switches. Bits may remain inverted on other hardware such that dormant switches are all ones. For a keyboard matrix, it may be convenient to have pull-down resistors (to prevent floating inputs) and then have one active switch pull one column high. This arrangement will be inverted on NES and SNES hardware. Likewise, in all cases, device ID and row number will be inverted on NES and SNES hardware.
There is similar scope for reading
bits and bytes in the wrong order. When reading eight independent switches, field order is not hugely significant. However, when reading nybble fields or mouse co-ordinates, ordering becomes very significant. I have followed the convention of the 4021 datasheet where the nominal MSB [Most Significant Bit] is shifted first. In particular, a 16 bit mouse co-ordinate is shifted MSB, each keyboard row is shifted right to left, keyboard or mouse data is shifted before device type which is shifted before parameter number and the top bit of the device type is shifted before other device type bits. The only exception is the hexadecimal keypad and this is for a rather fun reason. The first two rows of the keypad correspond to the eight buttons of a NES joypad and the third row corresponds to the additional four SNES buttons. Therefore, the hexadecimal keypad is compatible with NES/SNES/Gigatron games. Furthermore, the extra buttons on the hexadecimal keypad may be used during game development. Indeed, it is entirely possible that legacy games have hidden functionality which may be activated via additional buttons.
On a little endian system, such as 6502, it may be preferable to reverse the order of bytes received. Specifically, the first byte should be stored at X+2, the second byte should be stored at X+1 and the third byte should be stored at X. In this arrangement, the upper nybble of X contains the device type, the lower nybble of X contains the parameter number and the 16 bit data in X+1 and X+2 is in conventional 6502 byte order. Key switch data may or may not be inverted but this is specific to each known device type (and host).
Unless you plan to use every position of 16*16 switch matrix, it would be strongly preferable to implement a hidden diode matrix to denote type and subtype. For example, 105 key
PC keyboard, US/UK/French/Spanish/German layout. A shocking number of legacy keyboards use the same switch matrix and therefore it may be sufficient to support one physical layout and four keymaps or less.
Musical keyboards should assign row 4, position zero to 440Hz A Major. The remainder of the row should be used for the remainder of the octave. Row 5, position zero should be assigned to 880Hz A Major. If you are unfortunate enough to have a keyboard which works from C Major or similar, a hidden diode matrix may be required to define the skew. Auxiliary switches may vary considerably. Regardless, it should be relatively trivial to bridge a random synthesizer keyboard to SNES protocol (in hardware) and then to MIDI (in software). Furthermore, the result should be fairly portable.
Mouse should use row zero for buttons, row 15 for vertical position, row 14 for horizontal position, optionally use row 13 for vertical scroll and optionally use row 12 for horizontal scroll. This allows a trivial implementation to cycle through three, four or five multiplexed values, although update frequency will be adversely affected by the number of reported values. For compactness, it may be desirable to implement a SNES protocol mouse using CPLD, although current draw may be horrendous. (I believe idle current for ATF1504 is 105mA.) Furthermore, 24 bits of shift register and multiple up/down counters may exceed the available state of a 64 cell CPLD. 128 cells may be required or the resolution of the counters may be reduced. For example, make the least significant four bits always read zero. Actually, just use a microcontroller.
Regarding
serial clock speed, NES/SNES protocol officially works with 8us pulses (12.5kHz). However, working at the official speed and with a daisy-chain depth of two devices, this is only 520 readings per second - where mouse may require five readings to report full state and keyboard may require 16 readings to report full state (and a further 16 readings for consistency). Keyboard scanning at 100Hz may require clocking peripheral shift registers at 38.4kHz or more. This reduces reliability over distance but is otherwise overwhelming likely to work on clone devices made with modern components.
Faster keyboard scanning may be desirable. For example, a 6502 system with 144Hz keyboard scanning and 72Hz display. This only requires keyboard scanning and a frame rate which is 44% faster than a BBC Micro and may be performed on 6502/65816 which is at least seven times faster. Worryingly, due to reduced software overhead, such a system would have lower latency than many PCs with 1000Hz keyboard scanning and 144Hz display.
The
host interface for one SNES input is trivial. One 6522 shift register may be clocked autonomously from a timer and the 6522 may interrupt after eight bits are collected. This requires three readings per device; typically for a daisy-chain of two or more devices. This is no more onerous than single byte UART at the same data rate. However, each additional input stream may be collected with its own 74HC595 and all ganged units may be handled synchronously in the same interrupt (which may not be the case with UART). Indeed, it is possible to implement eight additional inputs by using nine additional chips. Yes, in this absurd case, all input peripherals may be connected to a long line of 9 pin D connectors, a 3*3 grid of 9 pin D connectors or, perhaps, a two row D of 9 pin D connectors on the front of a computer. Up to the power limit supplied by the host, this covers any permutation of hex keypad, computer keyboard, musical keyboard, mouse, joystick, dance mat or other input peripheral - directly connected or daisy-chained - with no affinity or preference regarding connector position.
My suggested fork of the NES/SNES joypad protocol only covers one channel of clocked serial data from each peripheral. This simplifies daisy-chaining. However, if you want full
historical compatibility, it remains possible to implement the triple data stream clocked serial over a lesser number of ports. Understandably, such a device may not daisy-chain. However, it does retain compatibility with the Mattel Power Glove.