USBキーボードをSBCにつなぐ KKBD-USB その3 ~キー入力完成、ハマったところまとめ~

前回(その2)では、TinyUSB によるUSBホスト基盤(Phase 3)まで来ました。今回はその続き。Phase 4〜6 を実装して、USB キーボードからキーを打ったら SBC に届くメインのパスをひと通り完成させました。最後にユーザーマニュアルも整備して、Phase 1〜6 の暫定稼働 OK というところまで来ましたという話です。
Phase 4: 基本キー入力(英数字)
USB HID の Boot Protocol では、キーボードから 8 バイト固定のレポートが届きます。Byte 0 が修飾キー、Byte 2〜7 が最大 6 キーの HID Usage ID です。キーを「押した瞬間」だけ処理するには、前回レポートとの差分検出が必要です。s_prev_report という 8 バイトのバッファを持って、新たに出現した Usage ID だけをキーダウンとして扱うようにしました。
6 キーを超える同時押しが発生すると、HID Boot Keyboard は Byte 2〜7 を全部 0x01(ErrorRollOver、いわゆる「Phantom 状態」)で埋めて返してきます。通常の文字入力では 6 キー超えはほぼないので、Phantom のみのレポートはスキップする処理を入れて対処しました。
Phase 5: 修飾キー対応
Shift/Ctrl に対応するにあたって、keymap.c を if-else からテーブル方式に書き直しました。256 バイトの静的テーブルを 3 つ(normal/shift/ctrl)用意して、C99 の designated initializer で初期化しています。keymap_convert(usage_id, modifier) の中で Ctrl → Shift → Normal の優先度で変換します。Ctrl+Shift+A は Ctrl が優先されて ^A(0x01)になります。
実機検証で使ったキーボードが JIS 配列でした。KKBD-USB の keymap は US 配列基準なので、JIS キーボードを使うと刻印と送信内容がずれます。P の右の @ キーを押すと [ が送信されるし、Shift+2 で @ が出てきます。最初はびっくりしますが、US 配列として打てば OK です。JIS 配列の完全対応は別 Issue として積み残しています。
Phase 6: 行末コード・キーリピート・LED
キーリピートは「500ms 初回遅延 + 50ms 間隔」で実装しました。時刻判定を keyrepeat_decide(now_us, last_fire_us, initial_fired) という純粋関数に切り出したので、ホスト PC でそのままユニットテストが書けます。Enter のリピートは意図的に無効にしています。
LED は 5 状態(BOOT/WAIT_DEVICE/MOUNTED/TX/ERROR)の状態機械です。TX 状態(30ms 点灯)から戻るとき、WAIT_DEVICE の点滅位相を保存・復元してチカチカが乱れないようにしています。行末コード CR/LF/CRLF はジャンパー JP1/JP2 で切替、python3 -m serial.tools.miniterm -f hexlify で 16 進確認しました。


ハマりまとめ
VBUS と VSYS の違い: VBUS は USB 入力専用で、Pico 内部では D1(ショットキーダイオード)経由で VSYS につながっています。外部 5V を追加したい場合は VSYS(ピン 39)にショットキーダイオード経由で入れるのが正解です。最初「VBUS 直接給電」と書いてしまいレビューで修正されました。Raspberry Pi Pico 公式ドキュメントに書いてある話なので、ちゃんと読んでおくべきでした。
JIS キーボードの US 配列基準動作: P の右の @ を押したら [ が出た。最初はびっくりしますが仕様です。US 配列として打てば OK。
次にやりたいこと
- Phase 7(異常系処理):tuh_init 失敗時セーフモード、受信失敗リトライ、watchdog 導入
- Phase 8(総合実機検証):複数キーボード互換性、24 時間連続動作
- JIS 配列対応(別 Issue)
- SBC6800 / KZ80 への実接続テスト
- 最終目標はスタンドアロン構成:MC6800 ROM モニタの SBC6800 + K68-VDG(画面)+ KKBD-USB(キーボード)でスタンドアロン構成を組んで、PC なしで BASIC を動かせるところまで持っていきたいです
関連リンク
- GitHub: https://github.com/kuninet/KKBD-USB
- Issue #12(Phase 4): https://github.com/kuninet/KKBD-USB/issues/12
- Issue #13(Phase 5): https://github.com/kuninet/KKBD-USB/issues/13
- Issue #14(Phase 6): https://github.com/kuninet/KKBD-USB/issues/14
- TinyUSB: https://github.com/hathach/tinyusb
- USB 簡単ホスト: https://q61.org/blog/2021/06/09/easyusbhost/