QMK FirmwareをDockerでビルドする


🐶 はじめに

初めての自作キーボードとして Helix を買った。
で、こういう自作キーボードは QMK Firmware というファームウェアによってキーマップを自由にカスタマイズできるらしいのでやってみた。

QMK Firmware は自分でビルドする必要があり、ビルド用環境も構築する必要があるため、記事に残しておく。

環境
Windows10 Pro
Docker for Windows 2.3.0.2
PowerShell 7.0.1
git 2.27.0.windows.1
QMK Firmware 0.9.44
QMK Toolbox 0.0.18
キーボード Helix

🏗 QMK 環境の構築

Windows でローカル開発環境を構築する苦行をしたくないので Docker を使う。
Docker イメージとして、必要なライブラリやソースがインストールされている qmkfm/qmk_firmware イメージを使う1

qmkfm/qmk_firmware リポジトリから Partial Clone

Git リポジトリが巨大なせいでそのままクローンすると動作が鈍くなる。
そのため、カスタマイズするキーボードのディレクトリに限定してクローンする。

  1. git ローカルリポジトリを作成・初期化
  2. Sparse checkout 機能を有効化
  3. カスタマイズするキーボードのディレクトリパスのみを指定
  4. リモートリポジトリ( fork 推奨)を設定してソース取得
  5. 新しくブランチを作成して切り替え
  6. 既存のキーマップをコピー
部分的なクローン
mkdir qmk_firmware
cd qmk_firmware
git init

git sparse-checkout init --cone
git sparse-checkout add keyboards/helix/

git remote add origin https://github.com/qmk/qmk_firmware.git
git pull --no-rebase --depth=1 origin master

git switch -c custom-helix
cp -r keyboards/helix/rev2/keymaps/default keyboards/helix/rev2/keymaps/custom

あとはコピーしたキーマップディレクトリ内で QMK Configurator から出力した JSON ファイルを追加したり keymap.c ファイルを編集したりする。

Docker for Windows ファイル共有設定

Docker コンテナにマウントするディレクトリを共有できるように設定する。

Settings -> Resources -> File sharing
を開いて共有したいディレクトリルートを指定する。

以前はボリュームディスク単位でしか設定できなかったけど、今回調べたらディレクトリ単位で指定できるようになってた。
使い勝手が良くなって嬉しい。

⌨️ キーマップの作成

keymap.c を直接編集する方法だと分かりにくいので、Web ツール QMK Configurator を使って作成した。

本来はそのままコンパイルもできるらしいが、Helix の場合は 7/23 現在問題があってエラーとなる。
ので自分でコンパイルして hex ファイルを生成する必要がある。

🚀 コンパイル

以下のようなコンテナ設定やコマンドを記述した docker-compose.yaml を作成して使った。

environment 設定の EXPORTED, KEYBOARD, KEYMAP は各環境によって修正する。
もしくは docker-compose run 実行時に -e KEY=VALUE オプションで上書きする。

/docker-compose.yaml
version: "3.8"
services:
  # JSON to C
  json2c:
    image: qmkfm/qmk_firmware
    working_dir: /qmk_firmware
    volumes:
      - ./keyboards:/qmk_firmware/keyboards
    environment:
      # Absolute path of the keymap json from QMK Configurator
      EXPORTED: /qmk_firmware/keyboards/helix/rev2/keymaps/custom/export.json
      # QMK Command: qmk json2c [-o OUTPUT] JSON_FILE
      command: /bin/bash -c 'qmk json2c $$EXPORTED > $$(dirname $$EXPORTED)/keymaps_var.c'

  # Compile keymap.c to hex file
  compile:
    image: qmkfm/qmk_firmware
    working_dir: /qmk_firmware
    volumes:
      - ./keyboards:/qmk_firmware/keyboards
      - ./.build:/qmk_firmware/.build
    environment:
      KEYBOARD: helix
      KEYMAP: custom
    # QMK Command: qmk compile -kb KEYBOARD -km KEYMAP
    command: /bin/bash -c 'qmk compile -kb $$KEYBOARD -km $$KEYMAP'

JSON to C

QMK Configurator からエクスポートした JSON ファイルを、 .c ファイル(今回は keymaps_var.c)へと変換する。

JSONキーマップファイルを.cファイルへ変換
docker-compose run --rm json2c

変換した .c ファイルではキーマップ配列 keymaps が定義されている。

keymap.c のカスタマイズ

QMK Configurator で作成したキーマップレイアウトを使うように修正する。

上記で作成された .c ファイル内に記述されている配列 keymaps を、keymap.c の配列 keymaps にコピペで上書きすればいい。

keyboards/helix/rev2/keymaps/keymap.c
...

#if MATRIX_ROWS == 10 // HELIX_ROWS == 5
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    // ここにコピペで上書き
};

...

Helix が 4 行版の場合は #elif MATRIX_ROWS == 8 // HELIX_ROWS == 4 行の下を上書き。

他設定

rules.mk ファイルの設定を編集することで LED や OLED ディスプレイを有効化/無効化できる。

コンパイル実行

keymap.c ファイルの修正後、コンパイルする。

コンパイル実行
docker-compose run --rm compile

下記のように .hex ファイルが既定サイズ内で生成できれば成功。
.hex ファイルは .build/ に出力される。

コンパイル成功例
Linking: .build/KEYBOARD_KEYMAP.elf                            [OK]
Creating load file for flashing: .build/KEYBOARD_KEYMAP.hex    [OK]
Copying KEYBOARD_KEYMAP.hex to qmk_firmware folder             [OK]
Checking file size of KEYBOARD_KEYMAP.hex                      [OK]
 * The firmware size is fine - 18036/28672 (62%, 10636 bytes free)

📝 ファームウェア書き込み

コンパイルされた .hex ファイルを Helix に書き込む。

QMK Toolbox

ファームウェア書き込みツール QMK Toolbox をインストールする。
Windows なら qmk_toolbox.exe をダウンロードすればいい。

qmk_toolbox.exeダウンロード
curl -LO https://github.com/qmk/qmk_toolbox/releases/download/0.0.18/qmk_toolbox.exe

書き込み作業

  1. Helix キーボードを接続

  2. qmk_toolbox.exe を管理者権限で起動

  3. コンパイルした .hex ファイルを指定

  4. MCUatmega32u4 になっていることを確認

  5. Auto-Flash にチェック

    リセットボタン押下後のタイミングが割とシビアなので、ここにチェックしておくと楽。

  6. Helix キーボードのリセットボタンを押下

    Auto-Flash にチェックしていれば自動的に書き込みが開始。
    エラーが起きたり起きなかったりするので、何回か試してください。

  7. 下画像のように flash verified メッセージが出れば OK


以上でカスタムキーマップをキーボードに適用できた。

🐾 おわりに

QMK Configurator や Docker を有効活用して楽しようとしたら、逆に余計な時間がかかってぴえん 🥺。
まあ、キーマップをあれこれ考えてる時間に比べたら誤差みたいなものだったけど。

Docker を使えば環境によるコンパイル失敗とかがなくなるのでいいですよね!
(今回のDockerイメージは2GB近いサイズでビビりますが)
(リポジトリクローン&サブモジュール取得すると1GB強になるので仕方ないかなって)

🛠 トラブルシューティング

json2c で [Errno 18] Invalid cross-device link: ... -> '~~.c.bak'

リポジトリのルートディレクトリに .bak ファイルが作れない、とかだと思う……。
これは docker-compose でルートディレクトリをマウントしていないと発生した。

回避策として qmk json2c 実行時に -o オプションは使わず、リダイレクトで出力するように変更した(上述の docker-compose.yaml は修正済み)。

コンパイルエラーしたキャッシュ削除したい

make clean の実体が rm -rf .build なので .build/ を削除すればいい。

キャッシュ削除
Remove-Item -Recurse .build

error: macro "LAYOUT" requires 64 arguments

QMK Configurator でレイヤー番号を飛ばして定義しているとなる。
キーマップが N/A (KC_NO) のみだと空配列が出力されるため、必要とする配列要素が足りずにエラーとなっている。

適当なキーを 1 文字定義したり、レイヤーを飛ばさないようにする。

QMK Toolbox で書き込みエラー

QMK Toolbox でファームウェア書き込み時にエラー。

qmk_toolbox.exeでエラー
Connecting to programmer: .avrdude.exe: ser_drain(): read error: スレッドの終了またはアプリケーションの要求によって、I/O 処理は中止されました。

avrdude.exe: ser_send(): write error: sorry no info avail
avrdude.exe: ser_recv(): read error: デバイスがコマンドを認識できません。
...

これは QMK Toolbox を管理者権限で起動したところ、無事成功した。
……と思ったけど管理者権限でも再発した。

何度も再試行してたら突然成功したので、なんかタイミングがあるっぽい。
何度かやり直したり QMK Toolbox を起動し直したり、ちょっと時間をおいてみたりするしかない?

Windows で英語配列にすると半角全角/変換/無変換キーが使えない

US 配列に存在しないキーは無視される仕様 🥺。

代替として、Ctrl + Space で IME を ON/OFF するようにした。
F13 以降の未割当ファンクションキーを割り当てて使う方法もある。

参考


  1. なお、クローンした Git リポジトリから Docker イメージをビルドする方法もある(というかドキュメントではこちらの方法が記述されている)。