How it started...

I started this project with a fully functional TRS-80 Model II, including the stock keyboard. The first thing I did was get a copy of the TRS-80 Model II Technical reference manual to grab as much info as possible about the keyboard interface.

Next I intercepted the keyboard interface output lines directly from the keyboard card:


And captured the keystroke on the scope:

Then it was time to hookup the Arduino to enable some bit-banging:

Originally, I started writing the code literally from scratch, including the shaping of the waveforms themselves. Who knew that there was already a very handy ShiftOut function in the Arduino library? (Not me, that's who!) 😉 Fortunately I did some learning and was able to get a matching DATA and CLOCK signal that was (almost) perfect!

I later figured out (through trial and error) that the double characters were from push the signals through too quickly. Once I slowed it down to "typing speed" it seemed to clear up that problem.

USB Host Ghost

This is where things got weird. I purchased an Arduino compatible USB Host Shield from Amazon. The build quality was "ok" but I couldn't get it to work. After scouring several forums (and soldering the appropriate power jumpers) I found out that there's known issue with the wrong driver chips being used on these boards...the only fix was to replace one of them - they are surface mount - I don't have the tools, skills...or maybe just the patience...time to go in another direction!

Enter the ESP32

I made the switch from Arduino to ESP32, more specifically the ESP32 S3 WROOM. I also moved to the Visual Studio Code IDE. It took a few evenings to get the hang of it...I'm still an Arduino fan but this ESP32 is powerful stuff indeed! 

A couple of evenings in and I was already able to get the ESP32 to process USB HID keystrokes...I was on my way again!!! 

I ported my old Arduino code over to the ESP32, and managed to produce a duplicate of what the TRS-80 Model is looking for. (Note that M2_USB_Keyboard.c code is attached to the project for download.)

/**
 * @DiPDoT - NEW M2_SHIFTOUT FUNCTION used to bitbang the DATA and CLOCK
 *
 * @params: dataPin  : GPIO of DATA
 *          clockPin : GPIO of CLOCK
 *          bitOrder : MSBFIRST or LSBFIRST
 *          val      : Output Key Code (ASCII)
 */
/**
 * @DiPDoT - NEW M2_SHIFTOUT FUNCTION used to bitbang the DATA and CLOCK
 *
 * @params: dataPin  : GPIO of DATA
 *          clockPin : GPIO of CLOCK
 *          bitOrder : MSBFIRST or LSBFIRST
 *          val      : Output Key Code (ASCII)
 */
void M2_shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) {
    uint8_t i;
    
    // Model II - Only send the value if the busyPin is HIGH
    if(gpio_get_level(BUSY_PIN)) {
    
        // Model II - Start DATA high (Don't know if this is needed but just matching the spec for now)
        gpio_set_level(dataPin, HIGH);
        
        for(i = 0; i < 8; i++) {
            if(bitOrder == LSBFIRST)
                gpio_set_level(dataPin, !!(val & (1 << i)));
            else
                gpio_set_level(dataPin, !!(val & (1 << (7 - i))));
            
            ets_delay_us(SO_DELAY);         // Stalls execution for #uS
            gpio_set_level(clockPin, HIGH);
            ets_delay_us(SO_DELAY);         // Stalls execution for #uS
            gpio_set_level(clockPin, LOW);
            ets_delay_us(SO_DELAY);         // Stalls execution for #uS
        }
    
        // Model II expects line to be high
        gpio_set_level(dataPin, HIGH);
        ets_delay_us(SO_DELAY);         // Stalls execution for #uS

        // Add the "notch" to the end of the data cycle
        gpio_set_level(dataPin, LOW);
        ets_delay_us(SO_DELAY);         // Stalls execution for #uS
        gpio_set_level(dataPin, HIGH);
    }
}

Because the ESP32 has a max input of 3.3V to the GPIOs, I also needed to use a bi-directional level converter. Fortunately these are cheap and plentiful, and I was almost ready for the big test!

I used a female DIN connector this time so I don't even need to pop the top off of the Model II.

Testing

The new board is capturing keystrokes and bit-banging them to the Model II perfectly! I haven't seen a single double character...

Read more »