USBバルク転送タイムアウトのデバッグ:High-Speed・Full-Speed・STALL・NAK・ファームウェア遅延

USBバルク転送のタイムアウト、遅い読み出し、書き込みストール、NAK挙動、エンドポイントHALT復旧、速度不一致、ファームウェア遅延を、USB証拠をもとに診断する方法を解説します。

USBバルク転送タイムアウト, バルクエンドポイント, USB High-Speed, USB Full-Speed, エンドポイントSTALL, USB診断

USBバルク転送は、「タイミングの正確さ」よりも「正しさ」が大事な場面で活躍します。ストレージデバイス、シリアルアダプタ、デバッグプローブ、ファームウェア更新ツール、スキャナ、ベンダー固有デバイス、各種データ収集製品など、多くの機器がバルクエンドポイントを採用しています。失敗するときの検索ワードは USB bulk transfer timeoutbulk endpoint stalledUSB read timeoutUSB write timeoutlibusb bulk transfer failedUSB device stops responding during bulk transfer などです。

アプリケーション側に見えるのは、たいてい「タイムアウト」か「I/Oエラー」です。しかしバス側ではもっと豊かな物語が繰り広げられています。デバイスがNAKを返し続けた、エンドポイントがストールした、ホストが再送した、デバイスがリセットした、転送サイズが間違っていた、期待より速度が遅かった、ファームウェアがデータ準備中にブロックした——そんな可能性があります。

Bus Scopeが活きるのは、バルク転送の失敗には「エンドポイントレベルの証拠」が必要で、アプリのスタックトレースだけでは足りない場面が多いからです。

バルク転送の得意分野

バルク転送はUSBプロトコルレベルでは信頼性があります。利用可能な帯域を使い、再送も可能です。「遅延の厳密さ」よりも「データの正しさ」が大事な、大容量データ移動に向いています。

バルク転送を使う機器の例:

  • USBマスストレージ
  • CDCシリアルアダプタ
  • ベンダー固有ファームウェアツール
  • デバッグプローブ
  • 計測機器
  • プリンタ/スキャナ
  • 一部のキャプチャデバイス
  • FPGA/マイコンのデータパイプ

バルク転送は余ったバス帯域を使うため、性能は他のUSBトラフィックやホストのスケジューリングに左右されます。

タイムアウト ≠ パケットロスとは限らない

バルク転送のタイムアウトは、たいてい「アプリ側のタイムアウト時間内に、ホスト側のリクエストが完了しなかった」ことを意味します。USBバスが合法的に振る舞っている場合でも発生します。

原因はさまざまです:

  • デバイス側にデータがなく、NAKを返し続けている
  • ファームウェアが忙しく、応答が遅れている
  • STALL後にエンドポイントがHALTしている
  • ホストが誤ったエンドポイントにリクエストを送っている
  • 転送サイズがプロトコル上の期待と合っていない
  • デバイスがリセットされた/切断された
  • ドライバが転送を正しくサブミットしていない
  • Full-Speed経路では期待スループットが出ない
  • 別のデバイスがバス帯域を消費している
  • アプリ側のタイムアウトが厳しすぎる

トレースを見れば、このうちどれが妥当か切り分けられます。

NAKの挙動

USBデバイスはNAKを返すことで「今は一時的に準備できていない」と示せます。NAKは必ずしもエラーではなく、フロー制御のシグナルです。

バルクINエンドポイントでNAKが繰り返されるなら、デバイス側にまだデータがないということです。バルクOUTエンドポイントでNAKが続くなら、デバイスがこれ以上データを受けられないということです。

問題になるのは「継続時間」と「文脈」です。数回のNAKは正常範囲。アプリタイムアウトまでNAKが続くなら、デバイスがいつまでも準備できないか、ホストが時期尚早にデータを期待しているかのどちらかです。

STALLとエンドポイントHALT

STALLはNAKとは別物です。多くの場合、エンドポイントが停止したか、その文脈ではサポート外のリクエストが来た、という意味です。復旧には次のリクエストが要ることが多いです。

CLEAR_FEATURE(ENDPOINT_HALT)

ホストがHALTをクリアしないと、その後の転送も失敗し続けます。クリア直後に再度ストールするなら、ファームウェア側のコマンドシーケンスが拒否されている可能性があります。

確認すべきポイント:

  • タイムアウト前の最初のSTALL
  • CLEAR_FEATURE(ENDPOINT_HALT) の有無
  • クリア後に転送が再開するか
  • 毎回同じコマンドでSTALLするか
  • 繰り返すSTALLのあとでリセットが起きているか

High-Speed vs Full-Speedの現実的な期待値

USB速度によって「現実的なスループット」は変わります。Full-Speedで動いているデバイスは、High-Speedの性能を出せません。High-Speed対応デバイスでも、ケーブル・ハブ・ポート・信号品質・デバイスネゴシエーション次第でフォールバックすることがあります。

アプリがHigh-Speedの性能を見積もっていても、デバイスがFull-Speedで列挙されていれば、大容量転送でタイムアウトが現れます。

ディスクリプタ・ネゴシエートされた速度・エンドポイントの最大パケットサイズ・実際の転送ペースを確認しましょう。コネクタ形状やマーケラベルから速度を推測しないでください。

ファームウェアのコマンドプロトコル

多くのバルクデバイスは、USBの上に独自のコマンド/レスポンスプロトコルを持ちます。ホストがバルクOUTにコマンドを書き、バルクINのデータを待ちます。

タイムアウトは次のような場面で起きます:

  • コマンドフォーマットが間違っている
  • バルク転送の前にコントロールリクエストが必要
  • ステータスを別エンドポイントで返している
  • ホストが早く読みすぎている
  • ホストが多く読みすぎている
  • ファームウェアがコマンド処理中にブロックしている
  • デバイスがZero-Length Packet境界を要求している
  • 過去のエラー状態がクリアされていない

パケットの証拠を見れば、「デバイスがコマンドを無視した」「ストールした」「受け取ったが応答しない」「別エンドポイントで応答した」のどれかが見えます。

バルク転送サイズとショートパケット

USBバルクのプロトコルでは、ショートパケットが「転送の終わり」を示すことがあります。ホストが固定長を期待しているのに、デバイスがショートパケットを送ると、アプリ側で結果を誤認する可能性があります。デバイスがすでに転送を終えたあとでホストが追加データを待ち続けると、アプリ層でタイムアウトが発生します。

確認ポイント:

  • 要求された転送長
  • 実際に返ってきた長さ
  • ショートパケット
  • Zero-Length Packet
  • USBの上位にあるプロトコルフレーミング

カスタムファームウェアやlibusbベースのツールでは特に重要です。

デバッグチェックリスト

次の流れで作業すると、原因に早くたどり着けます。

  1. 列挙とエンドポイントディスクリプタをキャプチャする
  2. デバイス速度とエンドポイントの最大パケットサイズを確認する
  3. バルクIN/バルクOUTエンドポイントを識別する
  4. タイムアウトするコマンドまたは転送をキャプチャする
  5. エンドポイントがNAK・STALL・データ・切断のどれを返すかを確認する
  6. STALL発生時は CLEAR_FEATURE(ENDPOINT_HALT) による復旧を観察する
  7. 要求長と実長を比較する
  8. デバイスがショートパケット/Zero-Length Packetを送るかを確認する
  9. ポート直結とハブ経由、High-SpeedとFull-Speedの経路を比較する
  10. 可能ならファームウェアログと突き合わせる

最終的な診断

USBバルク転送のタイムアウトは、单一のバグではありません。正常なNAKがアプリタイムアウトを超えたケース、エンドポイントSTALLが復旧されなかったケース、ファームウェアが応答しなかったケース、想定より速度が遅かったケース、プロトコルフレーミングが間違っていたケース、デバイスがリセットされたケース——いずれも可能性があります。

Bus Scopeはエンドポイントレベルのシーケンスを可視化するので、「汎用I/O失敗」ではなく「診断可能なUSBの証拠」としてタイムアウトを扱えるようになります。