ESP32のPartition Tableの書き方

# ESP32のパーティションテーブル(Partition Table)
ESP32のフラッシュメモリを効果的に使うために、アドレスとサイズを指定したブロックを定義し、機能を割りあてることができる。
その指定をするファイルがパーティションテーブル(Partition Table)というもの。

公式ガイド
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/partition-tables.html

パーティションテーブルは目的別にいくつか用意されているので、目的にあったものを使うか、あるいは自分で新しいものを作成して使うこともできる。

## 既存パーティションテーブルの選び方
既存データのうち4Mタイプはつぎのものが提供されている。用途にあわせて選ぶ。

| filename   | プログラム|OTA|ストレージ| |
|-|-:|:-:|-:|-|
| default.csv| 1.2M|あり|1.4M|デフォルト|
|default_ffat.csv|1.2M|あり|1.4M(ffat)|ffatを使いたい時|
|huge_app.csv|3.0M|なし|960K|巨大なアプリを書きたい時|
|min_spiffs.csv|1.8M|あり|192K|OTAは使いたいが、もう少し大きなアプリを書きたい時|
|no_ota.csv|2M|なし|1.9M|OTAを使う予定がない時|

default.csvで問題になるケースはそれほどないだろう。

OTA(Over the Air)は、WiFi経由でプログラムの書き込みを行う機能。
IDEからWiFiで書き込みしたり、外部のWebサーバーにあるコンパイル済みバイナリーをプログラム上からダウンロードして書き込む、いわゆるオンラインアップデート機能を実装するなどができる。
プログラムの書き込みミスなどに以前のバージョンに復帰あせるため、プログラム領域を最低２つ用意するので、プログラム領域が半分になる。
OTAを使うケースはそれほど多くないと思うので、少しプログラムが大きくなった場合に、no_otaを選択するのはいい選択だと思う。

## Windows/Arduino環境下でのパーティションテーブル
WindowsでArduino(ArduinoIDE/PlatformIO)では、下記にパーティションテーブルがある。

* (Windows User Home)\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.4\tools\partitions\
* (Windows User Home)\.platformio\packages\framework-arduinoespressif32\tools\partitions\

# パーティションテーブルの書き方

### 例 (デフォルトで使われるもの)
```default.csv
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x5000,
otadata,  data, ota,     0xe000,  0x2000,
app0,     app,  ota_0,   0x10000, 0x140000,
app1,     app,  ota_1,   0x150000,0x140000,
spiffs,   data, spiffs,  0x290000,0x170000,
```

* テキストファイルで、フォーマットはcsv形式。
* １行ごとに Name,Type,SubType,開始アドレス,大きさ,フラグ を書く
* 行頭# はコメント

### Name
パーティションにつける任意の名前(Partition Label)。
最大16byte(NULLを含むので15文字)を超えて指定すると切り捨てられる。

### Type
0～254までの数値か、予約文字列'app' (数値では0)、'data' (1)を指定する。0～63は予約されているので使用しないこと。

### SubType
パーティションの使い方の詳細指定。
Typeが 'app' の時、SubTypeは 'factory'(0x00),'ota_0'～'ota_15'(0x10～0x1f),'test'(0x20)のどれか。

### Offset
開始アドレス。
10進数か16進数(0xを頭につける)で指定。4K とか 1M の様な単位をつけた記述も可能。
Type=app のパーティションは64K(0x10000）アラインメントが必要。
前に行がある場合、省略できる。省略すると、前の行のOffset+Sizeを64Kアラインメントした値になる。

### Size
サイズ
10進数か16進数(0xを頭につける)で指定。4K とか 1M の様な単位をつけた記述も可能。

### Flags
encrypted を指定するとその領域は暗号化の対象になる。Type='app'の領域はFlagsに限らず常に暗号化される。

## SubType 詳細
### nvs (subtype=data)
nvsはNon-Volatile Storageの略で、キーバリュー（名前と値）式のデータ保存領域。
nvsライブラリでアプリケーションから読み書きが可能。
システムでも使用しており、しかもあまり削除はされないため、いろいろなアプリケーションで同じデバイスを使いまわししていると、沢山のデータが書き込まれたままになっていることもあるので、注意。

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/storage/nvs_flash.html

下記に拠れば現在はnvs自体の暗号化はflagsに書けばいいというわけではないようだ。暗号化のためには専用のライブラリと、この後のnvs_keys領域を flags=encrypted で用意する必要がある。
（利用にはESP-IDFが必要）

https://dev.to/kkentzo/how-to-encrypt-the-nvs-volume-on-the-esp32-4n9k

### nvs_keys (data)
nvsを暗号化する時に使う。Size=4K,Flags=encrypted にしなくてはならない。

### ota (data)
OTA機能 (Over The Air Updates/Wifi経由のアップデート) で必要なパーティション。サイズは2K
内部的には1Kを2つとして利用しており書き込みが成功した場合に後で書き込んだほうを利用している。
OTAで書き込まれたパーティションのうち、どれを起動するか、などの情報が書かれている。

### phy (data)
PHY (PHYsical layer:物理レイヤ)、つまり通信関係の初期化データ。
デフォルトのコンパイルオプションでは、このPHYデータはアプリ自体に格納されれるので、別に用意する必要はない。
国ごとの利用可能な周波数（チャンネル）や電波強度などの情報を設定している。

### spiffs (data)
SPIFFS用の領域。Nameは任意でよいが、'spiffs'が無難。

### fat (data)
FFATファイルシステム用の領域。Nameは'ffat'を推奨（F_FAT.begin()のデフォルト値）

### littlefs (data)
LittleFS用の領域。Nameは'spiffs'を推奨(LittleFSFS.begin()のデフォルト値）

### coredump (data)
致命的なエラー発生時に、ソフトウエア状態情報を保存する領域。
このタイプのパーティションを見つけると、システムが自動的に保存を行う。

### factory (subtype=app)
デフォルトのアプリケーションの設置場所。OTAパーティション（この後に説明する）が無いか、書き込みを失敗したなど、OTAパーティションが起動できない場合に利用される。
逆にいえば、OTAがある場合は省略してもいい。
OTAでのアプリケーション更新処理はこのパーティションを上書きすることはない。

### ota_0～15 (app)
OTAでのアプリケーション書き込みの対象となるパーティション。OTAでは現在実行中のアプリケーションが書き込まれているOTAパーティション以外のOTAパーティションに書き込みを行う。もし、OTAパーティションが１つしかない場合はOTAアップデートは失敗する。つまり、OTAアップデートには最低２つのパーティションが必要となる。OTAアップデートが成功すれば最後に書き込まれたOTAパーティションが有効となり、リセット後に実行される。
アプリケーション上から１世代前にロールバック（巻き戻し）することも可能。

### test (app)
'factory'や'OTA_0'など、他のすべてのappパーティションの起動ができない場合に実行されるアプリケーション。
または CONFIG_BOOTLOADER_APP_TEST を有効にしてコンパイルしたアプリケーションでは、起動時にGPIOをLOWにすると起動させることもできる。
その名のとおり、主にテスト用。
(ESP-IDF必須)

## 補足：SubType=0x99(eeprom)パーティションについて
いくつかの資料で SubType=0x99の'eeprom'という名前のパーティションが必要と書かれているが、現在はeepromはnvs領域を使うように変更されたため不要。
そのままでも動作上は問題ないと思うが、単に使われない領域になるので削除したほうが良いだろう。

https://github.com/espressif/arduino-esp32/commits/master/tools/partitions/default.csv

## 補足2：spiffs/ffat/littlefsのNameの推奨値について
各FSがmountするパーティションは、.begin() の第４パラメータでパーティションNameで指定できるが、それぞれのFSごとに第４パラメータの省略時の規定値と、省略された時にアクセスされる領域名が違うので注意。

| FS | subtype |beginの規定値|規定値時の参照先|
|:-:|:-:|:-:|:-:|
|SPIFFSFS|spiffs|NULL|(最初に見つけたsubtype=spiffs)|
|LittleFSFS|littlefs|'spiffs'|'spiffs'|
|F_FAT|fat|'ffat'|'ffat'|

SPIFFS.begin()のデフォルト値はNULLとなっており、その場合はsubtypeがspiffsのパーティションのうち最初に見つかったものをmountしている。
LittleFSのbegin()のデフォルト値は'spiffs'なので注意。
https://docs.espressif.com/projects/esp-idf/en/v3.3/api-reference/storage/spiffs.html


## 独自パーティションテーブルの作り方
nvs,otadataはそのまま。0x10000からの3Mをの割り振りを自分の利用方法に合わせて最適な記述をすると、無駄なくメモリを活用できる。
例えば、OTAを使わず、spiffsをなるべく大きくするなど。

``` no_ota_huge_spiffs.csv
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,      0x09000,   0x5000,
otadata,  data, ota,      0x0e000,   0x2000,
app0,     app,  ota_0,   0x010000, 0x100000,
spiffs,   data, spiffs,  0x110000, 0x2F0000,
```