Trouble with Teensy 3.1 and SERIAL_7E1

Status
Not open for further replies.

russell

Member
I am working on a project where I'm reading input from a ps2 keyboard, converting keycodes to ASCII (using the Ps2KeyboardHost library of Steve Benz, which I don't think is related), with the intention of sending the ASCII down a serial port to a computer, read back serial data from the serial port, and then send that data (possibly modified) down another serial port to a line printer. I wrote some code to loop back the two serial ports so that what I write out one should arrive at the other end and get echoed back, and I should read it back on the originating serial port, to make sure that's all working before I go farther. Things seem to be mostly working (leaving aside some flow control problems still to be worked out), but if I put the two serial ports (Serial1 and Serial2) into SERIAL_7E1 at any baud rate I've tried, I get garbled output. Here's the code:

Code:
#include "ps2_Keyboard.h"
#include "ps2_NeutralTranslator.h"
#include "ps2_SimpleDiagnostics.h"

static const int clockPin = 4;
static const int dataPin = 5;

int unshiftTable[70] = {
  0x7F, 0x1B, 0x08, 0x09, 0x0A, 0x20, 
  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
  0x2E, 0x0A, 0x2B, 0x2D, 0x2A, 0x2F,
  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
  0x27, 0x2C, 0x2D, 0x2E, 0x2F, -1,
  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
  0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
  0x7A, 0x3B, 0x5C, 0x5B, 0x5D, 0x3D
};

int shiftTable[70] = {
  0x7F, 0x1B, 0x08, -1, 0x0A, 0x20, 
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1,
  0x28, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28,
  0x22, 0x3C, 0x5F, 0x3E, 0x3F, -1,
  0x7E, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
  0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
  0x5A, 0x3A, 0x7C, 0x7B, 0x7D, 0x2B
};

int keycode2ascii(uint16_t c) {
    // check for special bits so we can bail
    if (c & ~0x607F) {
        return -1;
    }

    if (!(c & 0x2000)) {
        if (c & 0x4000) {
            return shiftTable[(c & 0x7F) - 0x1A];
        } else {
            return unshiftTable[(c & 0x7F) - 0x1A];
        }
    } else {
    // handle CTRL
        // for CTRL-letter, nuke shift bit
        if ((c & 0xFF) >= 0x41 && (c & 0xFF) <= 0x5A) {
            c = c & ~0x4000; 
        }
        if (c >= 0x2041 && c <= 0x205A) {
            return c & 0x1F;
        }
        switch (c) {
            case 0x6032: // ^@
                return 0;
            case 0x205D: // ^[
                return 0x1B;
            case 0x205C: // ^BACKSLASH
                return 0x1C;
            case 0x205E: // ^]
                return 0x1D;
            case 0x6036: // ^^
                return 0x1E;
            case 0x603C: // ^_
                return 0x1F;
        }
    }
    return -1;
}

typedef ps2::SimpleDiagnostics<32> Diagnostics;
static Diagnostics diagnostics;
static ps2::Keyboard<dataPin,clockPin,16,Diagnostics> ps2Keyboard(diagnostics);

#define Printer Serial1
#define Computer Serial2

void setup() {
    pinMode(LED_BUILTIN, OUTPUT);
    ps2Keyboard.begin();
    Printer.begin(9600,SERIAL_7E1);
    Printer.attachRts(2);
    Printer.attachCts(20);
    Computer.begin(9600,SERIAL_7E1);
    Computer.attachRts(11);
    Computer.attachCts(23);
}

static ps2::NeutralTranslator translator;

void loop() {
    // diagnostics.setLedIndicator<LED_BUILTIN, ps2::DiagnosticsLedBlink::heartbeat>();
    int fromComputer;
    int fromPrinter;

    if (Computer.available() > 0) {
        fromComputer = Computer.read();
        Serial.printf("%c",fromComputer);
    }
    if (Printer.available() > 0) {
        fromPrinter = Printer.read();
        Printer.write(fromPrinter);
        Printer.flush();
        // Serial.printf("printer: %c\n",fromPrinter);
    }

    ps2::KeyboardOutput scanCode = ps2Keyboard.readScanCode();
    if (scanCode != ps2::KeyboardOutput::none) {
        // Serial.println((byte)scanCode, HEX);

        ps2::KeyCode translated = translator.translatePs2Keycode(scanCode);
        if (translated != ps2::KeyCode::PS2_NONE) {
            int c = keycode2ascii(translated);
            if (c >= 0) {
                // Serial.printf("0x%04x %02x %c\n",translated,c,c);
                // Serial.printf("keyboard: %c\n",c);
                // Computer.write(c);
                if(Computer.availableForWrite() > 0) {
                    Computer.println("THIS IS A REALLY LONG STRING");
                    Computer.flush();
                } else {
                    Serial.printf("cannot write yet\n");
                }
            }
        }
    }
}

Right now the keyboard input is just triggering the Serial2.println() function, which I was using to try to stress the prototype code.

I am doing the cross-over of RX-TX and RTS-CTS on the RS-232 side of a couple of Sparkfun level shifter boards: https://www.sparkfun.com/products/11189

With SERIAL_7E1, I get something like:

Code:
01:54:57.370 -> �H�S��S�A���A��Y���NG�S���NG�
01:54:57.569 -> �H�S��S�A���A��Y���NG�S���NG�
01:54:58.067 -> �H�S��S�A���A��Y���NG�S���NG�
01:54:58.134 -> �H�S��S�A���A��Y���NG�S���NG�
01:54:58.233 -> �H�S��S�A���A��Y���NG�S���NG�

If I switch to SERIAL_8N1 (or SERIAL_8E1 or SERIAL_8N2), the output isn't garbled:

Code:
01:56:03.094 -> THIS IS A REALLY LONG STRING
01:56:03.592 -> THIS IS A REALLY LONG STRING
01:56:03.659 -> THIS IS A REALLY LONG STRING
01:56:03.758 -> THIS IS A REALLY LONG STRING

I'm using arduino-1.8.9 and current teensyduino, which I just (re)installed a few days ago.
 
I am assuming that whatever you are using to receive the data is also configured to receive the data at 7E1 format?

That is when you output at 7E1, and for example you output "AB" one of these two will end up with the high bit set for parity...
But if your receiving program is expecting 8N1 (like most) - it will print garbled data...
 
Right now, the same teensy is sending on one of its serial ports, receiving the data on another of its serial ports and echoing it back. Both serial ports are configured as 7E1. I need 7-bit data to work because the device I'll be interfacing with expects it (although I have some other parity options, it is pinned on 7 bit data).

I'm reading Chapter 47 of https://www.pjrc.com/teensy/K20P64M72SF1RM.pdf, and it suggests that the hardware uart is really 8 or 9 bit, not 7, which suggests 7E1 is using some clever software hack. It seems like maybe on receive the byte isn't having the parity bit masked off.
 
Status
Not open for further replies.
Back
Top