Open5

Raspberry Pi Pico でキーボード的なものを作るための技術調査

numurumunumurumu

やりたいこと

  • Raspberry Pi Pico を接続したPCにキーボードと認識させ、ボードに接続されているボタンを押したらキー入力としてPCに送信
  • Webブラウザから設定をPicoに送信し、永続化
  • Pico のプログラムの開発は可能であればWSL上で行いたい
numurumunumurumu

Raspberry Pi Pico の開発環境を作る

最初Arduinoから使うのが楽かと思ったが、Arduinoのライブラリ(?)が2種類あって困惑する。

  • Arduino公式版 : Mbedベース
  • Earle Philhower版 : Pico SDKベース

参考 : https://lipoyang.hatenablog.com/entry/2021/11/27/202142

検索した感じ、後者の方が使いやすいと言われてる。

それならPico SDKを直接使ったほうが良いのでは?ということで、Pico SDKを使う方針に。
(※ もしかしたらArduinoの方が再書き込みが簡単にできるかもしれないので、戻ってくる可能性あり)

numurumunumurumu

Pico SDK をインストールする

https://github.com/raspberrypi/pico-sdk

SDKのインストール自体は、

  • sdkのソースをclone
  • clineしたパスを環境変数 PICO_SDK_PATH にセット
  • コンパイラ等の必要なパッケージをOSのパッケージマネージャーでインストール (linuxの場合)

で終わる。

サンプルプログラムを見てみる

https://github.com/raspberrypi/pico-examples

ここに色々ある。

これをビルドするときは全プログラムを一気にビルドすることになる。
ビルドすると uf2 ファイルが出来上がるので、これを以下の手順で書き込めばそのまま動作する。

  • Raspberry Pi Pico のボードにあるボタンを押しながらUSBケーブルを接続する
  • USBストレージとして認識されるので、そこにuf2ファイルをコピー(ドラッグ&ドロップ)する
    • USBハブをタコ足配線してたらこの認識がされず困った

ここまでの作業はWSL2で問題なく行える。

この書き込み方法は毎回USBケーブルを抜き差ししないといけないので微妙

USB HID のサンプルを動かしてみる

pico-sdkをcloneしただけだと、 USB機能を実装するために必要な TinyUSB ライブラリが入らない。cloneしたpico-sdkで git submodule update --init すればインストールできる。
その後、サンプルのビルドをcmakeからやり直せばusb系のサンプルも動かせる。

USB HIDのサンプルは以下
https://github.com/raspberrypi/pico-examples/tree/master/usb/device/dev_hid_composite

これを書き込むと、Picoがキーボードとして認識され、ボード上のボタン (※) を押すと下記入力がPCに送信される。

  • キーボードのA
  • ボリュームを下げる
  • ゲームパッドのAボタンとHAT(?)
  • マウスを少し右下に移動

下2つの入力はコード上から読み取ったもので、実際に入力されているかは確認できてない。

※ ボード上のボタンは、BOOTSELと書かれてるやつ。接続時にはモード切り替えボタンとして働くが、その後はユーザー定義のボタンとして動作するらしい。

numurumunumurumu

USB HID のサンプルを読む

tusb_ プレフィクスはTinyUSB、tud_プレフィクスはTinyUSBのデバイス側(notホスト側)の関数の様。

board_プレフィクスの関数は、TinyUSBのボード依存の関数の定義がある。
実装はここ。大したことはやってない。
https://github.com/hathach/tinyusb/blob/master/hw/bsp/rp2040/family.c

main.c

main関数

初期化してあとはずっとループ。
ループ中に呼び出している関数は名前にtaskとあるが、RTOSのtaskの様なOS管理されたものではなく、それぞれ単純に処理をまとめただけの関数。
tud_taskはTiny USBの関数で、おそらく必ず定期的に呼び出さないといけない関数。残り2つのtaskは独自に定義したもの。
led_blinking_taskはLEDを点滅させているだけなのであんまり見なくて良い。
hid_taskが本体

hid_task関数

この関数の処理は10ms毎に実行する想定らしく、関数の先頭はその実行タイミング調整用の処理。まだ実行すべきタイミングでなければ早期return。
board_button_readでボード組み込みのボタンが押されているかどうかを判断する。
待機状態中にボタンが押されたら、wakeupさせる。
そうでなければsend_hid_reportを呼び出す。

send_hid_report関数

第1引数のreport_idに応じて適切な tud_hid_xxxx_report 関数を呼び出す。
汎用的な関数を意図しているようにも見えるが、実際は tud_hid_report_complete_cb (レポート送信完了じのコールバック) 内の処理と合わせて、4種類のサンプル入力を次々と送信することを意図した関数。
キーボードだけでいいなら、こういう関数を作らず直接 tud_hid_keyboard_report を呼び出せば良い。

tud_hid_get_report_cb コールバック

分かんない

tud_hid_set_report_cb コールバック

ホスト側からのデータ通信。
CAPS LOCK のLED点灯命令が来たらLEDを光らせる実装に見える。
これを使えば、PCからのデータ通信を実現できそう。問題は最大データ量がいくつかという点。

その他コールバック群

以下はUSBの接続状態等の変化時に呼び出される関数らしい。
中でやっているのはLEDの点滅速度の変更だけなので、そういうのが不要なら無視して良さそう。

  • tud_mount_cb
  • tud_umount_cb
  • tud_suspend_cb
  • tud_resume_cb

tsub_config.h

Tiny USB を使う場合に必要なマクロによる設定をまとめて行う場所

usb_descriptor.c

アプリケーションとしては意識しなくて良いが、PC側がこのデバイスがどういう性質のものかを知るために必要な情報を提供するための実装一覧の様。
VIDが Cafe

numurumunumurumu

TODO