分区表
文章目录
- 分区表
- 1. esp32 flash结构
- 1.1 flash 物理组成
- 1.2 flash 内部结构
- 1.3 esp32启动过程
- 2. 分区表
- 2.1 分区表的组成
- 2.2 分区表的定义
- 2.2.1 Name字段
- 2.2.2 Type字段
- 2.2.3 SubType字段
- 2.2.4 offset和size
- 2.2.5 flags
- 2.3 系统分区表的查看
- 2.4 分区表的更换
- 2.4.1 使用内置分区表
- 2.4.2 使用自定义的分区表
- 3. 参考资料
1. esp32 flash结构
1.1 flash 物理组成
esp32的falsh可以分为三部分:
- 内部flash: 内部flash是esp32芯片自带的flash,空间大小是448k
- 主系统falsh: 一般esp32模组都带了一个flash芯片作为主系统flash,通过spi总线进行访问。这个主falsh芯片是用来存放系统数据、代码等东西的,如wroom模组上带了4M的主系统flash。不过,esp32 configmenu默认设置主系统flash是2M,需要手动进行调整,最大可以达到16M。主系统flash芯片一般来说是必须的。
- 外部flash: 除了主系统flash外,还可以通过spi的其他总线扩展外部flash。这个flash如果有需要,可以自己增加。
1.2 flash 内部结构
flash从结构上来看,包括BootLoader、分区表和用户数据(包括代码和存储数据)三部分。
比如我们看下面实际的一张flash内存表
flash从0x8000以前的区域,都是bootloader,用于esp32的启动
flash在0x8000处烧写一张分区表(partition Table),该分区长度为0xC00字节,最多可以保存95条分区表条目。分区表定义了后面数据段的用途
分区表后面的数据都属于用户数据,用来存放用户的代码和数据。该部分具体包含什么功能区,由分区表决定。可能包含以下内容:
- Factory: 属于代码区域(app)。存放的是从串口下载来的固件程序。
- OTA_0-15:属于代码区域(app)。该区域存放的是通过隔空下载的方式存储的程序。使用OTA下载功能,flash中至少开辟两个OTA区域(比如OTA_0和OTA_1)。因为OTA下载的时候,不会修改factory区域中的代码,而是将代码在OTA_0和OTA_1之间交替烧写。在没有OTA区域的时候,程序会执行factory区域的代码,有了OTA之后,会使用OTA的代码,通过OTA data区域来确定从哪个区域加载代码。
- NVS: 属于数据区域(data)。数据以键值对的方式在这段空间进行存储。如果启动了wifi功能,wifi的数据会存储在这个地方。用户也可自己存储键值对类型的数据
- OTA data: 属于数据区域(data)。存放的是与OTA功能有关的数据,比如记录这次烧写的是哪个OTA,下次往哪个OTA烧写。
- Phy data: 属于数据区域(data)。存放的是PHY初始化数据
- Core dump:core dump分区用于查找系统崩溃时的软件错误,系统崩溃的时候会将调试信息写入到Flash中保存以便开发者对崩溃原因进行分析。
- SPIFFS: 属于数据区域(data)。是一种文件系统。
- Fatfs: 属于数据区域(data)。是一种文件系统。
- user data: 属于数据区域(data)。是未被使用的区域,可以通过直接读写内存地址的方式进行访问和使用
1.3 esp32启动过程
提到了flash区域,顺便说一下esp32的启动过程
ESP32启动大概分为三个步骤:
- ESP32内部ROM的引导程序启动,把spi flash是0x1000的bootloader程序加载到RAM中;
- bootloader启动,读取分区表和主应用程序映像
- 主程序运行,启动第二个CPU和RTOS程序。
2. 分区表
2.1 分区表的组成
前文已经提到,分区表主要的作用是用来划分剩余flash空间的功能和大小的。
分区表在0x8000的位置被烧写,最大长度为0xC00字节,最多能把flash分为95段。分区表数据后还保存着该表的 MD5 校验和,用于验证分区表的完整性。此外,如果芯片使能了安全启动功能,则该分区表后还会保存签名信息。
在esp32中,分区表是以bin类型的二进制文件进行烧写的。如果想读取这个分区表,可以通过一些方法把bin转换为csv进行阅读,具体方法后文会讲。
2.2 分区表的定义
分区表含有六个字段。包括Name,Type,SubType、Offset、Size、Flags,如默认的分区表定义如下:
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
2.2.1 Name字段
Name 字段可以是任何有意义的名称,但不能超过16个字符(之后的内容将被截断)。该字段对 ESP32 并不是特别重要。
2.2.2 Type字段
Type 字段可以指定为 app (0x00)(代码类型) 或者 data (0x01)(数据类型),也可以直接使用数字0-254(或者十六进制 0x00-0xFE)。注意,0x00-0x3F 不得使用(预留给 esp-idf 的核心功能)。
如果应用程序需要以ESP-IDF尚未支持的格式存储数据,请在0x40-0xFE内添加一个自定义分区类型。
2.2.3 SubType字段
SubType 字段长度为 8 bit,内容与具体分区 Type 有关。目前,esp-idf 仅仅规定了 “app” 和 “data” 两种分区类型的子类型含义。
Name | Type | SubType |
any value | app | factory ota_0-15 |
any value | data | ota data phy nvs spiffs |
当Type定义为app的时候,SubType可以选择factory(0x00)、0ta_0(0x10)…ota_15(0x1F)或test(0x20):
- factory:是默认的 app 分区。启动加载器将默认加载该应用程序。但如果存在类型为 data/ota 分区,则启动加载器将加载 data/ota 分区中的数据,进而判断启动哪个 OTA 镜像文件。OTA 升级永远都不会更新 factory 分区中的内容.如果您希望在 OTA 项目中预留更多 flash,可以删除 factory 分区,转而使用 ota_0 分区。
- ota_0 (0x10) … ota_15(0x1F)=为 OTA 应用程序分区,启动加载器将根据 OTA 数据分区中的数据来决定加载哪个 OTA 应用程序分区中的程序。在使用 OTA 功能时,应用程序应至少拥有 2 个 OTA 应用程序分区(ota_0 和 ota_1)
- test (0x20) 为预留的子类型,用于工厂测试流程。如果没有其他有效 app 分区,test 将作为备选启动分区使用。也可以配置启动加载器在每次启动时读取 GPIO,如果 GPIO 被拉低则启动该分区。
当Type定义为data的时候,SubType可以选择ota(0x00),phy(0x01),nvs(0x02),nvs_keys(0x04)等
- ota: 即 OTA 数据分区 ,用于存储当前所选的 OTA 应用程序的信息。这个分区的大小需要设定为 0x2000。
- phy:存放PHY初始化数据。默认PHY分区不启用,而是把PHY初始化数据编译到应用程序中。如果要从此分区加载PHY初始化数据,请打开项目配置菜单(idf.py menuconfig),并且使能CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION 选项。此时,您还需要手动将 phy 初始化数据烧至设备flash (esp-idf 编译系统并不会自动完成该操作)。
- nvs :是专门给 非易失性存储 (NVS) API 使用的分区。用于存储phy校准数据、wifi数据和自定义数据。NVS分区至少0x3000字节,如果要存储大量数据,建议增加。默认是0x6000字节
- nvs_key: NVS秘钥分区。用于存储加密秘钥。此分区至少4096字节
- 文件系统:可以存放fat、spiffs等文件系统
2.2.4 offset和size
偏移地址是功能分区的起始地址。这个地址要求与0x10000(64k)对齐。
如果偏移字段留空,gen_esp32part.py 工具会自动计算得到一个满足对齐要求的偏移地址。
如果 app 分区的偏移地址没有与 0x10000 (64K) 对齐,则该工具会报错。
app 分区的大小和偏移地址可以采用十进制数、以 0x 为前缀的十六进制数,且支持 K 或 M 的倍数单位(分别代表 1024 和 1024*1024 字节)
2.2.5 flags
当前仅支持 encrypted 标记。如果 Flags 字段设置为 encrypted,且已启用 Flash 加密 功能,则该分区将会被加密。
2.3 系统分区表的查看
分区表以二进制文件bin类型的方式进行存储,如果我们想要查看,就要把bin文件转换为csv文件。转换方法如下:
- 打开esp-idf\components\partition_table 路径,找到gen_esp32part.py
- 用命令行输入code. 的方法用vscode打开某个项目,输入命令,即可把当前项目中的分区表变成csv查看。注意,python脚本路径,输入文件和输出文件路径需要自己定义修改,这里只是个例子
python C:\Software\Esp\espidf\components\partition_table\gen_esp32part.py build\partition_table\partition-table.bin C:\Users\30311\Desktop\partition-table.csv
2.4 分区表的更换
- 输入指令
idf.py menuuconfig
- 在menuconfig中找到partition table,在此选项中即可进行分区表的更换
2.4.1 使用内置分区表
前两个选择是内置分区表
Single factory app, no OTA
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
Factory app, two OTA definitions
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x4000,
otadata, data, ota, 0xd000, 0x2000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
ota_0, app, ota_0, 0x110000, 1M,
ota_1, app, ota_1, 0x210000, 1M,
2.4.2 使用自定义的分区表
把自定义的分区表放在项目路径下,在这里吧名字输入进去即可。idf会自动把csv转换为bin文件
3. 参考资料
[1] ESP32分区表图解
[2] 玩转ESP32(3):partitiontable使用