Converting NerD60 to TMK

From Deskthority wiki
Jump to navigation Jump to search

Introduction

  • NerD60 is a PCB designed and produced by GON's KeyboardWorks.
  • The default firmware is closed source and has some stability issues (the keyboard is not recognized in BIOS or in GRUB, lag on OSX)
  • I wanted TMK firmware on this keyboard because this software has a lot of features.
  • In TMK the code for NerD60 and 80(TKL) was created by Deskthority user xauser, you can find the code here(this code is not longer maintained so you are better off using the Repo maintained by xauser )
  • Now a BIG WARNING: what I'm going to explain here has the potential to brick your expensive and quite rare Korean keyboard, do it on your own risk and don't blame this article or yours truly for any mishaps.
  • Also as a warning, once you have converted the board you won't be able to go back to the original firmware unless you get the original bootloader from GON (you can't make a backup because he protected the thing ), also you are loosing official support from GON .
  • In this article we assume that the ISP programmer used is an USBasp , in case you will be using something else the commands will have to be changed in order to reflect the correct ISP programmer used.
  • For this mod there is also a discussion thread here, feel free to join and contribute or ask questions.
  • And last but not least, please feel free to contribute to this article

PCB Compatibility

  • So far it has been tested with NerD60 v1.6/v2.0/v2.1 (these were tested by me personally) and NerD80(TKL) v2.0

Prerequisites

  • What you need is a NerD60 PCB (well duh)
  • You need an ISP programmer also, I have used an USBasp more info can be found here
  • You also need a computer, I have used Linux for this, but you can use also Mac or Windows (the Windows drivers are on the USBasp website)
  • Also good are some breadboard cables like these:

Discover USBasp

  • It's important to get familiar with your tools.
  • First thing, don't be cheap, buy the original product, part of the money you pay will go to the developer of the USBasp, without our support such tools will die.
  • How the USBasp looks, well… like this :
  • The original product will have 3 jumpers: these are quite important, at least 2 of them; some of the cheap clones don't have them. One jumper is for Power (you will power the MCU from the ISP), Slow (this will reduce the speed of the programmer) and Service (not important for normal usage)
  • The pinouts for the 10 pin connector are:
  • For the cable (the one that comes with the USBasp ) the pinouts are :
  • A more simple image of the female cable pins (I like simple things ), the colors are what I have used in my setup:
  (Red) VCC -> *  * <- MOSI (Green)
        GND -> *  * <- NC
        GND -> *  * | <- RST (Yellow)
        GND -> *  * <- SCK (White)
(Black) GND -> *  * <- MISO (Blue)
  • And this how my USBasp looks with the breadboard cables connected (the cables fit snugly in the ribbon cable, not so good on the ISP headers of the PCB, but if you are careful it doesn't present any issues):

Install the tools and configure Linux to use USBasp

  • Install the AVR tools (I have Debian, adapt it to your environment):
root@liz:~/ apt-get install gcc-avr gdb-avr binutils-avr avr-libc avrdude make
  • Set the udev rule for USBasp (check in output of dmesg and lsusb for the correct ID's. This is what I have; chances are you will have the same):
vi /etc/udev/rules.d/60-objdev.rules
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", MODE="0666", SYMLINK+="USBasp"
  • Restart udev and plug in again your USBasp

Conversion

Test the connection to the keyboard

  • The keyboard must be unplugged
  • On the USBasp set the jumpers for Power and Slow (if you don't set it to Slow the ISP will be too fast and you get "miss-fires" while reading or writing, at least this was my case with USBasp)
  • Connect the breadboard cables to the ISP headers on the PCB.
  • On the v1.6 PCB this ISP headers are located on the bottom of the PCB where the Spacebar resides (right under the NerD logo). This is how they look:
  • On the v2.1 PCB the ISP headers are next to the Caps Lock switch, on the left side of the PCB.
  • Plug the USBasp in your computer (the green Power LED should light up on the programmer)
  • Now it's time to see if you ca read data from the controller (do it for more times to make sure it works every time, if you get warnings don't ignore them and don't use -F as in force !!):
   user@liz:~/Software/Teensy$ avrdude -p m32u4  -c usbasp -U flash:r:/tmp/dump1.hex:i -P /dev/USBasp 

   avrdude: AVR device initialized and ready to accept instructions

   Reading | ################################################## | 100% 0.02s

   avrdude: Device signature = 0x1e9587
   avrdude: reading flash memory:

   Reading | ################################################## | 100% 141.76s

   avrdude: writing output file "/tmp/dump1.hex"

   avrdude: safemode: Fuses OK (E:C3, H:D8, L:DF)

   avrdude done.  Thank you.

Flash the new bootloader

  • To this point we didn't do anything to the keyboard, after the next step you won't be able to use GONs software to program your board, this is the point of no return (during the programming the Red LED will light up on the programmer).
  • I have used the standard ATMega32U4-usbdevice_dfu-1_0_0.hex bootloader image from ATMEL web site ( http://www.atmel.com/devices/ATMEGA32U4.aspx ).
   user@liz:~/Software/Teensy$ avrdude -p m32u4  -c usbasp -U flash:w:ATMega32U4-usbdevice_dfu-1_0_0.hex -P /dev/USBasp

   avrdude: AVR device initialized and ready to accept instructions

   Reading | ################################################## | 100% 0.01s

   avrdude: Device signature = 0x1e9587
   avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
            To disable this feature, specify the -D option.
   avrdude: erasing chip
   avrdude: reading input file "ATMega32U4-usbdevice_dfu-1_0_0.hex"
   avrdude: input file ATMega32U4-usbdevice_dfu-1_0_0.hex auto detected as Intel Hex
   avrdude: writing flash (32768 bytes):

   Writing | ################################################## | 100% 0.00s

   avrdude: 32768 bytes of flash written
   avrdude: verifying flash memory against ATMega32U4-usbdevice_dfu-1_0_0.hex:
   avrdude: load data flash data from input file ATMega32U4-usbdevice_dfu-1_0_0.hex:
   avrdude: input file ATMega32U4-usbdevice_dfu-1_0_0.hex auto detected as Intel Hex
   avrdude: input file ATMega32U4-usbdevice_dfu-1_0_0.hex contains 32768 bytes
   avrdude: reading on-chip flash data:

   Reading | ################################################## | 100% 0.00s

   avrdude: verifying ...
   avrdude: 32768 bytes of flash verified

   avrdude: safemode: Fuses OK (E:C3, H:D8, L:DF)

   avrdude done.  Thank you.


  • OK, now you are the lucky owner of a keyboard with a bootloader LOL , you can plug in the keyboard in USB port and see that it is recognized by the system. The controller is in DFU mode:
[ 5564.032173] usb 1-1: USB disconnect, device number 14
[ 5565.960092] usb 1-1: new full-speed USB device number 15 using uhci_hcd
[ 5566.141092] usb 1-1: New USB device found, idVendor=03eb, idProduct=2ff4
[ 5566.141095] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 5566.141097] usb 1-1: Product: ATm32U4DFU
[ 5566.141099] usb 1-1: Manufacturer: ATMEL
[ 5566.141100] usb 1-1: SerialNumber: 1.0.0

Flash TMK firmware

  • Now you can write the TMK firmware, I have used the default keymap from tmk/nerd just to see that it works. I used FLIP (on Windows) to write the firmware. On Windows you need to install the ATm32U4DFU driver.
  • How to use TMK is beyond the scope of this guide, but I have shared some sample keymaps just look further in this article.
  • At this point the keyboard starts only in DFU mode (starts the bootloader instead of the firmware), I could test that the firmware is working by starting the application from FLIP (uncheck Reset).
  • You can see that the keyboard is recognized :
   [  596.236048] usb 1-1: new full-speed USB device number 7 using uhci_hcd
   [  596.421099] usb 1-1: New USB device found, idVendor=feed, idProduct=6060
   [  596.421102] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
   [  596.421104] usb 1-1: Product: NerD
   [  596.421106] usb 1-1: Manufacturer: GON
   [  597.578507] input: GON NerD as /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1:1.0/0003:FEED:6060.000C/input/input25
   [  597.578790] hid-generic 0003:FEED:6060.000C: input,hidraw0: USB HID v1.11 Keyboard [GON NerD] on usb-0000:00:1a.0-1/input0
   [  597.583386] input: GON NerD as /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1:1.1/0003:FEED:6060.000D/input/input26
   [  597.583611] hid-generic 0003:FEED:6060.000D: input,hidraw1: USB HID v1.11 Mouse [GON NerD] on usb-0000:00:1a.0-1/input1
   [  597.589211] input: GON NerD as /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1:1.2/0003:FEED:6060.000E/input/input27
   [  597.589408] hid-generic 0003:FEED:6060.000E: input,hidraw5: USB HID v1.11 Device [GON NerD] on usb-0000:00:1a.0-1/input2
   [  597.594226] hid-generic 0003:FEED:6060.000F: hiddev0,hidraw6: USB HID v1.11 Device [GON NerD] on usb-0000:00:1a.0-1
  • Now, in order to make the keyboard start the firmware you have to change the value of the HFUSE, don't mess around with the other fuses, you risk to break your board, unless you really know what you are doing!!!
  • I have set the HFUSE value to 0xD9.
  • Just a side note : HFUSE 0xD9 means : OCDEN disabled, JTAGEN disabled, SPIEN enabled, WDTON disabled, EESAVE disabled, BOOTSZ1 enabled, BOOTSZ0 enabled, BOOTRST disabled. While HFUSE 0xD8 you have the same things as above with the exception of BOOTRST which is enabled(this was the default setting that came with the board from GON, and caused me a lot of grief).
  • Unplug the keyboard from the USB port and reconnect the ISP programmer. Again test a few times that you can really read the controller before you write anything, if you get warnings check the cables and find the source of the problem, don't go around forcing things!!!
user@liz:~/Software/Teensy$ avrdude -c usbasp -p m32u4 -U lfuse:w:0xdf:m -U hfuse:w:0xd9:m -U efuse:w:0xc3:m -P /dev/USBasp

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e9587
avrdude: reading input file "0xdf"
avrdude: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xdf:
avrdude: load data lfuse data from input file 0xdf:
avrdude: input file 0xdf contains 1 bytes
avrdude: reading on-chip lfuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of lfuse verified
avrdude: reading input file "0xd9"
avrdude: writing hfuse (1 bytes):

Writing | ################################################## | 100% 0.02s

avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xd9:
avrdude: load data hfuse data from input file 0xd9:
avrdude: input file 0xd9 contains 1 bytes
avrdude: reading on-chip hfuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
avrdude: reading input file "0xc3"
avrdude: writing efuse (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of efuse written
avrdude: verifying efuse memory against 0xc3:
avrdude: load data efuse data from input file 0xc3:
avrdude: input file 0xc3 contains 1 bytes
avrdude: reading on-chip efuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of efuse verified

avrdude: safemode: Fuses OK (E:C3, H:D9, L:DF)

avrdude done.  Thank you.
  • Now disconnect the ISP and plug the USB cable, the keyboard should start in firmware mode and should work without any problems.
  • The default keymap fotm GitHub has the following shortcut that can be used to access the bootloader : Left Shift + Right Shift + Fn-Y (Paus) (Fn is the Contextual Menu key on a 1.25u bottom row keyboard or the left Win key on a 1.5u bottom keyboard ). Or you can short the GND and RST pins on the PCB.

Sample TMK Keymaps

  • As I have said before, how to use TMK is beyond the scope of this guide, but considering that the layout on GitHub is a bit strange I can share a more vanilla one, it's almost a HHKB layout.
  • I have modified the keymap_common.h file by adding also an ANSI125 section, it looks like this:
/*
Copyright 2014 Ralf Schmitt <ralf@bunkertor.net>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef KEYMAP_COMMON_H
#define KEYMAP_COMMON_H

#include <stdint.h>
#include <avr/pgmspace.h>
#include "keycode.h"
#include "action.h"
#include "action_macro.h"
#include "report.h"
#include "host.h"
#include "print.h"
#include "debug.h"
#include "keymap.h"

extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
extern const uint16_t fn_actions[];

#define KEYMAP( \
        K08,      K09, K18, K19, K28, K29, K38, K39, K48, K49, K58, K59, K68,    K69, K88, K89, \
        K00, K01, K10, K11, K20, K21, K30, K31, K40, K41, K50, K51, K60, K61,    K80, K81, K84, \
        K02, K03, K12, K13, K22, K23, K32, K33, K42, K43, K52, K53, K62, K63,    K82, K83, K85, \
        K04, K14, K15, K24, K25, K34, K35, K44, K45, K54, K55, K64, K71, K65,                   \
        K07, K79, K16, K17, K26, K27, K36, K37, K46, K47, K56, K57, K66, K67,         K86,      \
        K06, K05, K78,                K70,                K72, K73, K74, K75,    K76, K77, K87  \
) { \
      { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07, KC_##K08, KC_##K09 }, \
      { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17, KC_##K18, KC_##K19 }, \
      { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27, KC_##K28, KC_##K29 }, \
      { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37, KC_##K38, KC_##K39 }, \
      { KC_##K40, KC_##K41, KC_##K42, KC_##K43, KC_##K44, KC_##K45, KC_##K46, KC_##K47, KC_##K48, KC_##K49 }, \
      { KC_##K50, KC_##K51, KC_##K52, KC_##K53, KC_##K54, KC_##K55, KC_##K56, KC_##K57, KC_##K58, KC_##K59 }, \
      { KC_##K60, KC_##K61, KC_##K62, KC_##K63, KC_##K64, KC_##K65, KC_##K66, KC_##K67, KC_##K68, KC_##K69 }, \
      { KC_##K70, KC_##K71, KC_##K72, KC_##K73, KC_##K74, KC_##K75, KC_##K76, KC_##K77, KC_##K78, KC_##K79 }, \
      { KC_##K80, KC_##K81, KC_##K82, KC_##K83, KC_##K84, KC_##K85, KC_##K86, KC_##K87, KC_##K88, KC_##K89 }  \
}

#ifdef NERD_LAYOUT_60
  #define KEYMAP_ANSI150( \
          K08, K01, K10, K11, K20, K21, K30, K31, K40, K41, K50, K51, K60, K61, \
          K02, K03, K12, K13, K22, K23, K32, K33, K42, K43, K52, K53, K62, K63, \
          K04, K14, K15, K24, K25, K34, K35, K44, K45, K54, K55, K64,      K65, \
          K07,      K16, K17, K26, K27, K36, K37, K46, K47, K56, K57, K66,      \
          K06, K05, K78,                K70,                     K73, K74, K75  \
  ) KEYMAP( \
          K08,      NO,  NO,  NO,  NO,  NO,  NO,  NO,  NO,  NO,  NO,  NO,  NO,   NO,  NO,  NO,  \
          NO,  K01, K10, K11, K20, K21, K30, K31, K40, K41, K50, K51, K60, K61,  NO,  NO,  NO,  \
          K02, K03, K12, K13, K22, K23, K32, K33, K42, K43, K52, K53, K62, K63,  NO,  NO,  NO,  \
          K04, K14, K15, K24, K25, K34, K35, K44, K45, K54, K55, K64, NO,  K65,                 \
          K07, NO,  K16, K17, K26, K27, K36, K37, K46, K47, K56, K57, K66, NO,        NO,       \
          K06, K05, K78,                K70,                NO,  K73, K74, K75,  NO,  NO,  NO   \
  )
  #define KEYMAP_ANSI125( \
          K08, K01, K10, K11, K20, K21, K30, K31, K40, K41, K50, K51, K60, K61, \
          K02, K03, K12, K13, K22, K23, K32, K33, K42, K43, K52, K53, K62, K63, \
          K04, K14, K15, K24, K25, K34, K35, K44, K45, K54, K55, K64,      K65, \
          K07,      K16, K17, K26, K27, K36, K37, K46, K47, K56, K57, K66, K67, \
          K06, K05, K78,                K70,                K72, K73, K74, K75  \
  ) KEYMAP( \
          K08,      NO,  NO,  NO,  NO,  NO,  NO,  NO,  NO,  NO,  NO,  NO,  NO,   NO,  NO,  NO,  \
          NO,  K01, K10, K11, K20, K21, K30, K31, K40, K41, K50, K51, K60, K61,  NO,  NO,  NO,  \
          K02, K03, K12, K13, K22, K23, K32, K33, K42, K43, K52, K53, K62, K63,  NO,  NO,  NO,  \
          K04, K14, K15, K24, K25, K34, K35, K44, K45, K54, K55, K64, NO,  K65,                 \
          K07, NO,  K16, K17, K26, K27, K36, K37, K46, K47, K56, K57, K66, K67,        NO,       \
          K06, K05, K78,                K70,                K72,  K73, K74, K75,  NO,  NO,  NO   \
  )

#endif

#ifdef NERD_LAYOUT_80
  #define KEYMAP_ANSI150( \
          K08,      K09, K18, K19, K28, K29, K38, K39, K48, K49, K58, K59, K68,  K69, K88, K89, \
          K00, K01, K10, K11, K20, K21, K30, K31, K40, K41, K50, K51, K60, K61,  K80, K81, K84, \
          K02, K03, K12, K13, K22, K23, K32, K33, K42, K43, K52, K53, K62, K63,  K82, K83, K85, \
          K04, K14, K15, K24, K25, K34, K35, K44, K45, K54, K55, K64,      K65,                 \
          K07,      K16, K17, K26, K27, K36, K37, K46, K47, K56, K57, K66,            K86,      \
          K06, K05, K78,                K70,                     K73, K74, K75,  K76, K77, K87  \
  ) KEYMAP( \
          K08,      K09, K18, K19, K28, K29, K38, K39, K48, K49, K58, K59, K68,  K69, K88, K89, \
          K00, K01, K10, K11, K20, K21, K30, K31, K40, K41, K50, K51, K60, K61,  K80, K81, K84, \
          K02, K03, K12, K13, K22, K23, K32, K33, K42, K43, K52, K53, K62, K63,  K82, K83, K85, \
          K04, K14, K15, K24, K25, K34, K35, K44, K45, K54, K55, K64, NO,  K65,                 \
          K07, NO,  K16, K17, K26, K27, K36, K37, K46, K47, K56, K57, K66, NO,        K86,      \
          K06, K05, K78,                K70,                NO,  K73, K74, K75,  K76, K77, K87  \
  )
#endif

#endif // KEYMAP_COMMON_H
  • I have also created keymap_60_ansi125.c that looks like :
#include "keymap_common.h"
#include "backlight.h"

/*
 * HHKB'ish Layout
 */
const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    /* 0: Default layer
     * ,-----------------------------------------------------------.
     * |Esc|  1|  2|  3|  4|  5|  6|  7|  8|  9|  0|  -|  =|  Bspc |
     * |-----------------------------------------------------------|
     * |Tab  |  Q|  W|  E|  R|  T|  Y|  U|  I|  O|  P|  [|  ]| \   |
     * |-----------------------------------------------------------|
     * |Ctrl  |  A|  S|  D|  F|  G|  H|  J|  K|  L|Fn3|  '|Return  |
     * |-----------------------------------------------------------|
     * |Shift   |  Z|  X|  C|  V|  B|  N|  M|  ,|  .|  /|Shift |Fn |
     * |-----------------------------------------------------------|
     * |LCtrl|LGui|Alt|      Space             |Alt |RGui|App |RCtl|
     * `-----------------------------------------------------------'
     */
    KEYMAP_ANSI125(
        ESC, 1,   2,   3,   4,   5,   6,   7,   8,   9,   0,   MINS,EQL, BSPC, \
        TAB, Q,   W,   E,   R,   T,   Y,   U,   I,   O,   P,   LBRC,RBRC,BSLS,      \
        LCTL,A,   S,   D,   F,   G,   H,   J,   K,   L,   SCLN,QUOT,     ENT,       \
        LSFT,Z,   X,   C,   V,   B,   N,   M,   COMM,DOT, SLSH,     RSFT,FN0,       \
        LCTL,  LGUI,LALT,          SPC,                     RALT,  RGUI,APP,RCTL),
    /* 1: HHKB Fn layer
     * ,-----------------------------------------------------------.
     * |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Del    |
     * |-----------------------------------------------------------|
     * |` |   |   |   |   |   |   |   |Psc|Slk|Pus|Up |INS  |      |
     * |-----------------------------------------------------------|
     * |Ctrl  |VoD|VoU|Mut|Led|   |  *|  /|Hom|PgU|Lef|Rig|Enter   |
     * |-----------------------------------------------------------|
     * |        |   |   |   |   |   |  +|  -|End|PgD|Dow|      |   |
     * |-----------------------------------------------------------|
     * |    |    |    |                        |    |    |    |    |
     * `-----------------------------------------------------------'
     */
    KEYMAP_ANSI125(
        ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, DEL,  \
        GRV,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PSCR,SLCK,PAUS,UP,  INS,TRNS,      \
        TRNS,VOLD,VOLU,MUTE,FN1,TRNS,PAST,PSLS,HOME,PGUP,LEFT,RGHT,     PENT,      \
        TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PPLS,PMNS,END, PGDN,DOWN,     TRNS,TRNS,      \
        TRNS,TRNS,TRNS,          TRNS,                    TRNS,TRNS,TRNS,TRNS),
};

/*
 * Fn action definition
 */
const uint16_t PROGMEM fn_actions[] = {
    [0] = ACTION_LAYER_MOMENTARY(1),
    [1] = ACTION_BACKLIGHT_LEVEL(BACKLIGHT_SWITCH)
};
  • If you want to use also PCB LED's (underlight) add an extra Fn action in your keymap_60_ansi125.c file or whatever it is named, also don't forget to assign a key for FN2
 [2] = ACTION_BACKLIGHT_LEVEL(BACKLIGHT_PCB)
  • Now all you have to do is compile the firmware:
user@liz:~/Software/Teensy/tmk_keyboard-master/keyboard/nerd$ make LAYOUT=60 KEYMAP=ansi125