OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 64|回复: 0

《ESP32-P4开发指南— V1.0》第七章 分区表管理与使用

[复制链接]

1212

主题

1226

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5221
金钱
5221
注册时间
2019-5-8
在线时间
1316 小时
发表于 4 天前 | 显示全部楼层 |阅读模式
第七章 分区表管理与使用

1)实验平台:正点原子DNESP32P4开发板

2)章节摘自【正点原子】ESP32-P4开发指南— V1.0

3)购买链接:https://detail.tmall.com/item.htm?id=873309579825

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/esp32/ATK-DNESP32P4.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子DNESP32S3开发板技术交流群:132780729


2.jpg

3.png

在ESP32中,分区表是定义Flash存储区域的关键组成部分。它决定了应用程序、数据存储和OTA更新等如何在芯片内部分配和管理,从而影响到整个应用的性能和功能。
本章将分为如下几个小节:
7.1 分区表概述
7.2 分区表API函数


7.1 分区表概述
在ESP32开发中,分区表(Partition Table)是一个关键的系统组件,用于定义芯片上Flash存储器的分配方式。通过分区表,可以指定Flash存储的不同区域分别用来存放应用程序、文件系统、OTA更新数据等。简单来讲,分区表用于告诉ESP32设备如何划分其内部的Flash存储区域。每个分区都有特定的用途,例如:
1)factory分区:存储应用程序固件。
2)ota分区:用于存储空中下载(OTA)更新的固件。
3)nvs分区:用于存储非易失性存的数据,常用于保存配置信息。
4)spiffs/fat分区:文件系统分区,用于存储用户数据。
5)phy_init分区:专门用于存储Wi-Fi和蓝牙物理层初始化数据的区域
6)自定义分区:用于存储用户的数据。
接下来,笔者将重点讲解分区表的格式及分区表条目结构。通过化整为零的方式,我们将逐步了解分区表的各个组成部分,深入剖析每个元素的作用和意义。

7.1.1 分区表的格式
ESP32的分区表通常使用两种格式来定义存储空间的布局:
1)csv格式:开发人员使用的格式,方便更改和配置各个分区的偏移地址和大小。它是易于阅读和修改的文本文件。
2)bin格式:用于烧录到设备的二进制文件。在编译过程中,系统会将CSV格式的分区表转换为bin格式,供烧录工具使用。
在编写程序时,开发人员可以通过修改 .csv 文件来定义各个子分区,如应用程序代码、OTA更新、SPIFFS文件系统等的存储区域。当项目编译时,CSV格式会自动转化为BIN文件,并在烧录设备时使用。下面我们来看一下本书籍提供的例程示例分区表,如下内容所示。

第七章 分区表管理与使用832.png
图7.1.1.1 书籍示例的分区表

上图中,分区的大小和偏移决定了每个分区在闪存中的位置和空间分配,以下是各个子分区的描述内容:
1,nvs分区:用于存储非易失性存储数据,通常用于保存设备的配置参数。它从地址0x9000开始,占用24KB的空间。这部分存储器为设备提供了一个可以在断电后仍然保存数据的区域。
2,phy_init分区:用于存储物理层初始化数据,主要用于Wi-Fi或蓝牙的硬件配置。该分区从地址0xF000开始,占用4KB的存储空间。
3,factory分区:是设备默认的应用程序存储区,它从地址0x10000开始,占用1MB的空间。设备上电后,会从这个分区加载并运行主要的程序代码。
4,vfs分区:用于FAT文件系统存储,适合用于文件操作或存储大容量数据。它从地址0x200000 开始,占用10MB的空间,通常用于挂载外部存储设备,如SD卡。
5,storage分区:用于SPIFFS文件系统,适合存储小型文件或嵌入式应用中的配置数据。该分区从地址0xC00000开始,占用4MB的空间。
为了帮助读者更好地理解分区表,以下将以图形化的形式进行描述,如下图所示。


第七章 分区表管理与使用1326.png
图7.1.1.2 16MB Flash划分区域示意图

从上图可知。用户可根据需求调整分区的大小和偏移位置,但笔者建议尽量不要修改启动区域和分区表烧入区域,保持默认设置。这有助于避免潜在的启动问题和系统不兼容情况,从而确保系统的稳定性和正常运行。值得注意的是:Factory /OTA等程序存储分区视为加密分区,用户不可随意修改。
综上所述,分区表是用户为系统准备的Flash区域划分目录,系统从地址0x8000读取分区表信息,以了解区域的范围、大小及各自的功能和作用。

7.1.2 分区表条目结构
分区表中的每个条目都由以下几个部分组成:
1,Name:分区的名称,用于标识该分区的具体用途。
2,Type:分区的类型,主要分为 app(应用程序) 和 data(数据)。
3,SubType:分区的子类型,用于进一步说明数据的用途,例如 nvs(非易失性存储)、phy(物理初始化数据)、fat(FAT文件系统)和 spiffs(SPIFFS文件系统)。
4,Offset:分区在闪存中的起始地址,通常以十六进制表示。
根据这些关键字段,系统能够精确定位每个分区并执行相应操作。例如,系统通过Name字段识别分区的用途;通过Type和SubType进一步明确数据的类型和处理方式;Offset则帮助系统找到分区在闪存中的起始位置和大小。这些信息使系统能够准确地进行读写、擦除等操作,从而确保分区操作的可靠性和有效性。
根据乐鑫ESP-IDF编程指南所示,分区表的长度为0xC00字节,最多可容纳95条分区表条目,也就是说每个条目占用32字节(3072 (0xC00十进制数值)÷ 95 = 32)。接下来,我们来看一下在ESP-IDF(SDK)程序中如何定义分区表结构体,以下是相关代码:
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief       ESP32 分区结构体</font>
  3. <font size="3"> */</font>
  4. <font size="3">typedef struct </font>
  5. <font size="3">{ </font>
  6. <font size="3">    esp_flash_t* flash_chip;            /* 指向所使用的 Flash 芯片的指针 */</font>
  7. <font size="3">    esp_partition_type_t type;          /* 分区的类型 */</font>
  8. <font size="3">    esp_partition_subtype_t subtype;    /* 分区的子类型 */</font>
  9. <font size="3">    uint32_t address;                   /* 分区在闪存中的起始地址 */</font>
  10. <font size="3">    uint32_t size;                      /* 分区的大小 */</font>
  11. <font size="3">    uint32_t erase_size;                /* 分区的擦除大小 */</font>
  12. <font size="3">    char label[17];               /* 分区的标签,最多可包含16个字符(末尾包含终止符)*/</font>
  13. <font size="3">    bool encrypted;                     /* 是否启用加密 */</font>
  14. <font size="3">    bool readonly;                      /* 是否为只读分区 */</font>
  15. <font size="3">} esp_partition_t;</font>
复制代码
很多人认为,通过调用sizeof(esp_partition_t)可以获取分区表条目的大小,其实并不完全正确。因为每个分区表条目由Name、Type、SubType和Offset组成,上述结构体成员变量仅部分描述了这一结构。下面笔者将基于分区表条目的组成,对esp_partition_t结构体进行一次缩减,代码如下:
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief       ESP32 分区结构体</font>
  3. <font size="3"> */</font>
  4. <font size="3">typedef struct </font>
  5. <font size="3">{ </font>
  6. <font size="3">    esp_partition_type_t type;          /* 分区的类型 */</font>
  7. <font size="3">    esp_partition_subtype_t subtype;    /* 分区的子类型 */</font>
  8. <font size="3">    uint32_t address;                   /* 分区在闪存中的起始地址 */</font>
  9. <font size="3">    char label[17]; /* 分区的标签,最多可包含16个字符(末尾包含终止符) */</font>
  10. <font size="3">} esp_partition_t;</font>
复制代码
这样我们就可以得到描述每个条目的结构体,然后使用sizeof(reduced_esp_partition_t)来获取分区表条目的大小。经过系统计算,最终得出的大小接近32字节。这确认了每个条目的存储结构符合预期。
注意:为确保分区表的完整性,系统在分区表末尾附加了MD5校验和(根据分区表内容计算,可在设备启动阶段用于验证分区表的完整性),以便在运行时进行验证。整个分区表占据一个完整的Flash扇区,大小为0x1000(4KB)。因此,紧随分区表之后的任何分区,其起始地址必须位于默认偏移地址 + 0x1000处,以避免与分区表区域重叠。这种设计确保了分区表与其他数据区域的安全隔离,并有助于系统在启动时正确加载各个分区。
若读者想关闭MD5校验和操作,则可以在Menuconfig菜单配置下失能MDK5校验和,如下图所示。

第七章 分区表管理与使用3467.png
图7.1.2.1 Menuconfig菜单下失能MDK5校验和

在上图中,取消勾选红色框中的选项即可关闭MD5校验和。

7.2 分区表API函数
esp_partition组件是ESP-IDF中用于管理ESP32及其系列芯片上Flash分区的关键组件。它提供了一组高层次的API函数,允许开发者方便地访问和操作定义在分区表中的各个分区。这些高层次的API函数为开发者提供了简洁易用的接口,以进行读取、写入、擦除分区内容等操作。这些分区表API函数可以在components/esp_partition/include/esp_partition.h路径下找到。

1,根据一个或多个参数查找第一个分区esp_partition_find_first
该函数是用于根据一个或多个参数查找第一个分区,该函数原型如下所示:
  1. <font size="3">const esp_partition_t *esp_partition_find_first(esp_partition_type_t type,</font>
  2. <font size="3">                                                esp_partition_subtype_t subtype,</font>
  3. <font size="3">                                                const char *label)</font>
复制代码
函数形参:

1.png
表7.2.1 esp_partition_find函数函数描述

返回值:
句柄:指向 esp_partition_t 结构体的指针。
NULL:未找到分区。

2,从分区中读取数据esp_partition_read
该函数是用于从分区中读取数据,该函数原型如下所示:
  1. esp_err_t esp_partition_read( const esp_partition_t* partition,
  2.                               size_t src_offset, void* dst, size_t size)
复制代码
函数形参:

2.png
表7.2.2 esp_partition_read函数函数描述

返回值:
ESP_OK:读取成功。
ESP_ERR_INVALID_ARG:超过分区大小。
ESP_ERR_INVALID_SIZE:读取会超出分区边界。

3,将数据写入分区esp_partition_write
该函数是用于将数据写入分区,该函数原型如下所示:
  1. esp_err_t esp_partition_write( const esp_partition_t* partition,
  2.                                size_t dst_offset, void* src, size_t size)
复制代码
函数形参:

3.png
表7.2.3 esp_partition_write函数函数描述

返回值:
ESP_OK:如果数据写入成功。
ESP_ERR_INVALID_ARG:如果 dst_offset 超出了分区大小。
ESP_ERR_INVALID_SIZE:如果写入范围超出了分区边界。
ESP_ERR_NOT_ALLOWED:如果分区为只读。

4,擦除分区的一部分区域esp_partition_erase_range
该函数是用于擦除分区的一部分,该函数原型如下所示:
  1. esp_err_t esp_partition_erase_range(const esp_partition_t *partition,
  2.                                     size_t offset, size_t size)
复制代码
函数形参:

4.png
表7.2.4 esp_partition_erase_range函数函数描述

返回值:
ESP_OK:如果范围擦除成功。
ESP_ERR_INVALID_ARG:如果传入的参数无效(如 iterator 或 dst 为 NULL)。
ESP_ERR_INVALID_SIZE:如果擦除范围超出了分区边界。
ESP_ERR_NOT_ALLOWED:如果分区为只读。
上述列举的函数是访问和操作分区表时常用的API函数。若需进一步了解或学习其他剩余的分区表API函数,可查阅esp_partition.h头文件。如果读者想了解这些函数的使用方法,可以查看本书提供的示例28_chinese_display下的fonts.c文件,笔者使用这些函数将GBK字库更新至storage分区,并完成了汉字显示实验。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-12-13 16:16

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表