Flash 映射
<zephyr/storage/flash_map.h> API 允许通过 flash_area 结构访问有关设备 flash 分区的信息。
每个 flash_area 描述一个 flash 分区。该 API 提供对“flash 映射”的访问,其中包含可通过全局唯一 ID 号访问的预定义 flash 区域。映射根据 DTS 文件中的 “fixed-partitions” 和 “zephyr,mapped-partition” compatible 条目创建。用户还可以在运行时为特定于应用的目的创建 flash_area 对象。
本文档在指代单个“fixed-partitions”或“zephyr,mapped-partition”实体时使用“flash 区域”一词。
flash_area 包含一个指向 device 的指针,该指针可用于直接通过 flash API 访问该区域所在的 flash 设备。每个 flash 区域由其所在的设备、相对于设备起始位置的偏移量以及设备上的大小来表征。flash_area_open() 函数使用一个额外的标识符参数在 flash 映射中查找 flash 区域。
flash_map.h API 提供用于操作 flash_area 的函数。主要示例是 flash_area_read() 和 flash_area_write()。这些函数基本上是 flash API 的封装,并增加了偏移量和大小检查,以将 flash 操作限制在预定义区域内。
大多数 <zephyr/storage/flash_map.h> API 函数都需要一个 flash_area 对象指针,用于表征它们将操作的 flash 区域。获取此类指针有两种可能的方法:
使用
flash_area_open()获取;定义一个
flash_area类型的对象,这需要提供一个有效的device对象指针,以及 flash 设备内该区域的偏移量和大小。
flash_area_open() 使用数字标识符在 flash 映射中搜索 flash_area 对象,如果找到,则返回指向表示具有给定 ID 的区域的对象的指针。flash 区域的 ID 号可以从 “fixed-partitions” 或 “zephyr,mapped-partition” DTS 节点标签使用 PARTITION_ID() 获得;这些标签从 devicetree 获取,如下所述。
与 devicetree 的关系
flash_map.h API 使用从 Devicetree API 生成的数据,特别是其 Fixed and mapped flash partitions。Zephyr 还为通过 MCUboot 引导加载程序进行的 设备固件升级 提供了一些分区约定,并定义了可供 file systems 或其他非易失性 storage 使用的分区。
以下示例 devicetree 片段对 MCUboot 和存储分区均使用固定 flash 分区。为清晰起见,省略了一些细节。
/ {
soc {
flashctrl: flash-controller@deadbeef {
flash0: flash@0 {
compatible = "soc-nv-flash";
reg = <0x0 0x100000>;
partitions {
compatible = "fixed-partitions";
#address-cells = <0x1>;
#size-cells = <0x1>;
boot_partition: partition@0 {
reg = <0x0 0x10000>;
read-only;
};
storage_partition: partition@1e000 {
reg = <0x1e000 0x2000>;
};
slot0_partition: partition@20000 {
reg = <0x20000 0x60000>;
};
slot1_partition: partition@80000 {
reg = <0x80000 0x60000>;
};
scratch_partition: partition@e0000 {
reg = <0xe0000 0x20000>;
};
};
};
};
};
};
分区偏移量应相对于该分区所属的 flash 存储器起始地址来表示。
boot_partition、slot0_partition、slot1_partition 和 scratch_partition 节点标签是为 MCUboot 定义的,但并非所有 MCUboot 配置都要求定义所有这些标签。有关更多详细信息,请参阅 MCUboot documentation。
storage_partition 节点定义为供文件系统或其他非易失性存储 API 使用。
通过将 DTS 节点标签传递给 PARTITION_ID() 可获得数字 flash 区域 ID;例如,要获得 slot0_partition 的 ID 号,用户可以调用 PARTITION_ID(slot0_partition)。
所有 PARTITION_* 宏都将 DTS 节点标签作为分区标识符。
如果某个区域在 DTS 文件中定义,用户不必使用 flash_map_open() 获取 flash_area 对象指针来获取 flash 区域大小、偏移量或设备信息。知道某个区域的 DTS 节点标签后,用户可以分别使用 PARTITION_OFFSET()、PARTITION_SIZE() 或 PARTITION_DEVICE() 直接从 DTS 节点定义中获取这些信息。例如,要获取 storage_partition 的偏移量,只需调用 PARTITION_OFFSET(storage_partition)。
以下示例展示如何使用 flash_area_open() 和 DTS 节点标签获取 flash_area 对象指针:
const struct flash_area *my_area;
int err = flash_area_open(PARTITION_ID(slot0_partition), &my_area);
if (err != 0) {
handle_the_error(err);
} else {
flash_area_read(my_area, ...);
}