Matias Mini Quiet Pro FK 303 keyboard scan matrix

I have been using a Matias Mini quiet Pro keyboard at work for a while now. I recently decided to replace it with a KB Paradise V80 (also with Matias quiet switches) to match the TKL layout of the keyboard I use at home. This was mainly because the different key placement between my home and office keyboard was driving me crazy. Using the standard TKL layout is nice, but the thing I miss the most about the mini quiet pro is the stealth space bar, which has to be the least noisy spacebar I have ever used. I should post a comparison video/audio of it someday.

matias1

 

By inspecting the photos posted on a review of this keyboard I realized that the keyboard controller daughter board was replaceable. So I decided to make a Teensy based replacement controller board so that I can make custom key mappings to fix some of my issues with this keyboard:

  • Change page-up, page-down to home and end
  • Change F12 to default to insert, and Fn+F12 to F12
  • Change caps-lock to Fn

01d0cc6720540417bb95fa4e78492d0c3b26f642a8

Opening the keyboard involved removing two screws on the back (thankfully without any warranty void stickers) followed by using plastic cards to push in the 7 tabs holding the top plate to the bottom plate. The plastic tabs are fairly sturdy but I somehow managed to break one of them the second time I opened the case, so do be careful about not pulling apart the top half till all the tabs are released.

DSCF5539

The key switches are mounted on a metal plate and soldered on to the two layer FR4 PCB. The daughter board with the 1×4 USB hub chip (Genesys logic GL852G) and keyboard controller (Weltrend WT6522, uses one of the 4 hub ports) mount on a daughter board which connects to the main board via 2mm header pins. The keyboard scan matrix is wired up to the two 17 pins sockets, which for some reason are offset by 1.5 pin width (1.5 * 2mm = 3mm). The other two sockets are used for the three USB hub ports.

DSCF5528DSCF5537

DSCF5533

After some googling I came across this post about reverse engineering the keyboard scan matrix. I mostly followed the directions from that post but with the following important additions:

  • Since one of the keyswitch terminals is connected to the scan row/column via a diode the polarity of the multimeter probes matters. I placed the black/common probe on the keyswitch terminals and scanned the pin headers with the red probe.
  • The left terminal seems to have a diode on most keys – and I named it pin 2, and the right terminals as pin 1 for each switch.
  • The pin with the diode made a blip sound vs. continuous beep sound for the pin without the diode.
  • As you scan though the keys remember to make note of which key blips vs. beeps
  • Build a table and use rows for pins that go blip and columns for pins that go beep, and add the PCB screen print label at the intersection of the row and column

 

 

0144a5aaffcf6cf087d1204cac77a4fa6305c60d9a

Scanning through all the keys took somewhere between 2 to 3 hours with multiple breaks taken in between. And then another hour to analyze and compile the data and find measurement bugs/typos.

Google drive spreadsheet with scan matrix details here.

Next I need to figure out how to make a PCB for this in Eagle/KiCAD and then map the pins to a Teensy 2.0++ board.

Advertisements

Frosty Flake controller for Cooler Master Storm QuickFire Rapid keyboard

After a sudden brain wave last week I had been googling to see if anyone of the mechanical keyboard models had easily modifiable firmware and realized that the very keyboard I was typing on had a removable daughter board… and there was already a ATmega32U2 (note U2 & not U4) replacement controller available for it called the Frosty Flake.

I ordered one of these and will be documenting my changes to the firmware here. Here are a few photos of it next to the original board (thinner and flimsier).

I also decided to remove the top plastic cover on my keyboard to give it a more naked look and taped up the controller to avoid shorting it. I plan to make a transparent acrylic laser cut cover for the Frosty Flake.

01d135d9843b976dcbb92e615f0c9c0427f32cd37b

Passing serial data over I2C between two Arduino’s

Below you will find some arduino code for passing serial data over I2C between two Arduino’s. Parts of the following code were salvaged from various places around the internet.

8536568652_0500c802fd

This can also be used for:

1) General communication between two Arduino’s over I2C

2) Using a second Arduino to expand the peripherals, for example: add a a second serial port device, add a second arduino for dedicated monitoring of certain interfaces

I used this to communicate between a Diavolino@ 5V with a Arduino Pro @ 3.3V using the Sparkfun level converter TX lines. My attempts at trying to run this without the level converter using pullup registers tied to 3.3V did not work. I will reattempt that once I get a scope for debug.

I2C Master code:

#include <Wire.h>
// SCL - analog pin 5
// SDA - analog pin 4

int led = 13;
int debug = 0;

void setup() {
  pinMode(led, OUTPUT);     
  Wire.begin(); //join I2C as master
  Serial.begin(9600); //setup serial for input and output
  digitalWrite(led, HIGH);
  Serial.println("I2C MASTER 3.3V");
  delay(5000); // the master should be ready after the slave
  Serial.println("Ready");
}

void loop() {
  if (Serial.available()) {
    char inChar = (char)Serial.read(); 
    if (debug) {
      Serial.print("serial:");
      Serial.println(inChar);
    }
    Wire.beginTransmission(4);
    Wire.write(inChar);
    Wire.endTransmission();
  } 
  else {
    if (debug) Serial.println("!serial");
  }

  Wire.requestFrom(4, 1); // request 1 byte from slave device #4
  if (debug) Serial.println("waitOnReq");
  while(!Wire.available());
  char d = Wire.read();
  if (debug) {
    Serial.print(" reqData:");
    Serial.println(d);
    delay(50);
  } 
  else { // ignore special character ?
    if (d != '?') Serial.print(d);
  }

  if (debug) digitalWrite(led, HIGH);
  if (debug) delay(200);
}

I2C Slave code:

#include <Wire.h>

// SCL - analog pin 5
// SDA - analog pin 4
int led = 13;
int debug = 0;
void setup() {
    pinMode(led, OUTPUT);     
    Wire.begin(4);                // join i2c bus with address #4
    Wire.onReceive(receiveEvent); // register event
    Wire.onRequest(requestEvent); // register event
    Serial.begin(9600);           // start serial for input and output
    digitalWrite(led, HIGH);
    Serial.println("I2C SLAVE 5V");
    delay(2000); // the slave should become ready first
    Serial.println("Ready");
}

void loop() {
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
    if (debug) {
        Serial.print("rxEvent:");
        Serial.println(howMany);
    }
    while(Wire.available())
    {
        char c = Wire.read();
        if (debug) {
            Serial.print("i2c_rx:");
            Serial.println(c);
        } 
        else {
            Serial.print(c);
        }
    }
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
    if (debug) Serial.println("reqEvent");
    if (debug) digitalWrite(led, LOW);
    if (Serial.available()) {
        char inChar = '0'; 
        inChar = (char)Serial.read(); 
        Wire.write(inChar);
        if (debug) {
            Serial.print("sent:");
            Serial.println(inChar);
        }
    } else { //send some dummy data if no data is available from serial
        Wire.write("?");
        if (debug) Serial.println("!sent:");
    }
}

Giving Arduino a second UART over I2C by stacking another Arduino on top

Now that I have the Cellular modem working with the PC over serial I am trying to get the same thing implemented on an Arduino. Since the modem uses the serial interface I will not be able to use that to debug my program via a serial terminal running on my PC.

I tried using the SoftSerial (or the NewSoftSerial) library but ran into data corruptions even at the low speeds, so I decided to look for other ways to get another hardware UART on the Arduino. For a while I was contemplating getting a Mega Pro from Sparkfun but its price was a turnoff. In the end I realized that I could just stack another Arduino on my Diavolino (both interfaced to each other over I2C as master slave) and after trimming the UART rx/tx shield pins be able to separate out the two UARTs.

The other issue is that the UART pins of the Cellular modem are not 5V tolerant. This had not affected me till now since I was using the Adafruit FTDI friend at 3.3V logic levels when connecting to the PC serial port. So I could not get another 5V Diavolino. In the end I decied to get a 3.3V Arduino Pro and stack that on top of my 5V Diavolino.

Overall the connections will look something like the following diagram:

arduino extra serial port plan

Note that when I drew this I was planning on using another Diavolino at 3.3V but decided against it since it seemed like more work because I would need to get the 3.3V regulator on my own and also somehow get an 8MHz AVR chip for it. In hind sight this may not have been a good idea since the Arduino Pro seems to be connecting both the Vcc pins in the header to 3.3V. The Diavolino instead has them separated which seems more sensible to me.

Another thing I forgot to show in the diagram above are the pull up registers for the I2C lines (SDA & SCL) between the two Arduino boards. I am hoping that connecting those to 3.3v would work for the 5v arduino, but I am not sure.

State Machine based serial interface to SM5100b shield in Python

Ever since I got TCP data rx/tx working on the SparkFun SM5100b GSM/GPRS shield I have been prepping for the next step which is to get HTTP GET requests working. The problem I seem to be having here is that the HTTP server disconnects the TCP connection immediately after sending the response to the GET request, and I am not able to transfer the TCP data received using the AT command after the TCP connection has been disconnected.

Yesterday I finally got a state machine based serial interface written in Python working. The input to the Python script is a state machine description written in a YAML file.

Dummy Shimmy

Here is the script:

https://github.com/cyclicredundancy/VCX/blob/master/projects/cellular_prowl/modem_driver.py

And here is a very simple YAML state machine file for the boot up sequence:

https://github.com/cyclicredundancy/VCX/blob/master/projects/cellular_prowl/cellular_state_machine.yaml

Coding up something equivalent for the Arduino will be a pain.

Sparkfun GSM/GPRS SM5100b shield on a Diavolino

I have decided to return the SM5100B evaluation board since I am instead using the SM5100B cellular shield. This is because I was not really going to use any of the interface pins of the SM5100B module broken out on the eval board. One useful thing about the shield (that I wasn’t expecting) is that it is able to reset the cellular module using the on board reset button similar to the eval board.

8008528875_923b20b2d9_z

The Diavolino board here is running without any AVR 328 mega chip plugged into it, and has the 2.5mm x 5.5mm power barrel socket for the 5V 3A regulated power supply from EvilMadScience.

Diavolino hosting a GSM/GPRS shield

Meanwhile although I can receive TCP data on the SM5100B modem over GPRS I still haven’t been able to successfully confirm transmission of data.

TCP connection over GPRS with SM5100B module

After having no success sending GET requests to HTTP servers I finally decided to set up my own tcp server by directing a port on my router to my PC and setting up a simple tcpserver listener in cygwin like this:

~ > tcpserver -t1000 -v -Bare_we_receiving 0 9876 bash -c "sleep 1000"
tcpserver: status: 0/40

Then I sent the following commands to the modem

AT+CGATT? 
AT+CGDCONT=1,"IP","epc.tmobile.com" 
AT+CGPCO=0,"None","",1 
AT+CGACT=1,1
AT+SDATACONF=1,"TCP","MY_ROUTER_ADDRESS",9876 
AT+SDATARXMD=1,1,0
AT+SDATASTART=1,1

For some reason the MY_ROUTER_ADDRESS had to be the text host name instead of the IP address, which was something like c-blah-blah.comcast.net for me as per my router.

Immediately I saw a connection appear in the tcpserver log:

tcpserver: status: 1/40
tcpserver: pid 5232 from 208.54.32.166
tcpserver: ok 5232 :::ffff:192.168.1.111:9876 :::ffff:208.54.32.166::50107
tcpserver: end 5232 status 256
tcpserver: status: 0/40

And then some data was received on the GPRS modem side:

> +STCPD:1
>

Which I read back promptly:

AT+SDATASTATUS=1
> +SOCKSTATUS: 1,1,0102,54,0,16
> 
> OK
>
AT+SDATAREAD=1
> +SSTR:1,are_we_receiving
> 
> OK
>

And it exactly matched the banner text. So atleast I can establish TCP connections. The AT command interface though is a real pain.