ADAM Keyboard Teensy 4.0

DannyVdH

10 Jun 2022, 23:57

I'm trying to connect the adam keyboard to usb with a Teensy 4.0, can someone tell me what I'm doing wrong?
Attached is my program and the electronic scheme. It's based on a example from this forum, but it was made with Teensy 3.2.

Thanks

Code: Select all

/*
 * Wiring for Teensy4.0:
 * Teensy 1(TX1) -- RJ 1
 * Teensy 2   -- RJ 2 (optional)
 * Teensy GND -- RJ 3,4,5
 * Teensy Vin -- RJ 6
 *
 * Note that a real Coleco keyboard cable is reversed.
 * It is best to check that 3,4,5 are connected to one another on the Teensy end.
 */

// See https://console5.com/techwiki/images/b/b5/Coleco_ADAM_Technical_Reference_Manual.pdf, Chapter 3.3.

// The high nibble is the message type and the low nibble is the address.
// Since we only send to device 1, the keyboard, we bake that in.

const uint8_t MN_RESET   = 0x01;  // command.control (reset)
const uint8_t MN_STATUS  = 0x11;  // command.control (status)
const uint8_t MN_ACK     = 0x21;  // command.control (ack)
const uint8_t MN_CLR     = 0x31;  // command.control (clr)
const uint8_t MN_RECEIVE = 0x41;  // command.control (receive)
const uint8_t MN_CANCEL  = 0x51;  // command.control (cancel)
const uint8_t MN_SEND    = 0x61;  // command.data (send)
const uint8_t MN_NACK    = 0x71;  // command.control (nack)
const uint8_t MN_READY   = 0xD1;  // command.control (ready)
const uint8_t NM_STATUS  = 0x81;  // response.control (status)
const uint8_t NM_ACK     = 0x91;  // response.control (ack)
const uint8_t NM_CANCEL  = 0xA1;  // response.control (cancel)
const uint8_t NM_SEND    = 0xB1;  // response.data (send)
const uint8_t NM_NACK    = 0xC1;  // response.control (nack)

#define DEBUG_ADAMNET 1
#define SERIAL_TX_PIN 1
#define RESET_PIN     2

IMXRT_LPUART_t *s_pkuart = &IMXRT_LPUART6;  // underlying hardware UART for Serial1

void send_command(uint8_t command) {
#if DEBUG_ADAMNET
    Serial.print("S: ");
    Serial.println(command, HEX);
#endif  
    s_pkuart->CTRL |= LPUART_CTRL_TXDIR;  // Set in to TX Mode...
    Serial1.write(command);
    Serial1.flush();       // Wait for transmit complete.
    s_pkuart->CTRL &= ~LPUART_CTRL_TXDIR;  // Set in to RX Mode...
}

bool receive_response(uint8_t *buffer, uint8_t expected_length) {
    uint8_t len = Serial1.readBytes(buffer, expected_length);
#if DEBUG_ADAMNET
    Serial.print("R:");
    for (uint8_t i = 0; i < len; i++) {
        Serial.print(" ");
        Serial.print(buffer[i], HEX);
    }
    Serial.println();
#endif  
    return len == expected_length;
}


void kbsetup() {
          // Setup Serial1 for Half duplex:
          Serial1.begin(62500, SERIAL_8N1_RXINV_TXINV);
          // Lets setup that IO pin to be in half duplex
          s_pkuart->CTRL |= LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC;

          // Lets try to enable PU resistor on that pin...
          //*(portControlRegister(SERIAL_TX_PIN)) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3) | IOMUXC_PAD_HYS;
          //IOMUXC_LPUART6_TX_SELECT_INPUT = 1; // need to get to right one...
          
          Serial1.setTimeout(100);

          // Hard RESET.
          pinMode(RESET_PIN, OUTPUT);
          digitalWrite(RESET_PIN, HIGH);

          delay(100);
          // Soft RESET. Mostly turns off LOCK.
          send_command(MN_RESET);
}

const uint32_t RECEIVE_INTERVAL = 10;

void kbrun() {
    static uint32_t last_receive_time = 0;
    if (millis() - last_receive_time > RECEIVE_INTERVAL) {
        uint8_t buf[8];
        send_command(MN_RECEIVE);
        if (receive_response(buf, 1)) { 
            if (buf[0] == NM_ACK) {
                send_command(MN_CLR); // Clear to Send
                if (receive_response(buf, 5) && buf[0] == NM_SEND) {
                    if (buf[1] == 0 && buf[2] == 1 && buf[3] == buf[4]) {
                        // Length 1, checksum okay.
                        send_command(MN_ACK);
#if DEBUG_ADAMNET
                        char ch = buf[3];
                        Serial.print("A: ");
                        Serial.print(ch, HEX);
                        if (ch > 0x20 && ch < 0x7F) {
                            Serial.print(" ");
                            Serial.write(ch);
                        }
                        Serial.println();             
#else
                        Serial.write(buf[3]);
#endif
                        last_receive_time = millis();
                    } else {
                        send_command(MN_NACK);
                        // Try again right away.
                    }
                }
            } else if (buf[0] == NM_NACK) {
                // No input available, wait a bit.
                last_receive_time = millis();
            }
        }
    }
}
Attachments
adam keyboard.PNG
adam keyboard.PNG (48.25 KiB) Viewed 981 times

DannyVdH

11 Jun 2022, 21:32

This was a hard nut to crack, with my scope I soon found out that something was drawn wrong on the schematic. After that I had the problem that I could enter a character but could not return a ACK. After placing a very short delay after switching the one wire communication (switching to RX) it was all right.

Code: Select all

    s_pkuart->CTRL |= LPUART_CTRL_TXDIR;  // Set in to TX Mode...
    Serial1.write(command);
    Serial1.flush();       // Wait for transmit complete.
    s_pkuart->CTRL &= ~LPUART_CTRL_TXDIR;  // Set in to RX Mode...
    delay(10); // <----- THIS WAS THE SOLUTION	
Attachments
keyboard2.PNG
keyboard2.PNG (36.99 KiB) Viewed 914 times

Post Reply

Return to “Keyboards”