---
date: 2025-11-02
task: ESP32ファームウェア書き込みエラーのトラブルシューティング
outcome: completed
---

# Progress Log: ESP32 フラッシュ書き込みエラーの解決

## Task Description

OSECHI検出器のESP32へのファームウェア書き込み時に以下のエラーが発生：

```
TypeError: argument of type 'NoneType' is not iterable
WARNING: Failed to communicate with the flash chip
Packet content transfer stopped
```

Arduino IDEからの書き込みが繰り返し失敗し、フラッシュチップとの通信ができない状態だった。

## Outcome

**根本原因**: OSECHIの電源スイッチがOFFだったため、ESP32に正常な電源が供給されず、GPIO12がフローティング状態になっていた。

**解決策**: スイッチをONにすることで、フラッシュ電圧が1.8Vから3.3Vに正常化し、書き込みが成功。

## Learnings

### 1. ESP32フラッシュ電圧の判定メカニズム

ESP32は起動時に**GPIO12 (MTDI)**のレベルでフラッシュ電圧を判定：

```
GPIO12 = LOW (GND)       → 3.3V フラッシュ（標準）
GPIO12 = HIGH (3.3V)     → 1.8V フラッシュ（特殊）
GPIO12 = フローティング    → 不定（エラーの原因）
```

スイッチOFF状態ではGPIO12が不安定になり、誤って1.8V判定されていた。

### 2. 診断に有効だったコマンド

```bash
# フラッシュ情報の取得
python3 -m esptool --port /dev/cu.usbserial-110 --baud 115200 flash_id
```

**正常時の出力**:

```
Manufacturer: 20 (XMC)
Device: 4017
Detected flash size: 8MB
Flash voltage: 3.3V
```

**異常時の出力**:

```
Manufacturer: ff
Device: ffff
Detected flash size: Unknown
Flash voltage: 1.8V
```

`ff/ffff`という値は、フラッシュチップと通信できていないことを示す重要な指標。

### 3. ESP32-D0WD-V3のフラッシュ仕様

検出されたチップ情報：

- **Chip**: ESP32-D0WD-V3 (revision v3.1)
- **Flash**: XMC 8MB (Manufacturer: 20, Device: 4017)
- **Crystal**: 40MHz
- **Features**: Wi-Fi, BT, Dual Core, 240MHz

### 4. 確認済みの書き込み設定（Arduino IDE）

```
Board: ESP32 Dev Module
Upload Speed: 115200
Flash Mode: QIO / DIO  ← どちらでも書き込み成功
Flash Size: 8MB (64Mb)  ← 重要！4MBではない
Flash Frequency: 40MHz
```

**確認結果**: スイッチONの状態であれば、QIOモードでもDIOモードでも書き込みが成功する。Flash Modeの選択は問題の原因ではなかった。

### 5. Flash ModeによるGPIOピン使用の違い

**QIO (Quad I/O)**:

- データ線: 4本 (IO0, IO1, IO2, IO3)
- 最速だが、外部ハードウェアと干渉しやすい

**DIO (Dual I/O)**:

- データ線: 2本 (IO0, IO1)
- QIOより遅いが、安定性と互換性が高い

OSECHI検出器のように外部センサーを接続する場合、**DIOモードが推奨**。

### 6. 書き込み時に重要なGPIOピン

以下のピンは書き込み時に特別な役割を持つため、外部回路と干渉しやすい:

- **GPIO0**: ブートモード選択（BOOT ボタン）
- **GPIO2**: フラッシュデータ（QIO/QOUTモード時）
- **GPIO12 (MTDI)**: フラッシュ電圧選択
- **GPIO15 (MTDO)**: ブートメッセージ制御

これらのピンを使用する場合、プルダウン/プルアップ抵抗の追加が必要。

## Next Steps

### データ取得の開始

ファームウェアが正常に書き込まれたので、データ取得を開始できる：

```bash
# シリアルポート確認
haniwers-v1 port list

# データ受信テスト
haniwers-v1 port test /dev/cu.usbserial-110

# データ取得開始
haniwers-v1 daq --config examples/daq.toml
```

### ドキュメント化の候補

このトラブルシューティング経験を以下のドキュメントに反映することを検討：

1. **`docs/users/`**: ユーザー向けトラブルシューティングガイド
   - ESP32書き込みエラーの一般的な原因と解決策
   - OSECHI電源スイッチの重要性

2. **`docs/developers/faq.md`**: 開発者向けFAQ
   - ESP32フラッシュ診断方法（`esptool flash_id`の使い方）
   - GPIO12とフラッシュ電圧の関係
   - Flash Mode（QIO vs DIO）の選択基準

3. **CLAUDE.md**: AI Agent向けガイド
   - ESP32書き込みエラーのチェックリスト追加
   - `esptool`診断コマンドの推奨

### 今後の予防策

**ファームウェア書き込み手順（チェックリスト）**:

- [ ] OSECHIの電源スイッチをONにする
- [ ] USB-Cケーブルで接続（データ転送対応ケーブル）
- [ ] Arduino IDEのボード設定を確認
  - [ ] Flash Size: 8MB (64Mb)
  - [ ] Flash Mode: DIO
  - [ ] Upload Speed: 115200
- [ ] 書き込み実行
- [ ] シリアルモニターでデータ受信確認

---

## 参考情報

### esptoolコマンド例

```bash
# 仮想環境にesptoolをインストール
$ uv venv /tmp/test-esp32/
$ source /tmp/test-esp32/bin/activate.fish
(test-esp32) $ uv pip install esptool


# フラッシュ情報取得
(test-esp32) $ uv run python3 -m esptool --port /dev/cu.usbserial-110 --baud 115200 flash-id

# チップ情報取得
(test-esp32) $ uv run python3 -m esptool --port /dev/cu.usbserial-110 --baud 115200 chip-id

# efuse確認
(test-esp32) uv run python3 -m esptool --port /dev/cu.usbserial-110 --baud 115200 summary
```

### haniwers CLIによるポート管理

```bash
# ポート一覧表示
haniwers-v1 port list

# ポート接続テスト（5秒タイムアウト）
haniwers-v1 port test /dev/cu.usbserial-110

# ESP32診断（esptool統合）
haniwers-v1 port diagnose /dev/cu.usbserial-110

# Flash情報のみ表示
haniwers-v1 port diagnose /dev/cu.usbserial-110 --flash-id

# Chip情報のみ表示
haniwers-v1 port diagnose /dev/cu.usbserial-110 --chip-id
```

**新機能**: `port diagnose`コマンドがesptoolを直接ラップし、フラッシュ診断を簡単に実行できるようになった。異常値（`ff/ffff`, `1.8V`）を自動検出し、対処法を提案する。

### 関連ドキュメント

- ESP32 Technical Reference Manual: GPIO12によるフラッシュ電圧選択
- esptool documentation: フラッシュ診断コマンド
- Arduino ESP32 documentation: ボード設定とFlash Mode
