REVIVE USB/MICRO開発 ソースコード改造のすゝめ
REVIVE USBシリーズはOSSライセンスのもと、かなり自由に改変が可能です。
私もREVIVE USBとREVIVE USB MICROのチャタリング対策&ロータリーエンコーダ対応版のファームウェアなどを公開しています。
先日、ビット・トレード・ワン社にREVIVE USB MICROに関するプレスリリースが掲載されました。
上記は私が公開していたファームウェアをマージし、公式側でさらに強化したものです。
この件に関しては発売元であるビット・トレード・ワン社から事前にご連絡をいただいております。
無印REVIVE USBになりますが、実際にこれらの機能をフル活用した作例が以下です。
MICROでも全く同じものを作れます。
元々は趣味で開発・公開していたものでしたが、使用している方が多く、チャタリング対策やロータリーエンコーダの対応という機能は私が思っていた以上に需要がありました。
今回はこれらの機能を公式に取り入れることで、有志による提供という形から昇華しています。
私のリポジトリで公開していたものはそのままにし、基本的にはアップデートを行わない方針です。
しかしせっかく調査して開発したものなので、REVIVE USBおよびMICROのプログラムに関して資料を残しておこうというのがこの記事の趣旨になります。
私について
JavaScript/Java/PHP/Python等、Web系を中心としたシステムエンジニアです。
(最近はゲーム開発しているのでUnityやってます)
REVIVE USBのファームウェアを制作した当時は学生で、マイコンに触れた経験がありませんでした。
情報系専門学校に通っていましたが、ハードウェアに近しい部分はほぼ学ばなかったので独学です。
(電子工学の知識はほぼありませんし、C言語もちょっと勉強した程度です)
制作当時は基本/応用情報技術者を保持していました。
基本情報技術者の午後の言語選択でCASL IIというアセンブラ言語を選択して合格し、応用情報技術者の午後の選択では組込みシステム開発を選んで合格しているため、一応ながら作る上での表面的な知識はありました。
開発において、座学と実践は天と地ほど違います。
当時の私はマイコンとかPICって具体的にはなんやねんというレベルだったので、詳しい方から見ると「そこから?」と思うところもあるかもしれません。
また逆に知りたい情報がここに書いていない可能性があります。ご了承ください。
注意点について
REVIVE USBとREVIVE USB MICROは仕様がほぼ同じですが、ファームウェアには互換性がありません。
例えばREVIVE USB MICROにREVIVE USBのファームウェアを当てると文鎮化します。
もう一度言います。
REVIVE USB MICROにREVIVE USBのファームウェアを当てると文鎮化します。
これは公式ホームページでも注意書きがあります。
必ずREVIVE USBにはREVIVE USBのファームウェアを、REVIVE USB MICROにはMICROのファームウェアを当ててください。
内部の仕様がほぼ同じなので、この記事ではREVIVE USBとREVIVE USB MICROを一緒くたにして扱うことがありますが、これだけは気を付けてください。
REVIVE USBおよびMICROのハードウェア仕様
REVIVE USBとMICROは、デフォルトで3つのHIDに対応しています。
改変する場合、これらの入力をハックすることになるかと思います。
- マウス入力
- キーボード入力
- ゲームパッド入力
製品仕様や回路図などについては公式リポジトリからダウンロードできます。
実際に使って触ってみたり、公式や私が配布しているファームウェアをダウンロードして適用してみるなど、ざっくりと流れを把握しておいてください。
しかし、ファームウェアを開発するとなると上記だけでは資料が足りません。
PIC18F14K50というPICマイコンで動作していることに注目してください。
これはUSB 2.0のFull Speed(1msごとの通信)モードに対応している8ビットマイコンです。
開発中に意識する必要があるのは以下の仕様です。
- プログラムメモリ:8kW
- EEPROM:256B
- RAM:768B
一応それぞれ解説します。
- プログラムメモリ
-
コンパイルしたプログラムを格納するメモリです。
「HIDBootLoader.exe」で書き込んだhexファイルはここに格納されます。
RAMではなくROMなので惑わされないように注意。不揮発性です。8kWというのは8192ワードまで格納できますよ、という意味です。
PIC18F14K50は8ビットマイコンなので1ワード=8ビットです。
8192ワード*8ビット=65536バイト(約65KB)まで格納可能、ということになります。
※hexファイルを格納できる領域は決まっているので、MICROの場合、hexファイルは34KB付近が限界です - EEPROM
-
REVIVE USBシリーズにおいては設定を保存するメモリです。
設定ツールで設定値を書き込むとここのメモリの内容が書き換わります。
こちらは名前の通りROMで、不揮発性です。256B。Bが大文字なので256バイトまで利用可能です。
マトリクス版でも36ボタン*3設定値*unsigned char(8ビット)/8ビットで108バイトまでしか使わないので、この領域は結構余裕があります。
※EEPROMは書き換えが頻繁に起こることを想定していません。プログラム内ではRAM代わりに使わないでください - RAM
-
これが一般的なメモリです。揮発性なのでUSBを抜き差しして電源を断つと内容がクリアされます。
プログラム内で変数宣言をすると、ここから確保します。
768バイトしかないので、大きな変数を宣言するとバッファオーバーフローを起こす可能性があります。
ゴリゴリに開発すると、プログラムメモリとRAMの少なさに苦労することになります。
後述しますが、MICROのマトリクス版ファームウェアにチャタリング対策やロータリーエンコーダ対応機能が載っていないのはこのリソースの制約があったからです。
REVIVE USBもREVIVE USB MICROも安価なので、スペックが低いのは仕方ないですね。
ちなみに低スペックなのはメモリ類だけで処理速度(クロック周波数)は優秀な方なので、実行時間はあまり意識せずにコーディングしても大丈夫だと思います。
PIC18F14K50に関する詳細な情報は秋月電子からダウンロードできるデータシートに載っていますが、内容は412ページと長い上に英語、かつ、専門的でとても難解です。
私の場合、調べても情報が見当たらなくて躓いた時に見るようにしていました。
(REVIVE USBの回路図の各ピンとPIC18F14K50の入出力ポートの仕様を紐づけて理解するために調べました)
正直目的があって見なければ何が書いてあるか分からなかったので、明確に知りたい情報が出てきてから見る程度でいいと思います。
IDEとコンパイラの導入
以下記事をご覧ください。
ファームウェアについて
使用言語
みんな大好きC言語です。
ポインタに対する理解がなくても作れます。
PIC18F14K50について
前述の通り、ハードウェア仕様はPIC18F14K50に依存します。
PIC18F14K50の実践的なコードに関しては以下のサイトが分かりやすいです。
iwamotoさんという方が運営されているようで、当時も参考にしたことがあります。私が見た時より情報が増えていることから時々更新も入っている模様。
こういう00年代を彷彿とさせる本当に必要な情報が書いてある個人運営のホームページ、失われてはいけない貴重な文化です
ファイル構成
以下からファームウェアのソースコードをダウンロードして、中身を展開します。
ファイルの中身の概要です。(バージョンによっては若干ファイルの中身が異なるかもしれません)
私も詳しいとは声を大にして言えないスキルレベルなのでご容赦ください。
※拡張子が.oのファイルはコンパイル時に出力されるオブジェクトファイルなので無視します。
ファイル名 (フォルダ名) | 概要 |
---|---|
Microchip ※フォルダ | USBの制御やPICマイコンの定義用ファイルが入っている。改変非推奨。ビット・トレード・ワン社のものではなく、Microchip社のライブラリと思われます |
eeprom.c | EEPROMの読み書き用の関数が定義されている |
eeprom.h | 上記のヘッダーファイル |
HardwareProfile - Low Pin Count USB Development Kit.h | PICマイコン用の定義ファイル。改変非推奨 |
HardwareProfile.h | 同上 |
main.c | メイン処理のファイル |
Makefile | コンパイラ向けの設定。新たにファイルを作るなどしなければ改変不要 |
NMakefile | 同上 |
Revive.mcp | 保存時に作られるMPLABのプロジェクト用ファイル。無視でOK |
Revive.mcs | 保存時に作られるファイル。無視でOK。何のファイルか分からないが内容的に上記と同じような用途? |
Revive.mcw | 保存時に作られるMPLABのワークスペース用ファイル。無視でOK |
Revive.mptags | 保存時に作られるファイル。無視でOKだが、何のファイルなのかよく分からない…… |
Revive.tagsrc | 保存時に作られるファイル。同上(無視でOK) |
REVIVE_MICRO_Ex_v100.cof | コンパイル時に作られるファイル。シミュレータ用のファイルのようだが、シミュレータは使っていないのでよく分からず |
REVIVE_MICRO_Ex_v100.hex | コンパイル時に作られる、HIDBootLoader.exeで書き込むためのバイナリファイル |
REVIVE_MICRO_Ex_v100.map | コンパイル時に作られるファイル。基本的には見ない。プログラム内の変数や関数がメモリのどこに割り当てられるかが分かる |
rm18f14k50.lkr | リンカー向けファイル。改変非推奨。メモリアドレスやセクションが定義されている |
usb_config.h | USBやHIDデバイス関連の定数が定義されている(VIDとPIDもここに書いてあるのでごにょごにょ可能) |
usb_descriptors.c | HIDデバイスのUSBディスクリプタが定義されている |
色々書きましたが、大体は「main.c」だけを取り扱うことになると思います。
改変対象のファイルはmain.cで、コンパイルして作られるのがhexファイルだと思っておけばOKです。
コンパイルするとプロジェクトのディレクトリに「Revive.hex」というファイルが作られます。
同梱されている「REVIVE_MICRO_Ex_v100.hex」はそれをリネームしたファイルということです。
私が改変したファイルについて
今度はREVIVE USBの公式ソースをダウンロードしてください。(ReviveUSB_FWver008.zipの方です)
ファイル内容はMICROと大体同じです。
私が作成したチャタリング対策&ロータリーエンコーダ対応版は、上記のmain.cを改変して作りました。
割り込み周りの処理がほぼ別物になっています。
(試行錯誤していたので他のファイルも更新した覚えがありますが、無視してください)
ここから先はレアケースでしょうが、以下のリポジトリでは追加で「usb_descriptors.c」も改変しています。
これはゲームパッドのX/Y軸入力をスライダー/ダイヤル入力に変更したものです。
スライダー/ダイヤル入力はUSBの仕様に定義されている入力方式です。
具体的にはusb_descriptors.cでHIDレポートの数値を変更しています。
たかがこれだけの変更でも当時、情報がなかったので調べるのが大変でした。USBの仕様書どれ読めばいいか分からないし長すぎて死ぬ
以下のリポジトリでは追加で「usb_config.h」も改変しています。
これは0~255の値を取るゲームパッドのX/Y軸入力を、-128~127の値にし、かつ循環するように変更したものです。
値は入力によって減算・加算され、127の次は-128、-128の前は127になります。
HIDレポートでこれらの最小値/最大値を定義する必要があり、それによってレポートサイズも変わるため、usb_config.hに定義されているレポートサイズも変更しています。
とまあこんな感じで改変していっていました。
ちなみにそれぞれmain.cの中身は若干異なります。
余談
プログラムは終了条件のないwhileで延々と動いています。
通電中はずっと動くので当然ですね。
ほとんどWeb系しかやったことがなかった私はその発想に行きつくまで時間がかかりました。
だってほら、while(1)で動かすWebアプリとか普通ないじゃん?
よくわからんところで躓くという独学の弊害ですね。
設定ツールについて
ファームウェアに対して何らかの設定を行いたい場合、設定ツールの変更が必要になります。
使用言語
C#ですが、一般的なC#の雰囲気はありません。(マイコン畑の方が書いたような感じ?)
ファームウェアとの通信機能も含まれており、マイコンからボタンの押下状態を送信する指示を出して受け取ったり、設定値を送信する機能など、Low-levelなコードがちらほらあります。
以上から、C#の知識はあまり必要ありません。
ソースコードは難解な箇所もありますが、Cが読み書きできるレベルなら大丈夫だと思います。
ファイル構成
以下から設定ツールのソースコードをダウンロードして、中身を展開します。
(App_sourceのReviveMicroEx_CT_ver310_20211111Fix.zipです)
ファームウェアと違ってファイルを一覧して概要を書いたりはしません。
なぜなら、「Form1.cs」にほぼ全ての内容が書いてあるからです。
あとは以下さえ知って入ればOKです。
- 「HID PnP Demo.csproj」がVisual Studioのプロジェクトファイル
- 上記をダブルクリックすればVisual Studioでプロジェクトが開ける
ガッツリ改変する場合は「Resource」フォルダに画像が入っていることを知っておいてもいいかもしれません。
他のファイルはVisual Studioを使っていれば生成されるようなファイルばかりですね。
Visual Studioについては調べれば情報がたくさん出てきますので、興味があれば調べてみてください。
Form1.csについて
何とも無機質な名前ですが、この中に全て書いてあります。
ソースコードは長いので解読には少し苦労するかもしれません。
序盤に構造体を定義している辺りがハードっぽくていいですね。(以下みたいなの)
internal struct SP_DEVICE_INTERFACE_DATA
{
internal uint cbSize; //DWORD
internal Guid InterfaceClassGuid; //GUID
internal uint Flags; //DWORD
internal uint Reserved; //ULONG_PTR MSDN says ULONG_PTR is "typedef unsigned __int3264 ULONG_PTR;"
}
余談はそれくらいにして、ファイル内のクラスは以下です。
クラス名 | 概要 |
---|---|
Form1 | メイン処理用クラス |
Constants | 定数用クラス |
KeyCode | 設定ツールで使用するバーチャルキーコードとUSBキーコードの変換用クラス |
Constantsクラスは見れば分かる内容ですし、KeyCodeクラスを変更することはないと思います。
つまり実質、解読する必要があるのはForm1クラスだけです。
処理はご自身で読んで変えていいかどうかを判断という感じになりますが、一応主なメソッドの概要だけ。
メソッド名 | 概要 |
---|---|
CheckIfPresentAndGetUSBDevicePath | 設定ツールに対するUSB機器が接続されているかどうかを、VIDとPIDなどで判断する |
CheckIfPresentAndGetUSBDevicePath_old_version | 上記の旧バージョン用(REVIVE USB MICROのRev.2と初代はPIDが異なるため) |
WndProc | 上記2つのメソッドを呼び出して、正しいUSB機器が接続されているかどうかを確認する |
ReadWriteThread_DoWork | USB機器とデータを送受信する。マイコン側から送受信するデータと仕様を合わせる必要がある処理 |
FormUpdateTimer_Tick | WndProcメソッドやReadWriteThread_DoWorkメソッドの処理の結果、正しいUSB機器なら設定ツールを有効化、そうでなければ無効化する。USB機器の着脱を検知して実行される |
ReadFileManagedBuffer | ReadWriteThread_DoWorkメソッドから呼び出される。USB機器からの受信内容を変数にコピーする |
my_get_rotary_encoder_setting | チェックしたロータリーエンコーダのペア設定をバイト列に変換する |
my_setDebounceCalcResult | 遅延秒数の計算を行い、設定ツールのテキストに反映する |
他のメソッドはボタンなどに付いているイベントハンドラです。
Visual Studioで作るWindowsアプリはこういう設計思想なんですよね。部品に処理を定義するっていう。
さすがに数が多いので書きませんが、実際にツールを触りながら見ていくと分かりやすいです。
ということで、ReadWriteThread_DoWorkメソッドが実質的にコアの処理になります。
ファームウェア側で送受信するデータを変えるとこの処理の変更が必要になります。
設定ツール全体で見ると、ここの処理のINBufferとOUTBufferにデータを出し入れするためだけに他の全ての処理がある感じになっています。
CheckIfPresentAndGetUSBDevicePathメソッドがあるのは正しいUSB機器を接続しているかどうかのチェックでもありますが、REVIVE USBシリーズにおいては、ファームウェアに対応した設定ツール以外を使えてしまうと危険だからという意味もあります。
ここがNGになると設定ツールがグレーアウトして使えなくなります。
例えば、別製品のFWの設定ツールを使えてしまうと問題が発生するかもしれません。
バグった設定値が書き込まれること間違いなしなので、そのような場合はグレーアウトすべきです。
ちなみにmy_get_rotary_encoder_settingとmy_setDebounceCalcResultは私が書いたメソッドです。
他のメソッドと命名規則が違うし、コード的にもお作法がいいかと言われるとアレです。お恥ずかしい。
私のように自分が書いたコードがいつの間にか公式化するかもしれないので、ちゃんとお作法に沿ったコーディングを行いましょう。
余談
設定ツールのプログラムはMicrochip社の「Device - HID - Custom Demos」が元になっているように見受けられます。
Low-levelなコードを全部解読するのはキツいので、要所要所で理解して変更した方がいいです。
(たまに出てくるWin32 APIっぽいDLLを読み込んでる処理とか正直わからん……)
ライセンスについて
REVIVE USBとMICROのソースコードはAssembly Desk Licenseライセンスのもと公開されています。
公式サイトによればMITライセンスを元に作成しており、MITライセンスとはほとんど内容が変わりません。
というか何が違うんだろう?
ちなみに後継のREVIVE USB ADVANCEではAssembly Desk Licenseライセンスが廃止され、MITライセンスに置き換わっています。
MPLABのトラブルシューティング
ファームウェアを開発していて遭遇する可能性が高いものです。
- Error - section '.xxxx.o' can not fit the section. Section '.xxxx.o' length=0x00000122(任意の数値)
-
コンパイル時、プログラムメモリ内にコードが収まらない場合に出力されるエラーメッセージです。
生成されるバイトコードを削減するようにリファクタリングを行ってください。
if-else文の分岐が大量にある場合、switch-case文に書き換えるといくらか減ります。
私が書いたファームウェアは一応そこも改善していたりします - WARNING: This version of MPLAB C18 does not support procedural abstraction. Procedural abstraction will not be run.
-
評価版の期限(60日)が切れると、コンパイル時にこのログが出力されます。
ちなみに一緒に以下のメッセージも表示されます。
「今コンパイラの最適化が効かない状態だから製品版を買ってね」という内容です。This version of MPLAB C18 does not support the extended mode
and will not perform all optimizations. To purchase a full
copy of MPLAB C18, please contact your local distributor or
visit buy.microchip.com.
もうIDEもコンパイラもアップデートが降ってこないですし、ライセンスは日本円で4万くらいするので、個人利用なら別環境にインストールすることで利用を継続したいところですね。
まあ、60日以内に開発する方が行儀がいいでしょう。
記事を書いたきっかけ
ビット・トレード・ワン社は元々オープンソースハードウェアのコミュニティサイト「Assembly Desk」を運営していたのですが、システムの老朽化に伴い、現在は閉鎖されています。
Assembly Deskはよくあるスレッド形式のフォーラムであり、ユーザー同士の交流に使われていました。
実際に作ってみたソースコードを公開し、発信する場所でもありました。
REVIVE USBについてはロータリーエンコーダ対応コードを上げている方などもいらっしゃいました。
そのコードは1つだけ接続が可能なもの(設定できるピンも固定)で、2つのエンコーダが必要なコントローラの制作には要件を満たせなかったため、そのコードをもとに作ろうと思い立った経緯があります。
どうせファームウェアを作るなら汎用的に作ろうと思い、色々な機能を追加したのがエンコーダ対応版です。
ただ、チャタリング対策機能についてはフォーラムに情報がなかったので、チャタリングについて調べて設計し、実装に関してはPICの資料を漁って作りました。
チャタリングに関する資料もネット上に少なかったので、当時考察して初心者向けに残したのが以下の記事です。
フォーラムの投稿はそれほど多くありませんでしたが、パワーユーザーはコミュニティ内に確かにいました。
現在はこのように情報が集約される場所やユーザー間で交流する場所はありません。
以上の経緯から、せめて私が関わったREVIVE USBシリーズだけでも情報を残しておこうと思いまして、この記事を書きました。
誰かの役に立てば幸いです。
最後に
Raspberry PiやArduinoの方が汎用的ですし、オリジナルUSB機器の制作という点に特化したREVIVE USBシリーズはOSSの活発度も含めて規模が非常に小さく、文献も少ないです。
しかしOSを挟まずにマイコンだけで処理を行う分、非常に安定した出力結果を得られます。
それも複雑な部品をボードに載せることなく、スイッチと何本かのリード線だけでUSB機器が作れます。
ここがREVIVE USBシリーズの優位性です。その一点においては他の追随を許しません。
特に入力遅延に厳しいゲームコントローラの制作においてはOSを挟まないArduinoが競合になりますが、私は設定のしやすさや価格の安さからREVIVE USBシリーズ一択とすら考えています。
使っている方自体はそれなりにいるでしょう。
鳴りを潜めるにはまだまだ惜しいプロダクトだと思います。