Kermiteのファームウェアの作り方(Arduino 実践編)
この記事では、Arduinoを使ってKermiteのファームウェアを作る手順を解説しています。
前回の記事で、KermiteのArduino対応の概要について書きました。今回はその実践編になります。
英語での解説がgithubに置いているライブラリのreadmeにあり、これをベースにしています。内容を日本語に訳して詳しい使い方の情報を追加しました。
さあはじめよう
このチュートリアルでは、1つのキーを持つシンプルなキーボードのファームウェアを作ります。RP2040が載っているマイコンボードに対応しています。
キーマトリクスを扱うファームウェアの例と、Webアプリからキー配列を設定する方法についても解説を行っています。
ボードの準備
RPP2040が載ったボードを用意します。
以下のボードであれば、サンプルを簡単に試すことができます。
- Raspberry Pi Pico
- Adafruit KB2040
- Seeed XIAO RP2040
- RP2040 Zero
- Tiny2040
これら以外のボードでも、コード上でピンの設定を変更して動かすことができます。
ここでは以下のような、KB2040を使ったボードを準備しました。

タクトスイッチかキースイッチを1つ用意して、デジタル入出力に対応しているピンに接続します。ピン番号などはあとで設定するので、どのピンでも良いです。
Arduinoのインストールと起動
Arduino IDEをインストールします。以下のURLからインストーラを入手できます。
Arduinoを起動します。
ボードパッケージのセットアップ
RP2040が載っているボードで、Nano RP2040 ConnectなどのArduinoの公式以外のボードはデフォルトではサポートされていません。ボードパッケージを追加してこれらに対応します。RP2040の開発ではearlephilhower版と呼ばれるパッケージがよく使われていますが、ここではそれをフォークして調整を加えたものを使います。USBまわりの実装に手を入れています。
追加のボードURLの設定
メインメニューのFile > Preferencesから、設定パネルを開きます。

Additional board manager URLsの設定欄に、
https://github.com/kermite-org/arduino-pico/releases/download/global/package_rp2040_index.json
を追加します。
この設定で、カスタムボードパッケージのバージョンリストがArduinoに認識され、パッケージマネージャのUIからボードパッケージをインストールできるようになります。
ボードパッケージのインストール
左のナビゲーションバーから、ボードマネージャを開きます。

rp2040で検索して、Raspberry Pi Pico/RP2040 by Earle F.Philhower,IIIというパッケージを探します。バージョン指定のセレクタで、kermite-fork-*が末尾についているバージョンで、一番新しいものを選んでインストールします。
ライブラリのインストール
ArdruinoでKermiteのファームウェアを作るために、2つのライブラリを提供しています。
KermieCore_Arduinoはキー入力のロジックやUSB HIDデバイスなどを含むコアライブラリです。Webアプリとの通信やキーマッピングの管理などもこのライブラリが内部で行います。
keyboard_peripheral_modulesはキーボードのファームウェアを簡単に作るために、補助的に使用するライブラリです。これは使わなくてもKermiteのファームウェアを作れますが、ボード上のLEDやキーマトリクススキャンなどの制御に特にこだわりがなければ、このライブラリを使うとファームウェア実装が簡単になります。
サイドバーからライブラリマネージャを開きます。

kermiteで検索するとこれらのライブラリが見つかります。両方インストールします。

インストールボタンを押したときに、ライブラリが依存しているモジュールも一緒にインストールするかどうかを聞くモーダルが出ます。INSTALL ALLを選んで、依存モジュールもインストールします。
サンプルプログラムを開く
ライブラリに付属しているサンプルプログラムを動かしてみます。
メニューのFile > Examples > KermiteCore_Arduino > basicからサンプルのスケッチを開きます。
1つのキーによる入力とボード上のLEDの表示に対応した、簡単なキーボードのサンプルです。

ボードの選択
メニューのTools > Board > Raspberry PI Pico/RP2040から開発ターゲットのボードを選びます。
多くのRP2040対応のボードがありますが、もし手元のボードがリストにないときは、リストの一番下にあるGeneric RP2040というボードを選びます。Generic RP2040はどのボードでも使える、汎用的なボード定義となっています。

コードの編集
オンボードLEDの定義と入力ピンの設定を手元のボードに合わせて変更します。
オンボードLED
//select an appropriate boardLED initializer for your board
//BoardLED boardLED(25); //pico
//BoardLED boardLED(18, 19, 20, true); //tiny2040
BoardLED_NeoPixel boardLED(17, 0x40); //kb2040
//BoardLED_NeoPixel boardLED(12, 0x40, 11); //xiao rp2040
//BoardLED_NeoPixel boardLED(16, 0x40); //rp2040-zero
ボードにあうように、インスタンスの定義の行をコメントアウト/コメントインします。
BoardLEDとBoardLED_NeoPixelというクラスがあります。これらはボード上のLEDの制御をラップしたクラスで、共通のインターフェイスで扱うことができます。BoardLEDは3個までの普通のLEDを駆動することができます。BoardLED_NeoPixelでは1つのNeoPixel LEDをプログラム側から3個の個別のLEDとして点灯状態を指定できるようにします。
ここに定義があるボード以外を使いたいときは、以下のコンストラクタ定義を参考にして、コードを書き換えてください。
BoardLED(int pin0, int pin1 = -1, int pin2 = -1, bool sink = false);
BoardLED_NeoPixel(int pin, int brightness = 0xFF, int powerPin = -1);
コード上で、ピン番号はRP2040のGP0-GP31のポートに対応しています。D0,D1,D2...というピン番号が振ってあるボードがありますが、この番号ではありません。
入力ピン
const int pinButton = 6; //set an input pin for your board
ボタンに接続しているピンのピン番号を指定します。どのピンでも良いです。このピンは内部でプルアップされるので、外付けのプルアップは不要です。
書き込み (初回)
ボードにArduino以外のファームウェアを書き込んで使っていた場合、手動でリセットしてブートローダモードにしてから書き込みます。
ボードのBOOTボタン押しながらRESETボタンを押して、ブートローダモードにします。

ポートの選択で、UF2 Boardを選びます。

画面左上のUploadボタンを押してボードにファームウェアを書き込みます。
書き込み (2回目以降)
Arduino対応のファームウェアをボードに書き込むと、ボードをリセットするための仮想COMポートがPC側から見えるようになります。これを使ってソフトウェアリセットをかける仕組みがあり、2回目以降の書き込みでは手動でリセットしなくても書き込みができます。
ポートの選択で、ボードに対応する仮想COMポートを選びます。

画面左上のUploadボタンを押してボードにファームウェアを書き込みます。
動作の確認
プログラムの編集と書き込みがうまくできていれば、ボードは以下のような動作をします。
- ボード上のLEDが1秒に1回短く光ります。
- ボタンを押すとLEDが別の色で光ります。
この動作に問題がないかを確認してください。
(※)Raspberry Pi PicoではLEDが1つしかないためボタンを押してもLEDは光りません。
このあと、Webアプリからキーマッピングを書き込めば、ボタンを押したときにキーボードとして文字が出力されるようになります。
キーマトリクスの対応
キーマトリクスを扱うサンプルもここで紹介しておきます。
メニューのFile > Examples > KermiteCore_Arduino > key_matrixにサンプルスケッチがあります。

このサンプルでは、4x3のキーマトリクスを読み取ってコアライブラリにキー状態を送っています。
以下の個所で、縦横のキー数やピン番号を設定しています。利用する際にはここを書き換えてください。
//set numColumns, numRows, pinColumns, pinRows according to your board
const int numColumns = 4;
const int numRows = 3;
const int pinColumns[numColumns] = { 28, 27, 26, 22 };
const int pinRows[numRows] = { 6, 7, 8 };
Webアプリでの使い方
ここまでで作ったファームウェアにKermiteのWebアプリからキーマッピングを書き込んでキーボードとして使えるようにする手順を解説します。
(※)現在アプリ側では、Arduinoで書いた新しいファームウェアを使うことができますが、パッケージにファームウェアを含めて配布する方法などはまだ実装がありません。この手順では、手元で作ったファームウェアを書き込んだキーボードを自分用に運用できるようにするところまでを解説します。
設定の調整

設定画面で、Allow Cross Keyboard Writeにチェックを入れます。Arduinoで書いたファームウェアとプロジェクトとの紐づけの仕組みがまだないので、ここにチェックを入れてどのファームウェアにもキーマッピングを書き込めるようにします。
ウィザードの開始

スタート画面で、'外部ファームウェアプロジェクト'のウィザードを起動します。
デバイスの接続

プロジェクトの概要設定とデバイスの接続を行うステップが表示されます。
プロジェクト名を入力します。これはマイコンに書き込んだ表示名とは特に関連がなく、任意のものを設定できます。
'デバイスを追加'ボタンを押すとダイアログが出るので、リストからデバイスを選んで接続します。

'次へ'ボタンを押してステップを進めます。
レイアウトテンプレートの設定

生成されるキーレイアウトの設定をします。マトリクスの行列数や個別キーの数を入力します。
ここでデバイスのキーを押すと、画面上のキー表示がオレンジ色でハイライトされます。
画面上で、キーの左右の並びが実際のボードと異なる場合には、列を反転するオプションを適用します。
'完了'ボタンを押します。
キーマッピングの設定

プロファイルが作成され、メイン画面に遷移します。
左上のメニューで、'名前を付けて保存'を選んでプロファイルを保存しておきます。
各キーに文字を割り当てて、'書き込み'ボタンを押すと、キーマッピングがボードに書き込まれて、キーボードとして機能するようになります。
まとめ
おつかれさまでした。これで今回の解説をおわります。Arduinoの環境で自由にファームウェアを作ってみてください。今回は簡単なファームウェアが作れるようになった、というところまでの話でしたが、今後さらにいろんなことができるように機能開発を進めていきたいと思います。よろしくお願いします。
補足情報
開発時に参考になりそうな補足です。少し立ち入った内容になっているので、本文から切り離してここにまとめました。
ビルドオプション
Toolsメニューにはビルドオプションを設定する項目がいくつかありますが、Kermiteのファームウェアに関連するものが2つあり、ここではそれらについて補足しておきます。
今回使用しているarduino-picoをフォークしたバージョンではこれらのオプションがデフォルトで選択されるように調整しているので、特に変更しなくても適切な設定になっているはずです。オプションを変更する際には、以下の項目を確認してください。
フラッシュ領域のサイズの設定

コアライブラリでは、フラッシュ領域の一部をキーマッピングなどのデータを保存するために利用しています。この選択肢のリストでは、Sketchがプログラム領域のサイズ, FSがデータ領域のサイズを表しています。
Kermiteのファームウェアを作る際には(FS 64kB)のオプションを選んでください。現在の実装では保存データのサイズは4KBなので、(no FS)以外の他のオプションを選んでも動作します。(no FS)ではキーマッピングが保存されない動作になります。
キーマッピングのデータはFS領域の末尾4KBに格納されます。それより前の番地はプログラム上で他のデータを格納するのに利用しても構いません。
USB Stackの設定

USB StackではArduino TinyUSBを選んでください。Pico SDKのUSBスタックでも基本的な動作には対応していますが、一部の機能(実運用のために仮想シリアルポートを無効にする機能)が非対応となっています。
ProductionModeについて
実際にキーボードを運用する際に誤ったファームウェアの書き込みを防ぐため、ProductionModeという動作モードを追加しました。
Arduinoで作ったファームウェアでは、デフォルトで仮想シリアルポートが有効になっています。
Arduinoではこのポートを使ってMCUにソフトウェアリセットをかけることで、手動でリセットボタンを押さなくてもブートローダモードにすることができ、その後ビルドしたファームウェアを書き込む仕組みになっています。
複数のキーボードを開発する際に、ポートの選択を間違えてメインで使っているキーボードに誤ってファームウェアを書き込んでしまう可能性があります。動作モードをProductionModeに設定することで、これを回避することができます。
kermite.setProductionMode(); //追加
kermite.begin();
kermite.begin()の呼び出しの前に、kermite.setProductionMode()を呼ぶと、仮想シリアルポートが無効になり、自動リセットによるファームウェアの書き込みができないようになります。
ファームウェアの開発や調整が完了して実際に運用するときには、このモードを有効にしておくと良いでしょう。
Production ModeでArduinoからの書き込みが全くできなくなるかというとそうではなく、ボードのBOOTボタンとRESETボタンを押して手動でブートローダにすると通常通り書き込みができます。ファームウェアの実装を再調整する際には、この方法で書き込んでください。
Discussion