分割⇔一体型40%キーボード「Maglit40」~QMKファームウェア編~

0.はじめに

私が自作した40%キーボード「Maglit40」のQMKファームウェアに関する私の設定情報を思いつくまま書き散らし、どこかの誰かのお役に立てばいいなという記事です。
私もたくさんの公開いただいている情報を参考にしてMaglit40をつくりました。拙い設計ですがご参考になれば幸いです。

1.Maglit40って?

こちらから一連のツイートをご参照のこと。

2.Maglit40の構成

Maglit40で使用している部品や一部の基板の配線について記載します。

  1. MCU Seeed Studio XIAO RP2040×2
    ピン配置はこのようにしています。分割キーボードにおける左右の判定用にGP3にVCCまたはGNDを接続しています。
    Maglit40では回路図でGP0ピンを使わず、フットプリントから削除することで、ホットスワップソケットと干渉なく取り付けることができるようにしてみました。
  2. マトリックス 総当たりマトリックス
  3. 左右間接続はTRRSケーブルと磁気ポゴピンによる2つ
    いずれもシリアル通信で、一般的なTRRSジャックを搭載した分割キーボードと同じシンボルで作成しました。

    磁気ポゴピン用のフットプリントは自作したのですが、並びを意識していなかったため「VCC,GND,SERIALの並び順が異なる」というミスをしました。その際フットプリントを変えずに回路図の並びで対応したので、青い注意書きを書いてます。磁気ポゴピンのフットプリントこんな感じです。
  4. LED SK6812MINI-E×2(左右1)
    LED動作保証外の直結型です。今のところ問題なく動作していますが動かなくても自己責任です。

    LEDに関する記事はこちらを参照させていただきました。

    25keys.com

    zenn.dev

3.QMKについて

2023年6月時点でのQMKの最新バージョンは0.21.0ですが、Maglit40は私がREAMPで使用したいため0.18.17で作成しました。

このためQMKの開発環境を0.18.17にする必要があります。古い環境を構築するには、qmk_firmwaregithubリポジトリのTagを0.18.17に指定しcloneする…という手順で行う必要があります。Tagを指定してダウンロードし、解凍した環境ではエラーとなります。

4.キーボードの作成

QMK MSYSを起動し、qmk new-keyboardで新しくキーボードを作成します。gachihamさんの記事に詳しく手順があり参考にさせていただきました。

gachiham.hatenablog.com

5.info.jsonについて

info.jsonへ必要な項目の設定を記述していきます。まずQMKドキュメントはこの2つを参照することになると思います。

github.com

github.com

matrix_pins

総当たりマトリックスの場合、"matrix_pins"は同じ値が入ります。左手側の回路図に合わせて記述していきます。

    "matrix_pins": {
        "cols": ["GP27", "GP28", "GP29", "GP6", "GP7", "GP4"],
        "rows": ["GP27", "GP28", "GP29", "GP6", "GP7", "GP4"]
    },
layouts

キーボードのレイアウトに合わせて、左から右、上から下へ{ "matrix": [0, 1], "x": 0, "y": 0 },の形式で記述していきます。

私はKeyboard Layout Editor レイアウトのレジェンドをpinに合わせて修正したものを見ながら作りました。Raw dataをもとにQMK Firmware - Convert KLE to QMK info.jsonで変換した方が分かりやすいかもしれません。

            "layout": [
                { "matrix": [0, 1], "x": 0, "y": 0 },
                { "matrix": [0, 2], "x": 1, "y": 0 },
                { "matrix": [0, 3], "x": 2, "y": 0 },
                { "matrix": [0, 4], "x": 3, "y": 0 },
                { "matrix": [0, 5], "x": 4, "y": 0 },
                { "matrix": [1, 0], "x": 5, "y": 0 },
                { "matrix": [6, 1], "x": 6.5, "y": 0 },
                { "matrix": [6, 2], "x": 7.5, "y": 0 },
                { "matrix": [6, 3], "x": 8.5, "y": 0 },
                { "matrix": [6, 4], "x": 9.5, "y": 0 },
                { "matrix": [7, 0], "x": 10.5, "y": 0 },
                { "matrix": [7, 2], "w": 1.5, "x": 11.5, "y": 0 },
                { "matrix": [1, 2], "x": 0.25, "y": 1 },
(以下、省略)

左手で折り返すのではなく、右手まで1行終えてから折り返します。

split

分割キーボードの"enabled"をtrueにし、右手のピンを指定します。また左右通信用のシリアルピンを指定し、通信プロトコル指定します。

    "split": {
        "enabled": true,
        "matrix_pins": {
            "right":{
                "cols": ["GP27", "GP28", "GP29", "GP6", "GP7"],
                "rows": ["GP27", "GP28", "GP29", "GP6", "GP7"]
            }
        },
        "soft_serial_pin":"GP1",
        "transport":{
            "protocol":"serial"
        }
    },
rgblight

通常のLEDの指定の他、分割の指定もします。Maglit40の場合はLEDの役割としてアニメーションさせたいのではなく、CAPSLOCKやレイヤーのインジケータが目的のため、アニメーションは一つだけにしています。blinkなどはお好みで実装に合わせて。

    "rgblight": {
        "led_count": 2,
        "pin": "GP26",
        "animations":{
            "rainbow_mood": true
        },
        "sleep": true,
        "max_brightness": 128,
        "hue_steps": 8,
        "saturation_steps": 8,
        "layers": {
            "blink": true,
            "enabled": true,
            "override_rgb": true
        },
        "split": true,
        "split_count": [1,1]
    },
 
buildとdebounce

XIAO RP2040×総当たりマトリックス×分割キーボードの組み合わせの場合、デフォルトのままだとチャタリングが発生し同一文字が連続で入力されました。その解決策として、チャタリングをソフト的に解消しよう - 25KEYS を参考にさせていただき、”debounce_type"をsym_eager_pkへ変更し、時間を延ばすことで対策しています。

    "build": {
        "debounce_type":"sym_eager_pk"
    },
    "debounce": 75,
permissive_hold

Maglit40は40%キーボードなので「単押しでtab、長押しでctrl」などのdual-role keyがいくつかありますが、高速で指を動かしたときにdual-role keyの誤打を避けるように設定しています。これはお好み項目です。

    "permissive_hold":true,

docs.qmk.fm

caps_word

起動すると「単語」にCAPSLOCKが働かせることができる機能です。左右シフトキーの同時押し(片方はdual-role keyでも可)やシフトキーの2連打、キーコード割り当てで起動させることができます。これもお好み項目ですがあると意外に便利です。

    "caps_word":{
        "enabled":true,
        "both_shifts_turns_on":true,
        "double_tap_shift_turns_on":true,
        "idle_timeout":5000
    }

docs.qmk.fm

6.config.hについて

info.jsonに記述できない設定を追加します。

MATRIX_MASKED

RP2040×総当たりマトリックスの場合、交点にダイオードを追加したことによって交点のキーが押されていることがファームウェアに通知される状態になるため、PCへの接続時に不具合が生じます。これを回避するために設定します。

先に出てきたgachihamさんのブログを参考に設定しました。

gachiham.hatenablog.com

maglit.cファイルを新規作成し、以下の記述を行います。分割キーボードなので6×2の12行設定を入れています。

#include QMK_KEYBOARD_H

const matrix_row_t matrix_mask[MATRIX_ROWS] = {
    0b11111110,
    0b11111101,
    0b11111011,
    0b11110111,
    0b11101111,
    0b11011111,
    0b11111110,
    0b11111101,
    0b11111011,
    0b11110111,
    0b11101111,
    0b11011111
};
BOOTMAGIC_LITE_ROW/COLUMN

BOOTMAGIC_LITEが有効の場合、特定のキー押下しながらUSB接続をすることでBOOTモードになりますが、デフォルトだとキーは0,0となるため変更します。接続したときに左上のキーを指定しています。

#define BOOTMAGIC_LITE_ROW 0
#define BOOTMAGIC_LITE_COLUMN 1
#define BOOTMAGIC_LITE_ROW_RIGHT 6
#define BOOTMAGIC_LITE_COLUMN_RIGHT 1
SPLIT_HAND_PIN

左右接続を自動判定するためのピンを指定します。あらかじめ基板側でピンにVCCまたはGNDを繋いでおく必要があります。VCC接続を左とするか右とするかのオプションもあります。

#define SPLIT_HAND_PIN GP3
SPLIT_USB_TIMEOUT/SPLIT_MAX_CONNECTION_ERRORS

RP2040×分割キーボードではPCのコールドスリープから復帰時に、キーボードが正常に起動しない不具合があります。その解決策として、SPLIT_USB_TIMEOUTを延ばしてあげるか、USB_VBUS_PINを指定します。詳しくは下記の記事をご参考に。

www.eisbahn.jp

yyoshisaur.hatenablog.com

Maglit40の場合、ピン数の都合からyyoshisaurさんの基板側での対応ができなかったのでSPLIT_USB_TIMEOUTを延ばしています。SPLIT_MAX_CONNECTION_ERRORS は何かの拍子に入れたのですが理由は忘れちゃいました。無くてもいいかもしれません。

//#define USB_VBUS_PIN GP3
#define SPLIT_USB_TIMEOUT 5000
#define SPLIT_USB_TIMEOUT_POLL 25
#define SPLIT_MAX_CONNECTION_ERRORS 10

7.rules.mkについて

LEDを動作させるためWS2812_DRIVER、分割キーボードのシリアル通信を動作させるためにSERIAL_DRIVERを記述します。
WS2812_DRIVER = vendor
SERIAL_DRIVER = vendor

8.keymapsについて

キーマップ自体はお好みなので説明しないですが、Maglit40の場合keymap.cにLED制御などを記述しているためその内容を記載していきます。なお、QMKの本体へのマージリクエストはしたことがないため、正しい場所に記載できているかどうかなどはわかりません。

レイヤーインジケータの色を設定する

レイヤーごとにLEDを点灯させる設定です。

Maglit40の場合、RGBアニメーションを「オフ」にして「インジケータ」としてだけ使用することを前提の記述となっています。この前提における多くの場合の問題は、アニメーションをオフにしてもレイヤーインジケータの色が残ってしまうということです。その対策のためにHSV_OFFのレイヤーを定義したり、起動時に(0, 0, 0)をsethsvしたりと工夫した記憶があります。(今見返すと不要な処理もありそうですが…)

// RGBLayer setting
const rgblight_segment_t PROGMEM my_layer1_layer = RGBLIGHT_LAYER_SEGMENTS({1, 1, HSV_RED});
const rgblight_segment_t PROGMEM my_layer2_layer = RGBLIGHT_LAYER_SEGMENTS({1, 1, HSV_BLUE});
const rgblight_segment_t PROGMEM my_layer3_layer = RGBLIGHT_LAYER_SEGMENTS({1, 1, HSV_GREEN});
const rgblight_segment_t PROGMEM my_layerCL_layer = RGBLIGHT_LAYER_SEGMENTS({0, 1, HSV_YELLOW});
const rgblight_segment_t PROGMEM my_layerNL_layer = RGBLIGHT_LAYER_SEGMENTS({0, 1, HSV_MAGENTA});
const rgblight_segment_t PROGMEM my_layerIOFF_layer = RGBLIGHT_LAYER_SEGMENTS({0, 1, HSV_OFF});
const rgblight_segment_t PROGMEM my_layerLOFF_layer = RGBLIGHT_LAYER_SEGMENTS({1, 1, HSV_OFF});

const rgblight_segment_t * const PROGMEM my_rgb_layers = RGBLIGHT_LAYERS_LIST(
    my_layerNL_layer,
    my_layerCL_layer,
    my_layer3_layer,
    my_layer2_layer,
    my_layer1_layer,
    my_layerIOFF_layer,
    my_layerLOFF_layer
);

void keyboard_post_init_user(void) {
    rgblight_layers = my_rgb_layers;
    rgblight_sethsv_noeeprom(0, 0, 0);
};

// LayerIndicator
layer_state_t layer_state_set_user(layer_state_t state) {
    rgblight_set_layer_state(6, layer_state_cmp(state, 0));
    rgblight_set_layer_state(4, layer_state_cmp(state, 1));
    rgblight_set_layer_state(3, layer_state_cmp(state, 2));
    rgblight_set_layer_state(2, layer_state_cmp(state, 3));

    return state;
};
CAPS_WORDの色を設定する
CAPSロック状態では左手側のインジケータだけ黄色に点灯させています。
//CAPS WORD
void caps_word_set_user(bool active) {
    if (active) {
        rgblight_sethsv_range(HSV_YELLOW, 0, 1);
    } else {
        rgblight_sethsv_range(HSV_OFF, 0, 1);
    }
}

9.VIA/REMAP対応について

keymaps/[キーマップ名]/rules.mkを作成し、VIA_ENABLEを記述します。
VIA_ENABLE = yes
VIAやREMAPへ読み込ませるためのjsonファイルを記述します。Maglit40では、”matrix"のところは分割キーボードのためrowは12となります。
"keymap"は、Keyboard Layout Editor のRaw dataを置換して設定しています。
置換は、正規表現を有効にして、検索対象に ([xcnywdth]): 、置換する文字に "$1": を入れて変換しています。
{
    "name": "Maglit40",
    "vendorId": "dammy",
    "productId": "dammy",
    "matrix": { "rows": 12, "cols":6  },
    "lighting": "qmk_rgblight",
    "layouts": {
        "keymap":
        [
          [{"c":"#c73a64"},"0,1",{"c":"#a3a6b5"},"0,2","0,3","0,4","0,5","1,0",{"x":0.5},"6,1","6,2","6,3","6,4","7,0",{"c":"#20204a","t":"#ffffff","w":1.5},"7,2"],
          [{"x":0.25},"1,2",{"c":"#a3a6b5","t":"#000000"},"1,3","1,4","1,5","2,0","2,1",{"x":0.5},"7,3","7,4","8,0","8,1","8,3",{"c":"#20204a","t":"#ffffff","w":1.25},"8,4"],
          [{"w":1.75},"2,3",{"c":"#a3a6b5","t":"#000000"},"2,4","2,5","3,0","3,1","3,2",{"x":0.5},"9,0","9,1","9,2","9,4",{"c":"#20204a","t":"#ffffff","w":1.5},"10,0"],
          [{"x":1.25},"3,4",{"w":1.25},"3,5",{"c":"#a3a6b5","t":"#000000","w":2},"4,0",{"c":"#20204a","t":"#ffffff","w":1.5},"4,1",{"x":0.5,"c":"#a3a6b5","t":"#000000","w":1.75},"10,1",{"c":"#20204a","t":"#ffffff","w":1.25},"10,2","10,3"]
        ]
      }
}

10.コンパイル

ついでにコンパイル方法も。QMK MSYSを起動し、qmk_firmwareのホームディレクトリに移動後、qmk compile -kb [keyboard名] -km [キーマップ名]でコンパイルします。

RP2040の場合、コンパイル後に出力さる.uf2ファイルを使用します。XIAO RP2040をブートモードにし、表示されたフォルダへ.uf2ファイルをコピーして読み込ませます。

おわりに

以上、Maglit40のQMKファームウェア編でした。こうして書き出すとなかなかのボリュームになりますね。推敲せずに書き散らしているので見にくい、分かりにくいところも多々あると思いますがご容赦ください。
この記事が誰かの役に立つことを願って。

Maglit40