USB充電時の停止再開ループの原因を探る

# サマリ
* 2024年の夏に買い換えたXperia 1 VIをUSB充電する際、充電が突然停止＆再開を繰り返すという謎挙動に遭遇。再現性はかなり高いが、充電器を変えたらOKだったり、全く充電できないわけではない。
* 検索してみても同様の事象は引っかからないようで、個体差という気がしなくもなかったが、原因が気になったので解析してみた。というのが本記事。
* PDプロトコルアナライザを使わないでPDパケットを解析するという暴挙の記録とも。
* 結論としては、スマホの充電電流(I)とケーブル電源線抵抗(R)からオームの法則で求まる電位差(E=I*R)が、ある一定基準(＝耐性)を超えた場合に症状が発生する。この耐性は充電器やスマホの設計により異なるところが、この問題の難しさ。

# 登場アイテム
### 充電器
* Anker Nano II 65W
https://www.ankerjapan.com/products/a2663
* Anker PowerPort III 3-Port 65W Pod
https://www.ankerjapan.com/products/a2667
### ケーブル
* Amazonベーシック USB-Cケーブル (USB2.0) 0.9m (推定250mΩ)
https://www.amazon.co.jp/dp/B01GGKZ0V6
* Anker PowerLine III Flow USB-C & USB-Cケーブル 0.9m (推定100mΩ)
https://www.ankerjapan.com/products/a8552
* UGREEN USB Type-Cケーブル USB3.1/PD100W/TB3/5Gbps 1m (推定100mΩ)
https://www.amazon.co.jp/dp/B07BTV4KJJ
### スマホ
* SONY Xperia 1 VI (SIM Free)
* SONY Xperia 5 II (au)

# 症状
## 正常(と思われる)挙動
状況により様々な挙動が観測されるため推測ではあるが、Xperia 1 VIは25W充電で設計されているようで、スマホが9Vを要求して最大2.8A吸うのが定常状態。ただしケーブルでの電圧降下を補償するためか、充電器出力はPPSで10V程度になっていることも多い。

## 症状概要
スマホをUSB充電していると、充電停止・再開が2秒前後の周期で繰り返されることがある。繰り返し回数は1回で終わることもあれば10回以上繰り返されることもある。ただし永遠に続くようなことはなく、そのうち安定充電に移行する。また発症タイミングとしてはケーブルを挿した直後の他、一旦は安定充電動作となった後でもしばらくしたら充電停止再開のループが始まることが多い。この安定⇔発症の状態遷移も複数回の繰り返しがあり。

動画で見ると次のような感じ。動画ファイルが直接貼れなかったのでXへのリンクで。
<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">うちのスマホの充電開始停止ループ問題の動画を録ってみた。電圧電流測定は充電器(ソース)側。上げたのは比較的少ない回数で安定したタイミングだけど、もっと(20回くらい)繰り返したり、一旦安定した後も1～2分でまたループが始まったりと色々で… <a href="https://t.co/kNsVom3h6A">pic.twitter.com/kNsVom3h6A</a></p>&mdash; Tosy (@tosy) <a href="https://twitter.com/tosy/status/1866465172111671715?ref_src=twsrc%5Etfw">December 10, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 発症条件
#### 充電器・ケーブル・スマホの組み合わせ
<table>
<tr><th colspan=2></th><th align=center colspan=2>推定ケーブル抵抗</th></tr>
<tr><th>スマホ</th><th>充電器</th><th>250mΩ</th><th>100mΩ</th></td>
<tr><td rowspan=2>Xperia 1 VI<br>(充電25W)</td><td>Nano II 65W</td><td><b>発症</color></b></td><td>正常</td></tr>
<tr><td>3-port 65W Pod</td><td>正常</td><td>正常</td></tr>
<tr><td rowspan=2>Xperia 5 II<br>(充電20W)</td><td>Nano II 65W</td><td>正常</td><td>？</td></tr>
<tr><td>3-port 65W Pod</td><td>正常</td><td>？</td></tr>
</table>

#### ここから推測される発症条件
上表より、
* 充電器がAnker Nano II 65W
* ケーブルの内部抵抗(VBUS-GND)が高い
* スマホがXperia 1 VI

の3条件が重なった場合に発症すると推測される。

スマホの違いがどういう影響をもたらしているかは不明だが、充電電力の違いという可能性はありそう。充電電力は公表されておらず手元での実測値ではあるが、Xperia 1 VIは25W、Xperia 5 IIは20Wと違いがある模様。

## 暫定対策
上記3条件が1つでも外れればよいので、
* 充電器を変える
* ケーブルを内部抵抗の低いものに変える
※ただしケーブルが太くなって取り回しは悪化…

のような対策を取ればよい。また、ある程度の不便さを受け入れるのであれば、以下のような妥協策もあり。
* 強制的に非PD状態にする(USB-A充電器を使う、USB-C→A→Cの2段変換をかましてCC信号線を切断する、など)
➡ 5W充電になってしまう

* あきらめるｗ
➡ 全く充電できないわけではなく、充電停止・開始時の本体通知(バイブレーション)を無視できる強い心があればOK

# 症状の解析
## 解析環境
### 使用機材
* USBテスター WINGONEER TC66
https://www.amazon.co.jp/dp/B07T5KSSTC
* オシロスコープ RIGOL MSO1104Z
https://www.amazon.co.jp/dp/B011E8DXZA

### 観測風景
![1000006381.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/01a2421f-79b9-6624-a5ab-ce6e82b89eeb.jpeg)
そのままではオシロスコープの標準プローブは当てられないので、TC66実装部品のパッドから短い配線を引き出してプローブに引っ掛ける。測定箇所はシャント抵抗(15mΩ)の両端と、USBコネクタのCC信号。ケーブルによっては表裏依存があるので、信号の拾える向きに挿し直す必要あり。

シャント抵抗の両端から引き出すことで電流も測定しようと目論んだわけだが、電圧分解能が足らなくてまともに使えなかった…

## 停止再開ループの全体像
### 全体
![GgcGkkua8AEstST.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/24ca8b3f-adb6-54e3-6d5c-a9cd5c0aabe8.png)
充電電圧の変化の全体像。スマホ端(USBケーブルとスマホの間)での観測。横軸は1秒/マス目、全体で12秒。黄色の信号(1番)がVBUS電圧。ケーブルでの電圧降下が見えていて、充電器は9V(もしくはPPS制御により9V以上)を出しているはずだが、観測される電圧は9Vを割り込んでいる。

2秒前後の周期で充電停止再開ループが繰り返されている様子が見える。調子が良いときは9Vで安定するが、状況によっては9V出力が1秒も持たずにシャットダウンしてまた5V→9Vと変化を繰り返す(充電器を挿し直したのと同じ)。細かく見ると繰り返しの各回ごとに、持続時間や電圧とその変化など、色々と挙動が違う。

### 単回
![GgcGkksbUAAZJW0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/adc7f90e-9750-ed7b-2f1a-ec790694207a.png)
充電停止再開ループの中の1回の拡大。ピンク色の信号(3番)がUSB-PDのCC信号線。この信号で充電器とスマホが双方向に通信して充電電圧の変更などを行う。全体像のところでも説明したとおり単回の挙動は千差万別だが、ここでは説明しやすいような動作をしたものを代表例として示している。

最初(充電器を挿し直したのと同じ)は5Vが充電器から供給され、充電器とスマホがネゴシエーションなどを実施。電圧が緩やかに落ちていっていることからスマホ側が充電電流を徐々に増やしていっているのだと思われる。

その後しばらくしてスマホが充電器に9Vを要求し、そこから本格的な急速充電が始まる。その200msくらい後で電圧を上げる制御が入るが、その直後に突然のシャットダウンが発生する。

### 拡大
![1000006391.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/da053025-120b-861a-a8e6-c8706937d319.jpeg)
シャットダウン直前の拡大。CC信号を使ってPD通信している様子が見えるが、プロトコルアナライザ等は持っていないので通信内容は不明。

最初の2つの通信がスマホから充電器への電圧を上げる指示ではないかというのは想像がつく。その通信を受けて電圧が上がった後に何らかの通信が行われているが、その後30msくらいして突然のシャットダウンが発生。出力が0Vまで落とされている。

充電電圧を見る限りはおかしなことは無さそうなので、誰がシャットダウンのトリガを引いているかは謎…

# 原因の絞り込み
## PD通信の解析
PD通信を解析しないとどうしようもない感がでてきたが、解析しようにもPDプロトコルアナライザを持っていない。ただ、オシロスコープでどんどん波形を拡大していくと何となくシリアル通信っぽい波形は見えてくる。これなら何とかなりそう？

### 4B5B符号化とBMC変調
![1000006392.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/9fe0d85b-387f-4063-dbfc-00b3f8f6c0c7.jpeg)
色々ググっていくと、PD通信は4B5B符号化したデータ列を300kbpsのBMC (Biphase Mark Code)変調で送っているらしい。手始めに送信方向(スマホ⇔充電器)が入れ替わっているような場面(上記波形)を手動で復元してみると、元データ(シンボル)が見えてくる。

ちなみにUSB PD通信は1本の配線(CC信号)で双方向に行われているため、途中の波形を見るだけでは通信方向が分からない。そこを判断できるのは現状の観測環境だと波形の「綺麗さ」くらしかないが、ここで見ている波形はスマホ端での観測なので、波形の綺麗なほうがスマホ→充電器の向き、汚いほうが充電器→スマホの向きと思われる。

このあたりの低レイヤーの資料は、探した中ではROHM社の資料がいちばんわかりやすかった感。4B5B符号化やBMC変調の解説、その上にどうPD通信パケットが乗っかってるかがよく理解できた。
→https://www.rohm.co.jp/documents/11401/3642051/20150916_usbpd.pdf

### シャットダウントリガの発見
![1000006393.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/a7f561f0-24d0-7845-7c7c-cd222664e1f1.jpeg)
なにか謎事象が起きている場合はその時点から遡るという鉄則のもと、シャットダウン直前(約30ms前)で起きているPD通信を解析。

すると「Hardware Reset」を意味する特殊パケットを発見。この通信は充電器→スマホの向きで行われているため、明確に充電器側の意思をもってシャットダウンが行われていると推測される。充電器側が何らかの異常を検知しているのだと思われるが、何を検知したのかはまだ分からない…

### さらに通信を遡る
![GgffTIga8AUayEB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/a2026910-fe01-dc93-2ca1-8fc728191e86.png)
<details><summary>通信詳細(PDパケット解析)</summary>

```
recv -45570us           +--------header-------+ +---------------------CRC---------------------+
00011 00011 00011 10001 01110 01101 11011 01111 11011 00101 11010 11110 11010 10101 11110 01011 10110 0
+----------SOP--------+   6     A     D     0     D     2     5     7     5     3     7     C     T
Ext[15]:0(C/D) Num[14:12]:0 MsgID[11:9]:6 PRole[8]:1(src) Rev[7:6]:2 DRole[5]:1(DFP) Type[4:0]:0x06(PS_RDY)
send -45021us           +--------header-------+ +---------------------CRC---------------------+
00011 00011 00011 10001 10010 01010 01011 01111 01111 11001 01111 00101 11011 01111 10010 01101 10110 00
+----------SOP--------+   1     4     C     0     0     9     0     2     D     0     1     A     T
Ext[15]:0(C/D) Num[14:12]:0 MsgID[11:9]:6 PRole[8]:0(snk) Rev[7:6]:1 DRole[5]:0(UFP) Type[4:0]:0x01(GoodCRC)

recv -43960us (再送1)
00011 00011 00011 10001 01110 01101 11011 01111 11011 00101 11010 11110 11010 10101 11110 01011 10110 0
send -43411us (再ack)
00011 00011 00011 10001 10010 01010 01011 01111 01111 11001 01111 00101 11011 01111 10010 01101 10110 00

recv -42434us (再送2)
00011 00011 00011 10001 01110 01101 11011 01111 11011 00101 11010 11110 11010 10101 11110 01011 10110 0
send -41885us (再ack)
00011 00011 00011 10001 10010 01010 01011 01111 01111 11001 01111 00101 11011 01111 10010 01101 10110 00

recv -*****us           +--------header-------+ +---------------------CRC---------------------+
00011 00011 00011 10001 11011 01101 10010 01111 11011 01011 01111 00111 11110 11110 11011 00101 10110 00
+----------SOP--------+   D     A     1     0     D     C     0     E     7     7     D     2     T
Ext[15]:0(C/D) Num[14:12]:0 MsgID[11:9]:0 PRole[8]:1(src) Rev[7:6]:2 DRole[5]:1(DFP) Type[4:0]:0x0D(Soft_Reset)
send -36898us           +--------header-------+ +---------------------CRC---------------------+
00011 00011 00011 10001 10010 01010 01111 01111 11101 11101 01011 01110 11101 11101 01001 01101 10110 00
+----------SOP--------+   1     4     0     0     B     B     C     6     B     B     8     A     T
Ext[15]:0(C/D) Num[14:12]:0 MsgID[11:9]:0 PRole[8]:0(snk) Rev[7:6]:1 DRole[5]:0(UFP) Type[4:0]:0x01(GoodCRC)

recv -35889us (再送1)
00011 00011 00011 10001 11011 01101 10010 01111 11011 01011 01111 00111 11110 11110 11011 00101 10110 00
send -35340us (再ack)
00011 00011 00011 10001 10010 01010 01111 01111 11101 11101 01011 01110 11101 11101 01001 01101 10110 00

recv -34290us (再送2)
00011 00011 00011 10001 11011 01101 10010 01111 11011 01011 01111 00111 11110 11110 11011 00101 10110 00
send -33742us (再ack)
00011 00011 00011 10001 10010 01010 01111 01111 11101 11101 01011 01110 11101 11101 01001 01101 10110 00


send -32304us           +--------header-------+ +---------------------CRC---------------------+
00011 00011 00011 10001 10101 01010 01111 01111 11110 11110 11001 11011 11110 11110 10010 11010 10110 00
+----------SOP--------+   3     4     0     0     7     7     9     D     7     7     1     5     T
Ext[15]:0(C/D) Num[14:12]:0 MsgID[11:9]:0 PRole[8]:0(snk) Rev[7:6]:1 DRole[5]:0(UFP) Type[4:0]:0x03(Accept)
recv -31663us           +--------header-------+ +---------------------CRC---------------------+
00011 00011 00011 10001 10010 01101 10010 01111 10010 01011 10111 01101 00101 01011 10010 01001 10110 0
+----------SOP--------+   1     A     1     0     1     C     F     A     2     C     1     8     T
Ext[15]:0(C/D) Num[14:12]:0 MsgID[11:9]:0 PRole[8]:1(src) Rev[7:6]:2 DRole[5]:1(DFP) Type[4:0]:0x01(GoodCRC)

recv -30535us
11100 11100 11100 10011 0
  R     R     R     S    -> Hardware Reset
```
</details>

この波形に見えている中では、最初の一群が充電器→スマホ向きのPS_RDYコマンドと、その応答(GoodCRC)。本波形よりも前にスマホから送られた電圧変更コマンドに対して電圧変更が完了したという通知(PS_RDY)であり、ここまでは特におかしいことはない。ただし規格上は1回で良いはずなのになぜか3回繰り返されていて、再送が起こっていると思われる[^1]。
[^1]:この時点では再送が怪しいと気付いていない

この4msくらい後で起きているのが、充電器→スマホ向きのSoft_Resetコマンドと、その応答(GoodCRC)。この辺りから気配が怪しくなってきて、シャットダウンへと進路が切られて行っている感。ただしPS_RDYとこのSoft_Resetの間には何も気になる動きは無いので、いったい何がどうなって充電器がSoft_Resetを出すに至ったのかは謎。

その後、スマホ→充電器向きのAcceptコマンドとその応答(GoodCRC)があり、スマホはSoft_Resetコマンドを受け入れたと通知。そしてその直後、最後のパケットが上で説明したHardware Resetコマンドであり、この30ms後にシャットダウン。

状況から見てPS_RDYとSoft_Resetの間に何かが起きていると思われるものの、何が起きてるんだろう…

## PDOなどを確認
なにか充電器側がトリガを引くなら、過電流検知か何かだろうと想像して少し追っかけ。まずはSource_Capabilitiesの結果＠Anker Nano II 65W (発症するタイプ)。e-Marker無しのケーブルなので電流は3Aでリミットがかかっている。

|No.|タイプ|Limit|最大電圧|最小電圧|最大電流|
|:-:|:----:|:---:|:------:|:------:|:------:|
| 1 | 固定 |  -  |  5.00V |    -   |  3.00A |
| 2 | 固定 |  -  |  9.00V |    -   |  3.00A |
| 3 | 固定 |  -  | 15.00V |    -   |  3.00A |
| 4 | 固定 |  -  | 20.00V |    -   |  3.00A |
| 5 | PPS  | あり| 21.00V |  5.00V |  3.00A |

またスマホがRequestコマンドで要求する電力(RDO)をいくつか抜粋。固定PDOで対応できるものであっても、PPSで要求しているようだ。いずれも電流は3.00Aで固定。

|PDO番号| EPR|要求電圧|要求電流|
|:-----:|:--:|:------:|:------:|
|   5   | 無 |  5.00V |  3.00A |
|   5   | 無 |  8.70V |  3.00A |
|   5   | 無 |  9.46V |  3.00A |

ここで3.00A未満の電流を要求して過電流検出がかかっているのではないかと疑ったのだが、実測でも最大2.8A程度しか流れていないようなので、この説は原因ではなさそうだ。ますますの謎。

<details><summary>PDO/RDO詳細(PDパケット解析)</summary>

```
recv +245644us          +--------header-------+ +--------------------PDO_1--------------------+ +--------------------PDO_2--------------------+
00011 00011 00011 10001 10010 01101 10010 11010 01011 00101 10010 11001 10010 01111 01001 01111 01011 00101 10010 11011 00101 01111 01111 01111
+---------SOP---------+   1     A     1     5     C     2     1     9     1     0     8     0     C     2     1     D     2     0     0     0
Ext[15]:0(C/D) Num[14:12]:5 MsgID[11:9]:0 PRole[8]:1(src) Rev[7:6]:2 DRole[5]:1(DFP) Type[4:0]:0x01(Src_Capa)
<PDO_1> Type[31:30]:0(Fixed) ... Ext[27]:1 ... Peak[21:20]:0 Vol[19:10]:0x064(5.00V) Cur[9:0]:0x12C(3.00A)
<PDO_2> TYpe[31:30]:0(Fixed) ... Ext[27]:0 ... Peak[21:20]:0 Vol[19:10]:0x0B4(9.00V) Cur[9:0]:0x12C(3.00A)
+--------------------PDO_3--------------------+ +--------------------PDO_4--------------------+ +--------------------PDO_5--------------------+
01011 00101 10010 11101 01010 01111 01111 01111 01011 00101 10010 01010 01110 01111 01111 01111 01011 10101 00101 10101 01010 01101 11001 01011
  C     2     1     B     4     0     0     0     C     2     1     4     6     0     0     0     C     3     2     3     4     A     9     C
<PDO_3> Type[31:30]:0(Fixed) ... Ext[27]:0 ... Peak[21:20]:0 Vol[19:10]:0x12C(15.0V) Cur[9:0]:0x12C(3.00A)
<PDO_4> Type[31:30]:0(Fixed) ... Ext[27]:0 ... Peak[21:20]:0 Vol[19:10]:0x190(20.0V) Cur[9:0]:0x12C(3.00A)
<PDO_5> Type[31:30]:3(APDO) [29:28]:0(PPS) Lim[27]:1 Max[24:17]:0xD2(21.0V) Min[15:8]:0x32(5.00V) Cur[6:0]:0x3C(3.00A)
+---------------------CRC---------------------+
01011 11011 01110 01001 11101 00111 11101 01010 10110 00
  C     D     6     8     B     E     B     4     T
send +246885us          +--------header-------+ +---------------------CRC---------------------+
00011 00011 00011 10001 10010 01010 01111 01111 11101 11101 01011 01110 11101 11101 01001 01101 10110 00
+---------SOP---------+   1     4     0     0     B     B     C     6     B     B     8     A     T
Ext[15]:0(C/D) Num[14:12]:0 MsgID[11:9]:0 PRole[8]:0(snk) Rev[7:6]:1 DRole[5]:0(UFP) Type[4:0]:0x01(GoodCRC)
send +248162us          +--------header-------+ +---------------------RDO---------------------+ +---------------------CRC---------------------+
00011 00011 00011 10001 00101 01001 01111 10010 01011 10101 01010 10111 10010 01111 10101 11010 01001 00111 00111 00101 10101 10010 10010 01110 10110 0
+---------SOP---------+   2     8     0     1     C     3     4     F     1     0     3     5     8     E     E     2     3     1     1     6     T
Ext[15]:0(C/D) Num[14:12]:1 MsgID[11:9]:0 PRole[8]:0(snk) Rev[7:6]:2 DRole[5]:0(UFP) Type[4:0]:0x02(Request)
Pos[31:28]:0x5 Miss[26]:0 Comm[25]:1 nSus[24]:1 UnC[23]:0 EPR[22]:0 Vol[20:9]:0x0FA(5.00V) Cur[6:0]:0x3C(3.00A)
recv +248933us          +--------header-------+ +---------------------CRC---------------------+
00011 00011 00011 10001 10010 01101 10010 01111 10010 01011 10111 01101 00101 01011 10010 01001 10110 0
+---------SOP---------+   1     A     1     0     1     C     F     A     2     C     1     8     T
Ext[15]:0(C/D) Num[14:12]:0 MsgID[11:9]:0 PRole[8]:1(src) Rev[7:6]:2 DRole[5]:1(DFP) Type[4:0]:0x01(GoodCRC)
```
</details>

# ひとまず原因判明

## 改めて考えてみる

ここまでのところ、何かの異常を検知して充電器側がシャットダウンを発動しているというところまでは追い込めてはきたが、「何かの異常」というものが見つけられずにいる。

ここで色々なオシロ波形を見直してみて、あることに気付く。シャットダウンの前にはPDパケットの再送が存在するようだ。この再送、おそらくはPD通信で起きている通信異常が原因である可能性が高そうだ。

USB PD規格書を読み解いてみると、
1. コマンドを送ったのにGoodCRCを受信できていない状態をカウント
2. 3回までは再送を実施するが、それでもだめならSoft_Resetコマンドを発行
3. Soft_Resetコマンドの発行に対するGoodCRCを受け取れなかったらHard Resetを発行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/6a5fbfa6-ee96-9f9e-b15d-6e13df53238d.png)
という流れが記載されており、スマホが送ったPDパケットを充電器側が受け取れていないとすると状況と辻褄が合う。

PD通信は基本的には、送信側からのコマンド(仕様書の文言では"メッセージ")と受信側からの応答(GoodCRC)[^2]が1セットとなって行われている。ということで、方向別に再送(通信異常)時の様子を見てみる。
[^2]:パケットの構造的には応答もコマンドの一種(GoodCRCコマンド)ではあるがここでは区別して扱う。

#### スマホからの応答(GoodCRC)が充電器で受け取れていない例
今までの説明で使った例はすべてこのパターンに該当。

充電器がスマホにコマンドを送り、スマホは受け取って応答(GoodCRC)を返すが充電器側がそれを受け取れず、充電器は追加で2回ほどコマンドを再送。それでも応答を受け取れずSoft_Resetシーケンスに移行しているパターンが多い。

#### スマホ発のコマンドが充電器で受け取れていない例
![GggbivBa8AAT3kV.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/1fb9a079-0ca6-9e9d-3a76-ec522974cb4a.png)
発生頻度が低いようで発見しづらかったが、スマホが発行したコマンド本体を充電器が受け取れなかった事例も。この場合は2回失敗するも3回目に受信が成功したようで、その後は正常動作に復帰した模様。

## 別パターン
Hard Resetコマンドは充電器→スマホ向きに発生する動作ばかり観測してきたが、たまたまスマホが発行する場面も捕えられたので波形を取って通信を解析。

![GgrXwnNawAALSzJ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/8e6fbcde-c46f-f564-cd1d-2658fe5693d3.png)

①の電圧変更要求後、②のAccept応答で通信エラーとなり充電器側がSoft_Reset対応に移るが、その後③のSoft_Reset～Acceptの流れはたまたま通信エラーなく通ったので通常のSoft_Resetのシーケンスを踏み始める。しかしその後④のSource_Capabilitiesコマンドでまた通信エラーとなり、結果的にスマホ→充電器向きにHard Resetが打たれている。この部分の機序がよく分からないが、Source_Capabilitiesを何度も送ってくる＝異常判定ってことか？

通信エラーが出たり出なかったりのタイミングが絶妙に変わらないと発生しないと思われるので、なかなか珍しいパターンではないかと思われる。しかもそれをオシロスコープで拾えたのは奇跡的かもしれない。

## ここまでで絞り込まれた原因
:::note warn
スマホ→充電器のPD通信(CC信号)で通信異常が発生している
:::

# さらに原因を深堀り
## 波形品質を疑う
通信異常が発生しているということは、何か通信線(CC信号)がおかしなことになっている可能性が濃厚。さらに充電器が信号受信する際に発生することから、オシロスコープで信号を観測するポイントをスマホ端ではなく充電器に変更して計測。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/259020af-93b1-2b7b-9c42-e3920b7f4887.png)

CC信号は1.125V(±0.075V)の振幅と規定されているので、単純計算ではスレッショルド電圧(デジタル信号を0/1の値として判定する電圧)は562.5mVとなる(ただしオシロスコープでは細かく指定できなかったので560mVで表示)。見るからにマージン(余裕)が減ってギリギリの判定ラインになっているのが見える。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/cc2d7dfa-4665-196d-fdc2-b2ffeac5e33d.png)

さらにCC信号のみを拡大。ここまで浮き上がっているとスレッショルドの判定は余裕でミスりそうだ。また信号の反射などでは説明しにくい揺らぎがあるが、恐らく電源線(VBUS-GND)のノイズを受けてしまっていると思われる。

実はここまで提示している波形でも信号の浮き上がり(スマホ端で見るとズレ方向が逆になるので沈み込み)は見えていたのだが、通信異常の原因とは思ってなくて無視してたのはトラブルシューティング的には失敗。

## 規格ではどうなっているか
### 信号受信側
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/9de17b6b-4867-b4a4-eae4-b196a883a980.png)
充電器は"Sourcing Power"なので、受信スレッショルドは0.6875V、信号0判定上限は0.4825Vということになる。…上のオシロスコープ波形を見る限りでは規格違反の信号となっている模様。

:::note warn
充電器が受け取るCC信号のレベルが規格違反となっている
:::

### ケーブル側
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/bf6cb0f7-bc1d-2d46-b500-ed3186bdbe77.png)
測定しているのはコネクタとケーブルの間(図ではRcontactとRcableの間)なので数字が少し変わってくると思うが、GND側は375mVの浮きは許容される規格となっている。

今回のケーブル(VBUS-GNDの合算抵抗が250mΩ、片側125mΩと推定)に2.8A流れた場合の片側の電位差は350mVということになりそうだが、オシロスコープ観測波形では400～500mVはありそうな感じ。精密な測定は難しいので、こちらは規格違反かどうかの判定は保留。

##### 2025/01/12 11:25追記
USB PD規格において別途BMC受信時のGND電位差について250mVとする規定があった。この記述からすると明らかに規格違反のようだ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/651f4b23-8ce0-98c8-1263-76eeefd0b8b2.png)

# 推測した原因の妥当性確認

原因が上で推測した通りであるなら、その原因を排除したら正常動作するはずである。その確認を実施。

### ケーブル抵抗を下げる
![GgsrNhjaQAAkF8Y.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/d4c113eb-bd25-7ce1-c367-5ddfc8d8ba62.png)
* 内部抵抗高めのケーブル(症状発生): VBUS-GND抵抗 推定250mΩ
* 内部抵抗低めのケーブル(正常動作): VBUS-GND抵抗 推定100mΩ

ケーブル抵抗を下げることで充電器～スマホ間のGND電位差が小さくなり、CC信号レベルの浮き上がりも小さくなって通信失敗しなくなる。

### 電圧降下への耐性を上げる(想像)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981018/970a1380-87ca-db71-d4e5-417c41f8a2ce.png)
* 充電器A(症状発生): Anker Nano II 65W
* 充電器B(正常動作): Anker PowerPort III 3-Port 65W Pod

充電器端での信号品質(CC信号レベルの浮きっぷり)は変わらないように見えるが、症状発生の有無は明確に分かれる。

# 結局なにが悪かったのか

### 充電器
* ケーブルでの電圧降下が原因でCC信号の電圧レベルが浮き上がってしまうと、スマホ→充電器の向きの通信を正常に受信できない。

* 本件発症時に充電器に届いているCC信号は、USB PD規格で規定されているスレッショルドや0/1判定レベルに対して恐らく規格違反となっているが、充電器によっては正常に受信できている。発症してしまう充電器はこの信号レベル浮きに対する耐性が低いのではないかと思われる。

### ケーブル
* 責任100%ではないが相対的には本件の主犯。ケーブル抵抗(とくにGND側)の高さがPD通信不良を誘発し、最終的にはシャットダウンに至ると推察される。またケーブル内でVBUSやGND線のノイズがCC信号に誘導されているようにも見える。

* 本件発症してしまうケーブル(VBUS-GNDの合算抵抗が250mΩ、片側125mΩと推定)も、3A流した際の電位差が375mVであり規格(375mV以下)ぴったりではあるが、抵抗値は低いに越したことはない。推定抵抗100mΩのケーブルでは症状は発生しなかったため、この説を裏付ける実験結果となっている。

### スマホ
* PD通信不良からのシャットダウン事象について、最初にUSB接続した際に一度だけ発生してしまうことについては仕方がないと思うところ。ただ、その後の充電停止再開ループを止められるのはスマホだけなので(スマホから給電要求があったら充電器は従うしかない)、そこを止められないのは惜しい。原因とまでは言い切れない感じだが…

# どうなればよい？(提案)

### 充電器
* VBUS-GNDの電圧降下に応じてCC信号のスレッショルドを変化させる
(おそらく気の利いた設計ではすでにそうなっている)
* スイッチングノイズ低減

### ケーブル
* とにかく電源(VBUS-GND)の抵抗値を下げる。ただし低抵抗なケーブルは太くなって取り回しに難が出てくるので、利便性を取るか性能を取るかで難しい…

### スマホ
* おそらく内部的にはケーブルでの電圧降下を推定するような動作を行っているように見える。電圧降下が一定基準(GND側で200mVとか; 規格上は375mV)を超えないように電流を抑制する。

* USBケーブルを接続したままでのシャットダウンが数回連続したらフォールバックしてセーフモード充電(例えば5V1A)にする。

# まとめ
当初は相性問題として雑に納得しようとしていた、スマホUSB充電時の停止再開ループの原因を探り当てることが出来た。結果として試行錯誤的に行き着いていた対処法と何ら変わることは無かったが、原因が分かっているか否かというのは気持ち的には大きく違う。

またオシロスコープしか機材が無い中でPD通信のプロトコル解析を行うことで、難解なUSB PD規格に対する理解を深めることが出来た。

# 追記
PDコントローラICについて少しだけ追加調査しました。

https://qiita.com/tzyk/items/3a0d41cf2e30d0028d15

# 参考
## 規格など
BMC変調など
https://www.rohm.co.jp/documents/11401/3642051/20150916_usbpd.pdf
4B5B符号化
https://ja.wikipedia.org/wiki/4B5B%E7%AC%A6%E5%8F%B7%E5%8C%96
USB PD規格の総本山
https://www.usb.org/document-library/usb-power-delivery