マイコンを触るときに課題となるのが「どうやってマイコンにプログラムを書きこむか」です。本記事ではその解のひとつとして、USB接続でデバイスドライバなしに使えるHIDブートローダーを実装したので、紹介します。
本記事はアドベントカレンダー「CH32V203」に参加しています。
ソースコード
作成したHIDブートローダーはこちらにあります。
HIDブートローダーとは
USB-HIDクラスとして動作するブートローダーのことを、通称「HIDブートローダー」と呼びます。USBでのHIDクラスは本来、キーボードやマウス、ゲームパッド、VRコントローラーなど、コンピューターと人間をつなぐデバイスのためのクラスですが、別の特徴として「追加でデバイスドライバをインストールしなくても動く」というのがあります。
マイコンの書き込みのためにデバイスドライバをインストールしたり特別な設定をしなくても書き込めるのは、ときとして重要だったりします。(企業管理のパソコンだったり、一般ユーザーに書き込んでもらう必要があったり……)通信速度は遅いので書き込み時間はかかりますが、その利点はとても貴重です。
構造
HIDクラスではキー入力やマウス入力のほかに、独自定義の通信をすることができます。一度に送れるのは最大64バイト(フルスピードの場合)とかなり少ないですが、とにかく任意のバイナリが送れます。
今回作成したブートローダーには、以下のコマンドを実装しました。
- NOP: なにもしない
- IDENT: チップの識別子を返す
- ERASE: FlashROMの指定領域を消去する
- PROGRAM_START: 書き込みデータの転送を開始する
- PROGRAM_APPEND: 書き込みデータを転送する
- FLUSH: 転送したデータを実際に書き込む
- READ: 指定領域を読み込んでバイナリを返す
- RESET: マイコンをリセットする
- CRC: 指定領域のCRC16を計算する
使い方
GitHubのリリースページからバイナリをマイコンに書き込んでください。
HIDブートローダーは次の場合に起動します。それ以外では、ユーザープログラムにジャンプします。
- ユーザープログラムが書き込まれていないとき
- リセットボタンを2回連打したとき(0.5秒以内に2回)
Rust製のhiduploadコマンドで、ユーザープログラムを書きこみます。ここで書き込むユーザープログラムは、開始位置が0x00004000としてビルドされているものでなければなりません。(リンカースクリプトの編集が必要です)
hidupload --bin userprogram.bin --address 0x08000000 --offset 0x00004000 --erase --verify
アップロードツールについて
今回はRustで製作しました(ほぼCodexが書いた)。Windows, macOS, Linuxのマルチ対応を見越しての選定です。Pythonでもいいのですが、Arduino IDEに組み込むときの外部ライブラリ(hidapi)の取り扱い方がわからなくて……
ブートローダーのビルド方法
LinuxかWSL2環境で、makeとriscv-none-elf-gccを準備してください。
git clone https://github.com/verylowfreq/...
cd ...
make
hidbootloader.elfかhidbootloader.binをマイコンに書き込んでください。
Arduino IDEへ組み込んだ
アップロードがかんたんになったので、Arduino IDEでさくっと書き込めるといいですね。
わたしがフォークして改造している arudino core for ch32では、このHIDブートローダーにも対応させました。
バージョン 1.0.4+sz9 にて対応しています。
board.txt, platform.txtを書き換え、tools/hidupload.exeを配置しました。細かい改変点はもう覚えてないので、レポジトリの実物をご参照ください。
Arduino IDE内からブートローダー自体を書き込むこともできます。WCH LinkEもしくはWCHISPをセットアップのうえ、ツール→Upload methodと書き込み装置の設定を合わせて、「ブートローダーを書き込む」を実行してください。一度書き込んだら、Upload methodのほうは「HID Bootloader」に切り替えてください。