Raspberry PiベアメタルプログラミングでのUSBキーボード入力の調査

以前、Raspberry PiベアメタルでMicroPythonの調査をしたときに

ステップとしてはまずUARTからREPLを叩けるようにし、そのあと画面出力、次にUSBへと進んでいくべきでしょう。

と書きましたが、UARTからREPLを叩くところまでは一応できていますので、今回はUSBキーボード入力についてまとめておきます。

まず、Raspberry PiにはUSBホストコントローラが搭載されていますが、このコントローラはSynopsys社のIPコアを利用していることがマニュアルに書かれています。
このマニュアルに記載されているのは、Synopsysのコアとの差分のところだけで、それ以外はSynopsysのドキュメントを参照してくれ、となっています。

SynopsysのドキュメントはNDAを結ばないと入手できないもので、公開されているドキュメントはありません

デバイスドライバとしては、現在

・Synopsysが提供しているソースコードからの派生(Raspbian等のLinux系OS)
・ケンブリッジ大学の「Baking Pi」チュートリアルに含まれている「csud」ドライバ
・上記2つを参考にした「Circle OS」用のドライバ
・上記3つを参考にした「ultibo OS」用のドライバ

が公開されています。

まず、Synopsys版ドライバについては、以下のフォーラム投稿記事が詳しいです。

RISC OS Open: Forum: USB stack on Raspberry Pi

Synopsys版をベースにしたLinux用のデバイスドライバのコードはこちらにあります。

linux/drivers/usb/host at rpi-patches · raspberrypi/linux

他のドライバもそうですが、IPコアの名称が「DesignWare Hi-Speed USB 2.0 On-the-Go Controller」なので、dwc(おそらくDesignWare Controller)というプレフィックスがファイル名に付いています。

Synopsys版の再配布条件はかなり緩いものになっており、ソースコード(改変可)を再配布する場合はソースコードに記されているライセンス条件を変更しないことが条件になっています。
ドキュメントはソースコードからdoxygenで生成したものがあります。
以下の解説を見るとThreadが必要であるらしく、ベアメタル環境へ移植するにはその部分をどうするかが課題になりそうです。

Synopsys DWC Portability and Common Library for UWB

派生の一つにxinu-osのドライバがあります。(未調査)
ライセンスはBSD3となっています。

xinu/system/platforms/arm-rpi at master · xinu-os/xinu

Linux版よりシンプルになっているように思われますが、OSの一部なのでライブラリとして切り離して扱えるかどうかは分かりません。

csudはAlex Chadwickという方が作成したライブラリです。
ライセンスはMITライセンスです。
Baking PiチュートリアルのLesson 10、Lesson 11がUSBキーボード入力を扱っています。
ライブラリの使い方も詳しく解説されています。
このチュートリアルはプログラミング言語としてアセンブラを使っていますが、ライブラリはCで書かれています。

チュートリアルのダウンロードページでサンプルごとダウンロードできるほか、ライブラリ単体でも以下のGitHubで公開されています。

Chadderz121/csud: Chadderz's Simple USB Driver for Raspberry Pi

チュートリアルは平易な内容で、非常に読みやすいです。
Lesson 10の内容をCで書いてみると、キーボードを読むループはこんな感じになります。

キー入力結果をUARTへ出力するRaspberry Pi Zero W用のコード全体は以下で公開しています。

bare_matal_rpi_zero/usb_kbd at master · boochow/bare_matal_rpi_zero

ただ、このドライバは簡易版のドライバで、バルク転送やインタラプト転送がサポートされていません。
また、手持ちのキーボードをいくつか試してみたところ、Raspberry Pi Zero WのUSBポートに直接接続すると

HCD: Request to New Device (Not Ready) has failed 3 times.
HCD: Transfer was not acknowledged.
HCD: Transaction error in transfer.
HCD: Control message to 0x6380008: 80060001 00001200.
HCD: Request to New Device (Not Ready) failed.
HCD: Could not send SETUP to New Device (Not Ready).
USBD: Verifying New Device (Not Ready) is still connected.
USBD: Yes, New Device (Not Ready) is still connected.
USBD: Failed to get descriptor 0x1:0x0 for device New Device (Not Ready). Result 0xfffffffc.
USBD: Failed to read device descriptor for 2.
HUB: Could not connect to new device in USB Root Hub.Port1. Disabling.
USBD: Deallocating device 2: New Device (Not Ready).

というエラーメッセージが表示されて、デバイスを認識させることができませんでした。
しかし、USBハブを介在させると普通に認識できます。
(Zero W以外ではまだ試していません。)

同様の現象がRaspberry Piフォーラムでも報告されていますが、解決方法は不明です。
csudの64bit対応の派生版もありますが、上記のデバイス認識の問題は変化ありませんでした。

Raspberry-Pi/Arm32_64_USB at master · LdB-ECM/Raspberry-Pi

csudはコードは全体でも5000行程度、ドライバの中核であるsource/hcd/dwc/designware20.cは800行あまりと、かなりコンパクトにまとまっています。

オリジナルでは実装されていないバルク転送モードについては、csudに機能追加された下記のフォークが存在しています(未調査)。
バルク転送モードとインタラプト転送モードはよく似ているらしいので、もしかしたらインタラプト転送モードも追加可能かもしれません。

yeqingyan/csud: Chadderz's Simple USB Driver for Raspberry Pi

なお、USBの転送モードの違いについては、USBの技術解説がいくつかありますのでリンクしておきます。

USBの解説(picfun、PDFファイル)
USB通信プログラミングテクニック(picfun)
USBの基礎知識 ――パケットのフォーマットからプロトコルの詳細まで|Tech Village (テックビレッジ) / CQ出版株式会社

次に、Circle OS用のドライバ「USPi」です。
これはCircle OSのドライバ部分を切り出して単独でライブラリとしたもので、以下で公開されています。

rsta2/uspi: A bare metal USB driver for Raspberry Pi written in C

Introducing USPi – A bare metal USB driver written in C – Raspberry Pi Forums

ライブラリのREADMEには、Synopsys版とCSUDを参考にしたと記載があります。
ライセンスはGPLv3となっています。

このドライバもサンプルにキーボード入力がありますので、動かしてみました。(動作にはHDMI接続が必要です。)
こちらはCSUDと違い、USB Hubを介さずともキーボードを認識することができました。
使用方法も、キーボード入力に対するコールバック関数を登録するだけで、かなり簡単です。
また、サポートされるデバイスがMIDIやEthernetなど、CSUDより多いです。
その代わり、CSUDと比べるとかなり規模は大きく、ライブラリが9000行程度、USB以外のサポートライブラリが4000行程度となります。

最後にultibo OSのライブラリです。
ライセンスはLGPL2.1です。
ultibo OSのデモを動かしてみたのでスクリーンショットを載せておきます。

ultibo-demo.jpg

DOS+マルチタスク+フレームバッファという感じでしょうか。

ultibo OSは全体がPascalで書かれています。
個人的には昔Turbo PascalやDelphiを使っていましたので、Pascalに抵抗感はありませんが、正直「今どきPascal?」という気もちょっとします・・・。

それはさておき、ultibo OSのUSBドライバはコアの部分だけでも5000行あります。
ドライバ自体は、Linux版、FreeBSD版、USPiおよびCircle OSのドライバを参考にしたとあります。

Core/dwcotg.pas at master · ultibohub/Core

ただ、このソースコードは冒頭にコメントが100行ほどついており、DWCの解説にもなっていますので一読の価値はありそうです。

ということで4種類のUSBドライバを見てきましたが、一長一短ですね。
Linux版はライセンスが緩く機能も完璧ですが(チップの開発元が作っているから当然)、Threadが必要という要件もあり、ベアメタルへの移植は大変(そう)かもしれません。
CSUDはコンパクトで、MITライセンスですので、MicroPythonと一緒に使ってもMicroPython本体への影響が少なくて済みそうですが、USBハブを介さないとキーボードを認識できないのが残念なところです。
USPiは機能的に十分ですが、ライセンスがGPLです。この場合、ベアメタルRPi版MicroPythonは、MicroPythonに統合するのではなくMicroPythonの応用製品という位置づけにしないと、MicroPythonのライセンス(MITライセンス)と不整合が生じます。
ultibo OSはLGPLで、機能もUSPiに近いですが、ultibo OSの他のUnitにも依存しているので、ライブラリとして使うというよりMicroPythonをUltibo OSに移植するようなイメージになると思います。
ちなみに、Raspberry Pi版IchigoJamのREADMEにはultiboを開発環境として利用していると記載されていました。

コメント