【自キ】自作キーボードを設計してみよう 7.ファームウェアの作成編【設計】
前回までで、キーボードそのものの組み立ては(ボトムプレートの取り付けを除き)完了していると思います。ですが、肝心な制御を司るファームウェアが存在しません。これが他の方が作った自作キーボードであれば、用意されているファームウェアをマイコンに書き込んで完成、ですが……自分が作ったこの世にひとつだけのキーボードには、ファームウェアが存在していません。
今回は、「とりあえず動くぞ」というファームウェアを作りたいと思います。具体的にはGitHubユーザーではなくても作れるやり方、という感じです。動くけれども間違った部分があるかもしれませんが、あらかじめご承知の上、お読みください。
長い、そして大変なので、ここで折れないように頑張りましょう!
※2022年11月4日時点の情報です。QMK MSYS、qmk firmwareのバージョンアップ等で変更される(本ブログ記載の方法では不可能になる、不具合が出る)可能性があります。
・ファームウェアとは
ファームウェアというのはキーボードを制御するために必要なプログラムです。キーを押した時に、たとえば『A』を打った際にPCに『A』を打ったという信号を送る等、このファームウェアがなければ出来ません。
自作キーボードのファームウェアはいくつか種類があるのですが、今回は『QMK Firmware』というもので作りたいと思います。
作るために必要なものは『QMK MSYS』とテキストエディタです。テキストエディタは派閥があるということなので、お好きなものをお使いください。(メモ帳ではなく、テキストエディタです)
なお、全ての手順はウィンドウズ環境での手順となります。筆者環境の都合上、ご容赦いただければ。
・QMK Firmware環境の構築
まずはQMK Firmwareを使えるようにしなければなりませんが、環境構築手順が頻繁に変わるのがQMK Firmwareの特徴の一つということなので、参考にした記事に倣ってここでは公式ドキュメントへのリンクを用意するに留めます。
頻繁に記事が修正できるのであれば、その時々の詳細な手順を書いておけば良いのですが……おそらくそれは無理なので、ここでは省略させていただきます。
参考にした記事:GL516 デザインガイド - QMK Firmwareを作成する
・GitHubの存在
自作キーボードについて興味を持ち、色々と眺めていると自作キーボード設計者の方々がリンクとして挙げている先の多くがGitHubであることに気が付くと思います。これはザックリ言ってしまうと「その方が都合が良いから」だと思いますが、プログラムに疎い人間からすると「よく分からない存在」ですよね?(あれ、私だけですか? そう感じるのは……)
GitHubはキーボードのデータ、プレートや基板のデータを置いていたりしますが、QMK Firmwareの通常の流れでオリジナルのキーボード用にファームウェアを作ろうとすると、GitHubのユーザーネームを聞かれます(2022年11月4日現在)。「そんなもの持ってないよ!」と思っても回避の仕方が分かりません……。ここで詰んでしまうのか? と諦めそうになりますが、正式ではないやり方であればどうにかなります。
・Keyboard Firmware Builderを利用する
少し調べた方であれば「あれ? それの使用は推奨できない(むしろ使うなレベル)って書いてあったぞ?」と思われるかと。その通りですが、使用を推奨できない理由はそれで作られたファームウェアのVENDOR ID、PRODUCT IDが同一のものとなってしまうから、ということのようです。なので、それがクリア出来れば(推奨するとは言えないが)多少の問題は解決しそうです。
その部分の問題を解決したものを堕落猫さんが公開されていましたので、それを使用します。(ただし、自己責任です。私も自己責任で使用します。)Keyboard Firmware Builderhttps://t.co/Q1gZRg0s31
— 堕落猫 (@daraku__neko) August 17, 2022
フォークしてよっぴさんの当ててVENDOR IDとPRODUCT IDを設定できる様にしたよ。
書かないと空が埋め込まれます。
hexは裏でなんか走らせないといけないのでソースだけダウンロードです。#自作キーボード
Keyboard Layout Editorで作成したRaw dataをインポートし、色々弄ります。WIRINGは配線についての項目ですが、自分で配線したものと異なるかもしれません。その場合は適宜いじってください(※ファームウェアを作ってから配線した方が効率的なのかもしれません、今更ですが。)。KEYMAPはそのままキーマップの項目ですが、日本語配列で作ろうとした場合、ここでは対応するキーが設定出来ないので『KC_NO』というキーが割り当てられます。そのまま無視しても構いません(後で修正可能)。他にもキーが微妙に違ったりすることがあるので、この場で修正できるものは修正しましょう。特に右シフトとかが左シフトになっているかと思います。(左右に振り分けられるキーはほとんど左として取り込まれていると思います)
SETTINGS項目にあるLayout Name、VENDOR ID、PRODUCT IDに記入し、自分用に変更します。VENDER ID等はUSB機器の認識に必要なもので、同じPCでこれらが一致している異なるふたつの機器を繋げた場合、支障が出ます(PC側が故障する可能性があるとのこと)。これらは正規の手段で取得すべきものとのことですが、それには法人格である必要があったり、申請に関わる費用が発生するようです。この辺りはなかなか私も理解が深まっていませんが、以下の参考文献によると既存IDとの重複を避けて使用する、という感じのようです。
https://www.caniusevia.com/docs/configuring_qmk#change-vendor_id-product_id
ただし、だから大丈夫ということも無さそうなので難しいところですね……。大量生産しないからこそ、でしょうか。(個人で使う、頒布目的無しで使う分には何かあっても自分が困るだけだと思います)
上記リンク先によれば、IDは8ビットASCII値で書くことがオススメとのことですが、何にせよ『0x』から始まる6桁にすることがルールのようです。私はリンク先の手法に合わせ、『Ainosuke Akutagawa』から『AA』とし、16進数で『4141』となるようなので『0x4141』とベンダーIDを決め、プロダクトIDも同じく決めていきます。今回は『Akutagawaの最初のキーボード』、ということで単純に『0xa001』としましたが、これはなるべく他のキーボードと被らないようにキーボード名をもじったものにする等、工夫した方が良いみたいです。
全て調整できたら、COMPILEタブからzipをダウンロードしましょう。zipの中にファームウェア作成のために必要なファイルが詰め込まれています。
・Keyboard Firmware Builderで作った各ファイルを微調整
Keyboard Firmware Builderで作ったファイルを確認し、調整します。特に配線関係に調整が必要だと思います。
解凍すると『qmk_firmware』というフォルダが出来ますが、その中の『kb』フォルダを自分のキーボード名(半角小文字英数)に変更します。私の場合はAct-JP52Sなので、『act_jp52s』と変更します(ハイフンは使えません)。
名前を変更したフォルダの中に色々ファイルがありますが、まずは『kb.c』と『kb.h』をそれぞれフォルダと同じネームに変更します。私の場合は『act_jp52s.c』と『act_jp52s.h』ですね。『.c』の方をテキストエディタで開いてもらうと
#include "kb.h"
と書かれていると思います。これを
#include "act_jp52s.h"
のように書き換えてください。
次に、『act_jp52s.h』のように書き換えたファイルを開き、キーマップの確認をします。『K000』のような表記でキーの配置を文字列で表していますが、これがちゃんとしているかを確認します。表記上のルールとしては『K◯◯◯』の3桁表記で、先頭が行、後ろ2桁が列を示しています。気を付けなければいけないのが、それぞれの先頭は『0』であるということ。プログラムとかやっていないと感覚的に『1』としたくなりますが、そうではないので注意が必要です。
似たような表記だけどちょっと違う文字列が並んでいますが、上が単純にキーを並べたもの、下がそれを位置も含めて表記したもの、という感じだと思います。下の文字列では上にはない、『KC_NO』があると思いますが、それはキーを行、列で揃えた時にキーが存在しない場所を示します。それらを踏まえておかしなところはないか確認し、修正が必要であれば修正します。私の場合、変則的な位置関係にしているせいか、Caps LockにあたるK100が単独になってしまい、Esc等がK001のようにひとつ右にずれてしまっていました。(Keyboard Firmware Builderで配線の仕方を一応いじれますが、今回は特に弄らなかったためにCaps Lockのみ別の列という扱いになっていました)
続いて、『config.h』を確認します。
#define VENDOR_ID 0x4141
#define PRODUCT_ID 0xa001
#define DEVICE_VER 0x0001
#define MANUFACTURER qmkbuilder
#define PRODUCT keyboard
#define DESCRIPTION Keyboard
上記のような表記があるところを探し、#define MANUFACTURERと#define PRODUCTを任意のものに書き換えます。私の場合は以下のような感じですね。
#define VENDOR_ID 0x4141
#define PRODUCT_ID 0xa001
#define DEVICE_VER 0x0001
#define MANUFACTURER Ainosuke_Akutagawa
#define PRODUCT act_jp52S
#define DESCRIPTION Keyboard
次に、
#define MATRIX_ROWS 4
#define MATRIX_COLS 15
のような記述があると思いますが、それを自分のキーボードの数値と同じか確認してください。作例だと4行14列なので、修正が必要ですね。(Keyboard Firmware Builderの段階でズレていたのは認識していましたが、15を14にすると書き出しが出来なかったので放置しました。ル、ルールがわからない……)
続いて、#define MATRIX_ROW_PINS、#define MATRIX_COL_PINSの確認、修正をします。
#define MATRIX_ROW_PINS { B0, B1, B2, B3 }
#define MATRIX_COL_PINS { B4, B5, B6, B7, C0, C1, C2, C3, C4, C5, C6, C7, D0, D1, D2 }
Keyboard Firmware Builderで自動的に割り当てられたピン(マイコン側の接続先)が入っているので、既にマイコンと接続している場合はそれに合わせて修正、これからマイコンと接続する場合にはこれに合わせるか、接続したいピンに変更します。筆者の場合は上の方で出た問題から有り得ない接続先が入っている(ピンが多い)ので、確実に修正が必要です。
#define MATRIX_ROW_PINS { D3, D2, D1, D0 }
#define MATRIX_COL_PINS { D4, C6, D7, E6, B4, B5, F4, F5, F6, F7, B1, B3, B2, B6 }
修正しました。
#define DEBOUNCING_DELAY 5
この表記は有効ではなくなったそうなので、
#define DEBOUNCE 5
に書き換えます。
#define DESCRIPTION Keyboard
/* prevent stuck modifiers */
#define PREVENT_STUCK_MODIFIERS
上記の記述も有効ではなくなったそうなのですが、代替記述は無いようなのでそのまま削除します。
今度は『keymaps』フォルダ内の『default』フォルダを開き、中にある『keymap.c』をテキストエディタで開きます。ズラッと色々書かれていると思いますが、
#include "kb.h"
を
#include QMK_KEYBOARD_H
#include "keymap_japanese.h"
に書き換えます。
KEYMAP(
KC_ESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_MINS, KC_CIRC, KC_BSPC,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_COLN, KC_LBRC, 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_RBRC, KC_RSFT,
KC_LCTL, KC_LGUI, KC_LALT, KC_NO, KC_SPC, KC_SPC, KC_NO, KC_NO, KC_RALT, KC_RCTL, MO(1)),
上記のような文字列がズラッと並んでいますが、これはひとかたまりでひとつのレイヤーとなっています。上から順に、レイヤー0、レイヤー1という感じですね。かなりの数のレイヤーが書かれていますが、仕様上4レイヤーが限界みたいなので、上から4つのレイヤーを残し、他は削除してください。削除の際は余計なものを(逆に言えば本来必要であるものを)消さないよう、注意してください。
また、ここで日本語配列の場合は対応したキーに書き換えておきます。おまじないとして、他の方々が
[0] = LAYOUT(
という表記を使用されているので、それに変えておきます(KEYMAPでも良さそうなのですが、比較してのエラー対処しやすさを考慮して、LAYOUTにしておきます。おまじない)。
さらに、私が作成中にMO(1)が上手いことエラーを回避できなかったので、KC_APPに変更します。(おまじない。たぶんどこかで問題を抱えていて、『)』の表記がエラーになっていたみたいです)
[0] = LAYOUT(
KC_ESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_MINS, KC_CIRC, KC_SPC,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_COLN, KC_LBRC, 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_RBRC, KC_RSFT,
KC_LCTL, KC_LGUI, KC_LALT, JP_MHEN, KC_SPC, KC_SPC, JP_HENK, JP_KANA, KC_RALT, KC_RCTL, KC_APP),
[1] = LAYOUT(RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______) ,
[3] = LAYOUT(RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______)
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) {keyevent_t event = record->event;switch (id) {}return MACRO_NONE;}void matrix_init_user(void) {}void matrix_scan_user(void) {}bool process_record_user(uint16_t keycode, keyrecord_t *record) {return true;}void led_set_user(uint8_t usb_led) {if (usb_led & (1 << USB_LED_NUM_LOCK)) {} else {}if (usb_led & (1 << USB_LED_CAPS_LOCK)) {} else {}if (usb_led & (1 << USB_LED_SCROLL_LOCK)) {} else {}if (usb_led & (1 << USB_LED_COMPOSE)) {} else {}if (usb_led & (1 << USB_LED_KANA)) {} else {}}
上記の記述はLED周りの記述のようですが、作例のようなLEDを使わない場合は必要ないみたいなので削除してください。(たぶん大丈夫)
ファイルの書き直しは以上ですが、ここからRemapでキーマップが変更できるように『VIA』に対応していきます。『default』フォルダ内に、新規作成で『rules.mk』というドキュメントを作成し、
VIA_ENABLE = yes
とだけ記述しておきます。これでVIAへの対応が可能になり、Remapでキーマップ変更が可能になります。……が、キーレイアウトを認識させるために、Keyboard Layout Editorで対応するキーレイアウトを作成する必要があります。
作例ですと上の画像のようになります。参考文献にも書いてありますが、注意点としては『0,0』であって『0.0』ではないことです。『0,0』からスタートして行毎に数字を振っていき、行が変われば『1,0』から『1,1』……のように、数字を振っていきます。分割キーボードの場合はまた別途注意点がありますので、参考文献を確認してください。ここでは割愛します。
完成したら、jsonファイルをダウンロード、もしくはRaw dataタグの数値をテキストエディタにコピー&ペーストしてください。
上記参考文献の『VIAに読み込ませるjsonファイルを作成する』を参考に、jsonファイルを作ります。サンプルのフォーマットをベースに自分のキーボード用に仕上げましょう。その際に上の作業で作ったレイアウトのデータを使います。参考文献をよく読んでおけば特に難しい作業ではないので、焦らずしっかりと読んで作業しましょう。
vendorId、productIdは『config.h』に記述されている、自分で決めたものを入れておきます。lightingは光るかどうかということなので、LED非搭載であれば『none』と記述しておきます。(ここまでとりあえず作例に沿ってやってきた方だとおそらく『none』になるかと思いますが)
・QMK MSYSでファームウェアを書き出す
調整したフォルダを上記『QMK Firmware環境の構築』で作成された『qmk_firmware』フォルダに格納します。『qmk_firmware』配下の『keyboards』フォルダにリネームした元『kb』フォルダ(作例では『act_jp52S』フォルダ)をコピーして貼り付けます。
格納した後、QMK MSYSを起動します。起動後、
cd qmk_firmware
を実行し、移動。さらに、
make your_keyboard:default
を実行してください。your_keyboardの部分はフォルダ名に合わせて変更してください(作例では『make act_jp52s:default』になります)。
エラーがなければ、
Copying act_jp52_default.hex to qmk_firmware folder [OK]
Checking file size of act_jp52_default.hex [OK]
* The firmware size is fine - 13928/28672 (48%, 14744 bytes free)
のような表示が出ます。そうしたらファームウェアがとりあえずの完成です。qmk firmwareのフォルダに自分のキーボードの名前が付いたhexファイルがあると思います。それが自分だけのオリジナルキーボードのファームウェアです。
・ファームウェアをProMicroに焼く
出来上がったhexファイルをProMicroに焼きます。Remapの『KEYBOARD CATALOG』右上にある『FLASH firmware』、またはPro Micro Web Updaterでファームウェアを焼きましょう。
注意点は、焼く際にProMicroのリセットが必要なのですが、種類によってはリセット1回か、連続でリセット2回等違いがあるので1回で駄目なら2回、みたいな感じでやってみてください。作例ではリセットボタン(スイッチ)を搭載していないので、ProMicroの『RST』と『VCC』をピンセット等でショートさせてください。リセット2回の場合はちょん、ちょんと触れてやればいけると思いますが、タイミングがずれると認識してくれなかったりするので落ち着いて、根気よくやりましょう。
ファームウェアの焼き方については下記の参考文献を私も参考にして行いました。
参考文献:(初心者編)自作キーボードにファームウェアを書き込む
正常に終了すれば、とりあえずキーボードとして機能するようになった筈です。
・Remapでキーマップを調整する
ファームウェアが焼けたら、Remapでキーマップを調整しましょう。『START REMAP YOUR KEYBORAD』をクリックすると、『+KEYBOARD』という項目が表示されますので、それをクリックします。デバイスの接続を要求されるので、自分のキーボードを選択し、接続します。
Remapに登録されているキーボードであればそのままキーマップ編集画面へ遷移しますが、貴方が作ったオリジナルキーボードは登録されていません。jsonファイルを求められるので、Remapにアップロードします。ここで求められているのはKeyboard Layout Editorで作成したものではなく、参考文献の『VIAに読み込ませるjsonファイルを作成する』を参考に作ったjsonファイルです。これをIMPORTをクリックしてファイル選択、アップロードするとキーマップ編集画面に遷移します。
開いた当初は英語配列の画面なので、日本語配列で製作した場合はキーコードの違いから違うキーが表示されていたりします。『English(US)』と表示されている部分をクリックし、『Japanese』を選択しましょう。これで日本語配列に適したキーが表示されるはずです。
ここからは、お好きなようにキーマップをカスタマイズしてください。レイアウトの段階では「こうしよう!」と思っていたけれども、ファームウェア作成中の制約(私の場合はMO(1)がエラーに繋がっていたので別のキーに置き換えた等)で異なる場合は、ここで思う存分、自分のための、最適なキーマップを追求してください。
なお、Remapに登録されていないキーボードは接続の度にjsonファイルを求められます。頒布予定がある等、度々求められるのは煩わしいという場合はRemapへの登録をされると良いでしょう。ご自身がそのキーボードの製作者(権利者)であることを示す必要があるとのことですが、それに問題が無ければ登録してらえるみたいですね。GitHubのアカウントが必要になるようなので(ファイルの確認等もGitHub経由なんですかね?)、Remap対応して頒布するぞ! ということでしたらGitHubを活用する必要がありますね。
※VENDOR ID、PRODUCT ID問題は忘れないようにし、対応しておきましょう。
・おわりに
正直なところ、この項目は不完全だと思います。そして、時間が経てば経つほど、それは顕著になるでしょう。改善、進化し続けているものを解説するというのは理解力と対応力の高さが必要ですが、私では足りていない気がします(気がするというか、それが事実だと思いますが)。
ファームウェアの作成の仕方含め、今後はもっと効率的で安全性の高いやり方が提示されるかもしれませんが、「とりあえずこういうものなのか」という部分をさらっとでも感じ取っていただければ、書いた意味があるかもしれません。
参考文献に挙げたサリチル酸さんのブログ、『自作キーボード温泉街の歩き方』は他にも参考になるものがあると思いますので、是非目を通してください!
(まあ、私のブログなんていう、こんな底辺から入る人はいないと思うので通過済みだろうとは思いますが……)
ついに完成した、この世に(たぶん)ひとつだけの貴方のキーボード。この企画の最後として『8.マイキーボードを使い倒し、そして自慢しよう編』をお送りいたします。
コメント
コメントを投稿