Model M Matrix + Teensy

User avatar
phosphorglow

02 Jun 2014, 01:37

Hiyo!

I'm sure someone has already done this, but I haven't found it, so hopefully this helps.

I'm a hardware guy. I've always meant to get into coding, and this little project really gave me a nice 101 crash course. Still not entirely sure what I'm doing, but I have a fuzzy idea... :P

THANK YOU HASU FOR YOUR AWESOME WORK! ^_^
And thank you matt3o for your very awesome intro guide to his firmware!
2014-06-01 19.14.12.jpg
2014-06-01 19.14.12.jpg (176.82 KiB) Viewed 11071 times
Layer 2 - COLOR MATRIX COMBINED.jpg
Layer 2 - COLOR MATRIX COMBINED.jpg (747.68 KiB) Viewed 11071 times

Code: Select all

#define KEYMAP_ANSI( \
    K72, K53, K54, K64, K74, K76, K78, K69, K59, K56, K46, K4B, K4C, K4F, K3F, K1E, \
    K52, K42, K43, K44, K45, K55, K57, K47, K48, K49, K4A, K5A, K58,      K66, K5C, K5E, K5D, \
    K62, K32, K33, K34, K35, K65, K67, K37, K38, K39, K3A, K6A, K68, K26, K5B, K4E, K4D, \
    K63, K22, K23, K24, K25, K75, K77, K27, K28, K29, K2A, K7A,      K16, \
    K61,      K12, K13, K14, K15, K05, K07, K17, K18, K19, K0A,      K11, K7E, \
    K50, K7F,                K06,                K0F, K10, K0E, K0B, K0C \
) { \
    { KC_NO,	KC_NO,	  KC_NO,    KC_NO,    KC_NO,    KC_##K05, KC_##K06, KC_##K07, KC_NO,    KC_NO,    KC_##K0A,  KC_##K0B, KC_##K0C, KC_NO,   KC_##K0E, KC_##K0F }, \
    { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17, KC_##K18, KC_##K19, KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_##K1E, KC_NO }, \
    { KC_NO,    KC_NO,    KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27, KC_##K28, KC_##K29, KC_##K2A, KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_NO }, \
    { KC_NO,    KC_NO,    KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_NO,    KC_##K37, KC_##K38, KC_##K39, KC_##K3A, KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_##K3F }, \
    { KC_NO,    KC_NO,    KC_##K42, KC_##K43, KC_##K44, KC_##K45, KC_##K46, KC_##K47, KC_##K48, KC_##K49, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D, KC_##K4E, KC_##K4F }, \
    { KC_##K50, KC_NO,    KC_##K52, KC_##K53, KC_##K54, KC_##K55, KC_##K56, KC_##K57, KC_##K58, KC_##K59, KC_##K5A, KC_##K5B, KC_##K5C, KC_##K5D, KC_##K5E, KC_NO },  \
    { KC_NO,    KC_##K61, KC_##K62, KC_##K63, KC_##K64, KC_##K65, KC_##K66, KC_##K67, KC_##K68, KC_##K69, KC_##K6A, KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_NO },  \
    { KC_NO,    KC_NO,    KC_##K72,    KC_NO,    KC_##K74, KC_##K75, KC_##K76, KC_##K77, KC_##K78, KC_NO,    KC_##K7A, KC_NO,    KC_NO,    KC_NO,    KC_##K7E, KC_##K7F }  \
}

Code: Select all

const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    /* 0: qwerty */
    KEYMAP_ANSI(
        ESC, F1,   F2,  F3,   F4,   F5,   F6,   F7,   F8,   F9,   F10,   F11,   F12,   PSCR,   SLCK,   PAUS, \
        GRV, 1,   2,   3,   4,   5,   6,   7,   8,   9,   0,   MINS,   EQL,   BSPC,   INS,   HOME,   PGUP, \
        TAB, Q,   W,   E,   R,   T,   Y,   U,   I,   O,   P,   LBRC,   RBRC,  BSLS, DEL, END, PGDN, \
        CAPS, A,   S,   D,   F,   G,   H,   J,   K,   L,   SCLN, QUOT, ENT, \
        LSFT, Z,   X,   C,   V,   B,   N,   M,   COMM, DOT, SLSH, RSFT, UP,\
        LCTL,   LALT,   SPC,   RALT,   RCTL,   LEFT, DOWN, RIGHT),

};

Code: Select all

/* Column pin configuration
 * col: 0   1   2   3   4   5   6   7   8   9   10   11  12  13  14  15
 * pin: B0  B1  B2  B3  B7  D0  D1  D2  D3  C6  C7  D5  E6  D4  D7  B4  
 */
static void  init_cols(void)
{
    // Input with pull-up(DDR:0, PORT:1)
    DDRE  &= ~(1<<6);
    PORTE |=  (1<<6);
    DDRD  &= ~(1<<7 | 1<<5 | 1<<4 | 1<<3 | 1<<2 | 1<<1 | 1<<0);
    PORTD |=  (1<<7 | 1<<5 | 1<<4 | 1<<3 | 1<<2 | 1<<1 | 1<<0);
    DDRC  &= ~(1<<7 | 1<<6);
    PORTC |=  (1<<7 | 1<<6);
    DDRB  &= ~(1<< 7 | 1<<4 |1<<3 | 1<<2 | 1<<1 | 1<<0);
    PORTB |=  (1<< 7 | 1<<4 |1<<3 | 1<<2 | 1<<1 | 1<<0);
}

static matrix_row_t read_cols(void)
{
    return (PINB&(1<<0) ? 0 : (1<<0)) |
           (PINB&(1<<1) ? 0 : (1<<1)) |
           (PINB&(1<<2) ? 0 : (1<<2)) |
           (PINB&(1<<3) ? 0 : (1<<3)) |
           (PINB&(1<<7) ? 0 : (1<<4)) |
           (PIND&(1<<0) ? 0 : (1<<5)) |
           (PIND&(1<<1) ? 0 : (1<<6)) |
           (PIND&(1<<2) ? 0 : (1<<7)) |
           (PIND&(1<<3) ? 0 : (1<<8)) |
           (PINC&(1<<6) ? 0 : (1<<9)) |
           (PINC&(1<<7) ? 0 : (1<<10)) |
           (PIND&(1<<5) ? 0 : (1<<11)) |
           (PINE&(1<<6) ? 0 : (1<<12)) |
           (PIND&(1<<4) ? 0 : (1<<13)) |
           (PIND&(1<<7) ? 0 : (1<<14)) |
           (PINB&(1<<4) ? 0 : (1<<15));
}

/* Row pin configuration
 * row: 0   1   2   3   4   5   6   7
 * pin: F0  F1  F4  F5  F6  F7  B6  B5
 */
static void unselect_rows(void)
{
    // Hi-Z(DDR:0, PORT:0) to unselect
    DDRF  &= ~0b11110011;
    PORTF &= ~0b11110011;
    DDRB  &= ~0b01100000;
    PORTB &= ~0b01100000;
}

static void select_row(uint8_t row)
{
    // Output low(DDR:1, PORT:0) to select
    switch (row) {
        case 0:
            DDRF  |= (1<<0);
            PORTF &= ~(1<<0);
            break;
        case 1:
            DDRF  |= (1<<1);
            PORTF &= ~(1<<1);
            break;
        case 2:
            DDRF  |= (1<<4);
            PORTF &= ~(1<<4);
            break;
        case 3:
            DDRF  |= (1<<5);
            PORTF &= ~(1<<5);
            break;
        case 4:
            DDRF  |= (1<<6);
            PORTF &= ~(1<<6);
            break;
        case 5:
            DDRF  |= (1<<7);
            PORTF &= ~(1<<7);
            break;
        case 6:
            DDRB  |= (1<<6);
            PORTB &= ~(1<<6);
            break;
        case 7:
            DDRB  |= (1<<5);
            PORTB &= ~(1<<5);
            break;	    
    }
}
I'm happily typing on my SSK at the moment. Yay!
Next up is to etch some PCB's.

Also, a couple of questions since I need to take a break from looking at code:

The number lock. I'm assuming the easiest solution would be to map a new layer with the Shift+Scroll Lock combo?

LED support! I tried changing the led file to write to the teensy's LED as an experiment, but I'm not getting anything. Which brings me to...

I2C i/o expander! I would like to be able to have control of status LED's as well as some backlighting. Sure I could get some teensy ++'s, but the regular teensy + an expander is significantly less expensive. Any experience/tips with those?

Thanks! :)

User avatar
Halvar

02 Jun 2014, 01:55

Can't really help you, just a quick Thank You for that matrix graph for the Model M and the matrix code. I might use that in the future, as my SSK came with a terminal controller.

User avatar
phosphorglow

02 Jun 2014, 02:29

Halvar wrote:Can't really help you, just a quick Thank You for that matrix graph for the Model M and the matrix code. I might use that in the future, as my SSK came with a terminal controller.
Hey no problem! It'd be a shame to keep it and all of its color coded prettiness to myself - I'm glad it helps!

I have a terminal SSK as well that's been waiting for something neat like this.

User avatar
phosphorglow

02 Jun 2014, 03:17

(OH OH!!! I just remembered my funny thought from earlier. Someone more talented than myself should throw some code together to utilize the speakers in the keyboards equipped with them. Each key press could sound like a Selectric typewriter. >:D)

quantalume

02 Jun 2014, 06:08

Thanks for posting this. It never dawned on me that the membrane leads are on 100 mil centers, but they obviously are if you have it plugged into a breadboard. Here I was thinking I'd need to lay out a custom PCB just to utilize the connectors. :roll: I have a nice Wheelwriter keyboard I'd like to make a controller for.
wheelwriter.jpg
wheelwriter.jpg (56.35 KiB) Viewed 11022 times

User avatar
phosphorglow

02 Jun 2014, 22:11

quantalume wrote:Thanks for posting this. It never dawned on me that the membrane leads are on 100 mil centers, but they obviously are if you have it plugged into a breadboard. Here I was thinking I'd need to lay out a custom PCB just to utilize the connectors. :roll: I have a nice Wheelwriter keyboard I'd like to make a controller for.
Yeah it's rather convenient! Either desolder them from a dead board, or as far as I can tell, Mouser sells them.

I intend on picking up one of those Wheelwriter keyboards soon, so if I get to it before you I'll keep you updated on the matrix layout. I'm thinking wooden case...?

quantalume

03 Jun 2014, 04:18

phosphorglow wrote:
quantalume wrote:I intend on picking up one of those Wheelwriter keyboards soon, so if I get to it before you I'll keep you updated on the matrix layout. I'm thinking wooden case...?
Sounds like a deal. Yes, I was thinking wood, but I'm not sure whether or not to keep the plastic bezel. It does trim off the board nicely, but it's got about an inch in width on either side that's unnecessary, and it has that lip on top that adds another inch of unnecessary height.

quantalume

09 Jun 2014, 04:26

I'm thinking of making a "universal" Model M to Teensy 2.0 PCB. The idea is that, regardless of which Model M you have, you can solder in the appropriately-sized membrane connectors and solder in a Teensy, and you're good to go. Any other configuration would take place in software.

What I've been able to discern based on my Model M inventory is that the spacing between the row and column connectors is 0.685 inches (closest conductors, center-to-center), regardless of the specific configuration (84/85, 101/102, Wheelwriter, etc). There are 15 or 16 columns and 8 or 15 rows (the Wheelwriter board I have has 15 row positions, of which only 8 are used). The 122-key board has 20 columns, so it's impossible to use a Teensy on it unless you place an external latch and make the appropriate modifications to the firmware.

User avatar
rklm

17 Jun 2014, 22:02

I considered doing something like this in my current '88 model m restoration project, but I gave up once I couldn't find a way to add diodes for NKEY rollover.

If you guys find a way to wire this matrix and add NKEY rollover via hardware/software, you would have my interest highly piqued.

User avatar
Muirium
µ

17 Jun 2014, 22:42

Can't be done. Like all membrane keyboards, Model Ms lack NKRO at the matrix level, and you would have to replace the membranes entirely to add it yourself. I did consider trying thin film diodes myself once…

http://deskthority.net/workshop-f7/plan ... 0model%20m

User avatar
rklm

17 Jun 2014, 23:23

Oh well... at least my 60% has it.

I am soldering LEDs for custom backlighting on my M atm, so that will keep me satisfied until I come across a goodwill model F!

User avatar
Muirium
µ

17 Jun 2014, 23:48

Backlighting, on an M? Where are you putting the LEDs?

User avatar
rklm

18 Jun 2014, 01:02

I will give you a hint... It involves the distance between the barrels on the plastic plate.

I will post pictures here on the workshop tomorrow or the next day (when I get the rest of my parts from Unicomp)

Post Reply

Return to “Workshop”