USB Type-Cの判断力をレガシーケーブルで推しはかる

![_DSC0646.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108691/a457b114-17db-69f6-e3a8-846dfb8c9ba3.jpeg)
先にオチを書いておくとUSB 1.1世代のセルフパワーのデバイスが、Type-Cで地味にトラブることがあるね。という話です。

USB Type-C to USB2.0 Micro-Bケーブルで、ちょっと古いデバイスとPCを繋ぐケースはよくありますよね。最近使っているRaspberry Pi PicoもMicro USBのデバイスなのですが、使っている間に

- Raspberry Pi Pico W(無線仕様)
- Pico Wをバッテリー駆動する(VSYSに給電)
- Type-C to USB 2.0 micro USBケーブル、またはType-C to Standard-AアダプタでホストPCと接続

という条件で、ケーブルを

1. デバイス
2. ホストPC

の順に接続するとUSBで電力が供給されず、結果USBデバイスとして機能できないという現象を踏みました。接続順を逆にすると問題は起きません。またType-CではなくType-Aでホストに接続しても問題は起きません。さらに標準のPicoの場合も問題は起きません。無線仕様のPico Wだけです。

## USBレガシーケーブルアセンブリ

USB Type-Cの仕様では、Type-C以前の古いコネクターとの配線を __Legacy Cable Assemblies__[^1]として定義しています。
![Type-C to USB2.0 Micro-B Cable assembly.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108691/5607f45f-2240-bc7f-ba54-b822366e3bd6.png)
それぞれのピンをどう配線するか、Type-Cにだけにあるピンをどう処理するか明確に記述されています。Type-Cケーブルでよく話題に上がる `CC`(Configuration Channel)ピンは、Micro-Bケーブル相手の場合はType-Cケーブル内で5.1kΩ±20%の抵抗を介してGNDに接続されます。

## 今回の現象

3本の単三電池で`VSYS`に給電したPico Wを、ときどきUSBでホストPCに接続。そのときに少し挙動を変えるようなプログラムを書いていました。回路はPico Wデータシート[^2]を参考に、ショットキーダイオードを挟むだけのシンプルなもの。
![circut_diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108691/d2232cde-7268-4cfa-2363-0e9c26ca9842.png)

データシートではVSYSにバッテリー給電しながらUSB接続して給電を受けても問題がない回路構成になっている旨説明されています。実際にUSBケーブルを着脱してもPico Wは動き続けます。ただしホストPCとのUSB通信はときどき確立されません。ん？ときどき？
世界中でめちゃくちゃ数が出ているIoT製品がこんな変な動きするわけないじゃんよ？とか思いつつもRaspberry Pi Pico forum[^3]で相談したところ、USBから給電されているはずの`VBUS`の電圧を実際に測ってみようぜーということになり、接続条件を変えながら測ってみました。

| Device  | USB未接続 | デバイス->ホストの順で接続 | ホスト->デバイスの順で接続 |
|---------|-------------------------------|----------------------------------------------------|-----------------------------------------------------|
| Pico    | 0.42 V                        | 5.17 V                                             | 5.17 V                                               |
| Pico W  | 1.36 V                        | 0.97〜1.09 V (計測値は不安定)                            | 5.16 V                                               |

結果、ケーブルの接続順によってはUSB通信どころかUSB電源(`VBUS`)が供給されていないことがわかりました。さらにUSB未接続時のPico WのVBUSにはどこからか1.36 Vの電圧が。犯人はヤツ。

## USB PD vSafe0V

Type-Cの仕様書ではVBUSの"0V"をUSB Power Deliberyで定義される __vSafe0V__[^4]としています。vSafe0Vの範囲は0〜0.8V。上記のUSB未接続時のPico Wの値 1.36VはvSafe0Vを余裕で超えています。これらの事実から、vSafe0Vを超えたVBUSを持つデバイスをType-C接続した際に、ホストのUSBコントローラーが異常と判断してVBUSに電力供給をしない操作をした可能性が推察されます。
_ホスト->デバイス_ の順で接続して問題が起こらないのは、Type-Cコネクタ内でGNDに接続されたCCの状態によって「俺はSource (ホスト)だ(確信)」と決心がつくから。 _デバイス->ホスト_ 順の場合はまだ決心がつかない。たぶん。詳しくはUSB Type-C Specを読んでください。僕は諦めました。

ちなみにvSafe0Vの閾値はUSBコントローラである程度いじれるようですが、たぶん非推奨。調査の過程で、無線仕様ではない標準PicoのVBUSにつながっている `GPIO24`[^5] をpull-upしても特に影響なかったことが解せなくて、こちらの電圧を測ってみたところ __0.96 V__ でした。超えてるじゃん！けど、これくらいは許容されるらしい。

## 問題の回避策

なんだかえらく遠回りした気持ちです。バッテリー駆動するPico WがUSB接続したことを検出する、という本来の目的を達成するためには、USB接続されたら確実に通信を確立してもらう必要があり、これは前出の事実と推察から次の3パターンで対応できます。

### A. ソフトウェア対応

Pico WのVBUSは、無線モジュールCYW43439の`WL_GPIO 2`に接続されています。このGPIOはデフォルトでtri-stateなのですが、これを明示的にLow出力に設定すると、この問題は回避できます。ただし、GPIOでVBUSの状態を見ることはできなくなります。 

```C
cyw43_arch_init();
cyw43_arch_gpio_put(2, 0);
```

### B. ハードウェア対応

VBUSへの漏れが問題なので、Pico WのVBUSに繋がる40ピンをPull-downする回路を追加すると、この問題は回避できます。抵抗値はUSBのサスペンドを配慮するなら10kΩ程度じゃないかということ。
![Pico W USB Pull-down.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108691/3b3937bf-cf43-9a31-9773-48207e3588f6.png)
手持ちの抵抗がなかったので1kΩ程度で試したところ、問題が起きないことを確認できました。

### C. 根本のファームウェア対応

無線モジュールCYW43439のGPIOの設定をソフトウェア的に変更すれば良いじゃない？そう思うのですが、このチップの仕様は公開されていません。マジかよ。pico-sdkが当該チップとSPIで通信している箇所も、あいにくGPIOのpull-up/down抵抗を設定する処理は含まれていませんでした。マジかよ。
というわけでエンドユーザーにとってこの選択肢は無し。Raspberry Pi PicoのGithub Issueにレポート[^6]して、対応を依頼しました。たぶんPico Wのデータシートでこの問題が言及されるオチではないかなと考えています。


結局、vSafe0Vを超える電圧が、何から漏れた電流由来なのかは確定できていません。無線モジュールCYW43439のGPIOか、オンボードのショットキーダイオードMBR120VLSFT1Gのいずれかだと思われます。

こんな感じで僕の2024年の大型連休は潰れました。結果、よく知らなかったことを勉強できて面白かったのですが、なんだかえらく遠回りした気分です。後日、Raspberry Piのエンジニアから謝意と、この問題を調査する旨コメントをもらいましたのでチャラとしましょう。
問題や調査の詳細はGithubリポジトリにまとめてあります。

https://github.com/oyama/pico-w-usb-failures


[^1]:[USB Type-C® Cable and Connector Specification](https://www.usb.org/document-library/usb-type-cr-cable-and-connector-specification-release-23)
[^2]:[Raspberry Pi Pico W Datasheet](https://datasheets.raspberrypi.com/picow/pico-w-datasheet.pdf)
[^3]:[Raspberry Pi formu](https://forums.raspberrypi.com/viewtopic.php?t=370292)
[^4]:[Universal Serial Bus Power Delivery Specification](https://usb.org/document-library/usb-power-delivery)
[^5]:[Raspberry Pi Pico Datasheet](https://datasheets.raspberrypi.com/pico/pico-datasheet.pdf)
[^6]:[Raspberry Pi Pico Feedbask Issue](https://github.com/raspberrypi/pico-feedback/issues/391)