QMK 0.19.2で改良二乗マトリクスのキーボードファームウェアを作っていく話

はじめに

この記事はキーボード #1 Advent Calendar 2022 17日目の記事です。

adventar.org

16日はyfukuさん『軸の秤』でChocスイッチ17種のフォースカーブを測定してみた – Daily Craft Keyboardでした。
ChocはRed以外ほぼ使ったことないで、Sunset Tactileが気になりますが付けるキーボードがないんですよね。

毎年恒例のこの時期がやってきましたね。
去年は、KEEB_PDのAdvent Calendarに参加しましたがネタがなくて、yohewiさんのM0ii0+十を光らせました。



今年も、とりあえず参加してからネタを考えるスタイルにしたところ、なんと現在12/10で何もネタがないです。 特に思いつくものもなく、今から新しいものを作成するにしても時間が足りないので、以前Seeed Fusion DIY XIAO Mechanical Keyboard Contestで作成したGL516互換PCBのXR63GLを最新のQMK(0.19.2)に対応させていこうと思います。


2022年12月29日追記
この記事を書いてからQMKを確認したところ、0.19.4にバージョンが上がっていました。
また、プルリクエストを出して、マージされたバージョンは0.19.5でした。

改良二乗マトリクスとは

まず、二乗マトリクスですが、IKeJIさんが2019年頃に考案されたキーマトリクスです。 呼び方が複数あるので、いつも混乱するのですが、私は二乗マトリクスと呼んでいます。
(二乗マトリクス、総当たりマトリクス、square matrix、round-robin matrixなど)
標準的なキーマトリクスよりもダイオードを増やして、少ないGPIOでより多くのキーを使用出来るようになっています。
二乗マトリクスのほかにも倍マトリクス( Japanese duplex-matrix)などもあります。
ただ、使ったダイオードの仕様や使用環境などが影響して、押していないキーが入力されてしまうゴーストという現象が発生するデメリットも存在します。
改良二乗マトリクスは二乗マトリクスよりゴーストの発生率を抑えるように考案されたマトリクス方式となります。

たぶん私が説明するより、IKeJIさんの記事を見たほうが理解できると思うのでリンクを貼っておきます。

2019年 IKeJIさんのマトリクス記事
blog.ikejima.org

2022年 IKeJIさんマトリクス記事
blog.ikejima.org

KBD.newsで取り上げられた二乗マトリクスの記事
kbd.news

KBD.newsで取り上げられた改良二乗マトリクスの記事
kbd.news

キーボードについて

seeedのコンテストで作成したものを使用するため、既にPCBは手元にあります。 コンテストに参加した時の記事は細かく書いてないため、ちょっと説明しようと思います。

レイアウト

よくある65%はバックスペースやエンターの横にもキーがありますが、よく誤打するので私には不要かなと思っています。また、右シフトキーとアローキーも離れていないと誤打するので、右シフトキーを1.75Uから1.25Uに変更します。

回路図

改良二乗マトリクスでGPIOを9本使用すると9*(9-1)=72キーとなります。 以下が72キーの状態の回路図となります。

ここから不要なキーを消していきます。
まずは、PCB上にどういう配置するかを考えます。
余談ですが、コンテストの製造代のクーポン発行の締め切りを知らなくて、慌てて作るはめになりました。
結果、以下のようにしました。





次からデバッグしながら記事書くのでキーボード変えます。
ここまでは以下のキーボードで書きました。
Keyboard: GL516+XR63GL
Switch: DUROCK Full POM(Stock)
Keycap: IFK OG

QMKについて

12/11現在の最新バージョンは、0.19.2です。
QMKの破壊的変更で、内部で持っているキーコードが変更になったようです。
これにより、VIAとREMAPとの連携が取れなくなり、キーによっては動作がおかしくなっているようです。
現状、VIAまたはREMAPでキーマップを変更するなら0.19.2を使用しないほうがいいと思います。

QMKの変更点ですが、多すぎて全部の説明は出来ないのでリンクを貼っておきます。 docs.qmk.fm

新しいキーボード

QMK CLIでコマンドを実行するだけです。
以下のコマンドを実行すると対話式で実行されます。

qmk new-keyboard

まずは、キーボード名を聞かれます。

Ψ Generating a new QMK keyboard directory

Name Your Keyboard Project
For more infomation, see:
https://docs.qmk.fm/#/hardware_keyboard_guidelines?id=naming-your-keyboardproject

Keyboard Name?

今回はgl516フォルダの中にXR63GLのファームウェアを置きたいので、以下のように入力しエンターキーを押します。この時、キーボード名は必ず小文字を使用してください。

Keyboard Name? gl516/xr63gl

すると、以下のように聞かれるので、Github上の名前を入力してください。
表示されている名前でいいなら、何も入力せずエンターキーを押してください。

Attribution
Used for maintainer, copyright, etc

Your GitHub Username?  [gachiham]

以下のようにリアルネーム聞かれますが、私はそのままエンターキーを押します。

More Attribution
Used for maintainer, copyright, etc

Your Real Name?  [gachiham]


次に新しいキーボードのレイアウトを聞かれるので、一番近いレイアウトの番号を入力してください。
XR63GLは63キーなので一番近い6. 64_ansiを選びます。

Pick Base Layout
As a starting point, one of the common layouts can be used to bootstrap the process

Default Layout?
        1. 60_abnt2
        2. 60_ansi
        3. 60_ansi_arrow
        4. 60_hhkb
        5. 60_iso
        6. 64_ansi
        7. 64_iso
        8. 65_ansi
        9. 65_iso
            :
            :
        48. tkl_ansi
        49. tkl_iso
        50. tkl_nofrow_ansi
        51. tkl_nofrow_iso
        52. none of the above
Please enter your choice:  [52]

6を入力してエンターキーを押します。

Please enter your choice:  [52] 6

次に使用するマイコンの種類を選びます。
デフォルトでは25. atmega32u4になっています。
PCBに直接atmega32u4を実装している場合は、何も入力せずにエンターキーを押してください。
ProMicroを使用する場合、10. promicroを選択するために10を入力してエンターキーを押してください。

What Powers Your Project
For more infomation, see:
https://docs.qmk.fm/#/compatible_microcontrollers

MCU?
        1. bit_c_pro
        2. blackpill_f401
        3. blackpill_f411
            :
        9. kb2040
        10. promicro
        11. promicro_rp2040
            :
            :
        32. MKL26Z64
        33. RP2040
        34. STM32F042
            :
        51. WB32F3G71
        52. WB32FQ95
Please enter your choice:  [25]

私は、今回XIAO RP2040を使用するため、33. RP2040を選びます。

Please enter your choice:  [25] 33

コマンドが終了すると以下の文字列が表示されます。

Ψ Created a new keyboard called gl516/xr63gl.
Ψ To start working on things, `cd` into keyboards/gl516/xr63gl,
Ψ or open the directory in your preferred text editor.
Ψ And build with qmk compile -kb gl516/xr63gl -km default.

するとqmk_firmware\keyboards\gl516の中に、xr63glというフォルダが作成されており、その中に、最低限のファイルが生成されています。

defaultのキーマップでコンパイルしたい場合は、コマンド終了時に表示されている通りqmk compile -kb gl516/xr63gl -km defaultを実行します。

ファイル編集

12/12現在だとRP2040を使用している場合、new-keyboardコマンド実行直後にコンパイル出来ません。
理由は、info.jsonのmatrix_pinsの定義が RP2040の記述と異なるからです。
RP2040でのピンの記述はGP0~GP29です。
XIAO RP2040で使用出来るピン名は赤枠で囲った番号の頭文字にGを付けたものです。

info.json

ファイルを生成したままだと以下のようなマトリクスになっています。

{
    "matrix_pins": {
        "cols": ["C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2"],
        "rows": ["D1", "D1", "D1", "D1", "D1"]
    }
}


XR63GLのXIAO RP2040のピンの割り当ては以下のようにしています。


改良二乗マトリクスの場合、colとrowに同じピンがくるため、どちらもPIN1~PIN9の順番で書きます。

{
    "matrix_pins": {
        "cols": ["GP26", "GP27", "GP28", "GP29", "GP0", "GP3", "GP4", "GP2", "GP1"],
        "rows": ["GP26", "GP27", "GP28", "GP29", "GP0", "GP3", "GP4", "GP2", "GP1"]
    }
}


次にレイアウトですが、新しいキーボードを作成する際に64_ansiを選択しました。
キーマップは異なりますが、レイアウトは以下のようになっています。

{
    "layouts": {
        "LAYOUT_64_ansi": {
            "layout": [
                { "matrix": [0, 0], "x": 0, "y": 0 },
                { "matrix": [0, 1], "x": 1, "y": 0 },
                { "matrix": [0, 2], "x": 2, "y": 0 },
                { "matrix": [0, 3], "x": 3, "y": 0 },
                { "matrix": [0, 4], "x": 4, "y": 0 },
                { "matrix": [0, 5], "x": 5, "y": 0 },
                { "matrix": [0, 6], "x": 6, "y": 0 },
                { "matrix": [0, 7], "x": 7, "y": 0 },
                { "matrix": [0, 8], "x": 8, "y": 0 },
                { "matrix": [0, 9], "x": 9, "y": 0 },
                { "matrix": [0, 10], "x": 10, "y": 0 },
                { "matrix": [0, 11], "x": 11, "y": 0 },
                { "matrix": [0, 12], "x": 12, "y": 0 },
                { "matrix": [0, 13], "w": 2, "x": 13, "y": 0 },
                                :
                                :
            ]
        }
    }
}


LAYOUT_64_ansiLAYOUT_63_ansiに書き換えます。 また、右下のキーのサイズや位置が異なるため書き換えます。

{
    "layouts": {
        "LAYOUT_63_ansi": {
            "layout": [
                { "label":"ESC", "matrix": [0, 1], "x": 0, "y": 0 },
                { "label":"1!", "matrix": [0, 2], "x": 1, "y": 0 },
                { "label":"2@", "matrix": [0, 3], "x": 2, "y": 0 },
                { "label":"3#", "matrix": [0, 4], "x": 3, "y": 0 },
                { "label":"4$", "matrix": [0, 5], "x": 4, "y": 0 },
                { "label":"5%", "matrix": [0, 6], "x": 5, "y": 0 },
                { "label":"6^", "matrix": [0, 7], "x": 6, "y": 0 },
                { "label":"7&", "matrix": [0, 8], "x": 7, "y": 0 },
                { "label":"8*", "matrix": [1, 0], "x": 8, "y": 0 },
                { "label":"9(", "matrix": [1, 2], "x": 9, "y": 0 },
                { "label":"0)", "matrix": [1, 3], "x": 10, "y": 0 },
                { "label":"-_", "matrix": [1, 4], "x": 11, "y": 0 },
                { "label":"=+", "matrix": [1, 5], "x": 12, "y": 0 },
                { "label":"Backspace", "matrix": [1, 6], "w": 2, "x": 13, "y": 0 },
                                :
                                :
            ]
        }
    }
}


"matrix": [0, 0],の部分の補足をちょっとだけしようと思います。
この部分は、以前は、keyboard_name.hに記載していたレイアウトの定義です。
キーマトリクス上の何処を使用するかを座標で記述します。
改良二乗マトリクスの場合、[0, 0]ダイオードを入れているだけなので、スイッチとして使用出来ません。 そのため、[0, 1]から始まっています。
キーマトリクスの座標は以下のようになっています。

keymap.c

ここもLAYOUT_64_ansiLAYOUT_63_ansiに書き換えます。
また、アローキー横のMO(1)はXR63GLには存在しないため、消します。

    [0] = LAYOUT_64_ansi(
        KC_ESC,  KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    KC_6,    KC_7,    KC_8,    KC_9,    KC_0,    KC_MINS, KC_EQL,           KC_BSPC,
        KC_TAB,  KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_LBRC, KC_RBRC,          KC_BSLS,
        KC_CAPS, KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT,                   KC_ENT,
        KC_LSFT,          KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_RSFT, KC_UP,   MO(1), 
        KC_LCTL, KC_LGUI, KC_LALT,                            KC_SPC,                             KC_RALT, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
    ),
    [0] = LAYOUT_63_ansi(
        KC_ESC,  KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    KC_6,    KC_7,    KC_8,    KC_9,    KC_0,    KC_MINS, KC_EQL,           KC_BSPC,
        KC_TAB,  KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_LBRC, KC_RBRC,          KC_BSLS,
        KC_CAPS, KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT,                   KC_ENT,
        KC_LSFT,          KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_RSFT, KC_UP,
        KC_LCTL, KC_LGUI, KC_LALT,                            KC_SPC,                             KC_RALT, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
    ),


マトリクスとキーマップが完成したので、一度コンパイルしてみます。
フォルダ作成時に表示されたqmk compile -kb gl516/xr63gl -km defaultを実行します。

Ψ Compiling keymap with make --jobs=1 gl516/xr63gl:default


QMK Firmware 0.19.2
Making gl516/xr63gl with keymap default

arm-none-eabi-gcc.exe (GCC) 10.1.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Size before:
   text    data     bss     dec     hex filename
      0   26812       0   26812    68bc gl516_xr63gl_default.uf2

Compiling: quantum/keymap_introspection.c                             [OK]
            :
            :
Linking: .build/gl516_xr63gl_default.elf                              [OK]
Creating load file for flashing: .build/gl516_xr63gl_default.hex      [OK]
Creating UF2 file for deployment: .build/gl516_xr63gl_default.uf2     [OK]
Copying gl516_xr63gl_default.uf2 to qmk_firmware folder               [OK]
(Firmware size check does not yet support RP2040; skipping)

コンパイルに成功したのでqmk_firmwareのフォルダの中にgl516_xr63gl_default.uf2というファイルが生成されています。
なお、コンパイルが通るのかを確認したかっただけなので、ファイルの修正は続きます。

Bootmagic Lite

これは、決められたマトリクスのキーを押しながら、PCなどにUSB接続するとブートローダーが起動する機能です。主にファームウェアを書き換えたいが、物理的なリセットスイッチがない時やアクセスしにくい時に使用します。
info.jsonfeatures"bootmagic": trueと記述されている場合に機能が有効になります。

    "features": {
        "bootmagic": true,
    },


config.hに定義しない場合は、マトリクスの[0,0]が対象になりますが改良二乗マトリクスの場合、常に押されていると判定されてしまうので、マトリクスの[0.1]に変更します。
これで、ESCを押しながら、PCに接続するとブートローダーモードで起動するようになります。

#define BOOTMAGIC_LITE_ROW 0
#define BOOTMAGIC_LITE_COLUMN 1

詳細は公式ドキュメントを参照してください。
docs.qmk.fm

RP2040_BOOTLOADER_DOUBLE_TAP_RESET

これは、RP2040専用の機能でPCB上のリセットスイッチをダブルタップするとブートローダーモードで起動します。(正直、Bootmagic LiteやQK_BOOTキーを使用しても同じことが出来るので個人的には不要かなと思っています。) config.hに以下を追加します。

#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET
#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 500U
#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK 0U

これも詳細は公式ドキュメントを参照してください。
docs.qmk.fm

MATRIX_MASKED

この仕様を知らなくて、以前PCがキーボードを認識しなくてハマりました。
改良二乗マトリクスのダイオードのみの交点が、常に押しっぱなしと判断されてしまいPCが認識しません。STM32やRP2040の場合には必須のようです。
IKeJIさんのブログに記載されていました。
blog.ikejima.org

MATRIX_MASKEDを有効にするために、config.hに以下を追加します。

#define MATRIX_MASKED

2022年12月29日追記
次にkeymap.cに以下の定義を追加します。
レビューでkeymap.cではなく、<keyboard_name.c>に定義しなさいと指摘を受けました。
たしかに、keymap.cに定義するとキーマップ毎に同じ定義を書いておかなければならないので、新しくxr63gl.cを作り、ここに定義します。
これで、ダイオードのみの交点は無視されるため、PCがキーボードを認識するようになります。

#include QMK_KEYBOARD_H

const matrix_row_t matrix_mask[MATRIX_ROWS] = {
    0b1111111111111110,
    0b1111111111111101,
    0b1111111111111011,
    0b1111111111110111,
    0b1111111111101111,
    0b1111111111011111,
    0b1111111110111111,
    0b1111111101111111,
    0b1111111011111111,
};

いつもの通り、詳細は公式ドキュメントを参照してください。
docs.qmk.fm

デバッグ

もう一度コンパイルして、XIAO RP2040にuf2ファイルを書き込み、VIAでキーテストを行います。 全部認識したので完成です。


あとは、readme.mdinfo.jsonの情報を書き換えたり、QMKのコーディング規約通りに体裁を整えるとプルリクエストを行えると思います。

最後に

いかがでしたか?
ここまで読んだ方は、もうお気づきかと思いますが、この記事はIKeJIさんのブログとQMKの公式ドキュメントで出来ています!
有用な情報を発信してくださる先駆者の方々には感謝しています。
せっかくここまで作ったので、もうちょっと作業してQMKにプルリクを出してみようと思います。

明日はsatromiさんです。

QMK編は以下のキーボードで書きました。
Keyboard: GL516+TH63GL
Switch: Akko CS Lavender Purple(Stock)
Keycap: KAT Iron


P.S.
コマンド調べてる時に気づきましたが、qmk compile -j 0 -kb <keyboard_name>コンパイルの高速化出来ます。(0が最速)
docs.qmk.fm