添加对新的闪存设备的支持
本节描述如何使用libflash或libquadflash来支持新的闪存设备。libflash是一个实现对SPI闪存设备支持的库,而libquadflash则使用类似的API实现了对Quad SPI设备的支持。
要支持新的闪存设备,需要编写一个配置文件,描述设备的特性,例如页面大小、页面数量以及读取、写入和擦除数据的命令。这些信息可以在闪存设备的数据手册中找到。市场上的许多设备都可以使用这些配置参数进行描述;那些无法描述的设备则不受支持。
生成的配置文件可用于在XFLASH中支持不受支持的闪存设备,也可以用于直接使用libflash或libquadflash编写目标软件。
下面显示了Numonyx M25P10-A的配置文件。该设备被描述为C结构的初始化器,其值在以下各节中进行了描述。
10, /* 1. libflash device ID */
256, /* 2. 页面大小 */
512, /* 3. 页面数量 */
3, /* 4. 地址大小 */
4, /* 5. 时钟分频器 */
0x9f, /* 6. RDID 命令 */
0, /* 7. RDID 虚拟字节数 */
3, /* 8. RDID 数据大小(以字节为单位) */
0x202011, /* 9. RDID 制造商 ID */
0xD8, /* 10. SE 命令 */
0, /* 11. SE 完全擦除扇区 */
0x06, /* 12. WREN 命令 */
0x04, /* 13. WRDI 命令 */
PROT_TYPE_SR, /* 14. 保护类型 */
{{0x0c,0x0},{0,0}}, /* 15. SR 保护和解除保护命令 */
0x02, /* 16. PP 命令 */
0x0b, /* 17. READ 命令 */
1, /* 18. READ 虚拟字节数 */
SECTOR_LAYOUT_REGULAR, /* 19. 扇区布局 */
{32768,{0,{0}}}, /* 20. 扇区大小 */
0x05, /* 21. RDSR 命令 */
0x01, /* 22. WRSR 命令 */
0x01, /* 23. WIP 位掩码 */
0x000000, /* 24. 忽略的制造商 ID 位掩码 */
0, /* 25. libquadflash: QE 位位置,libflash: 保留 */
该配置结构实现了一种参数继承的形式,允许最多三个信息源。按优先顺序,设备配置文件可以覆盖通过SFDP查询获得的任何值(对于支持此功能的设备),这些值可以覆盖默认配置文件。
设备配置文件是用于与闪存设备建立连接的最权威的参数集。根据读取设备ID中的描述,会对配置进行设备ID检查,以匹配正确的文件和所连接的闪存设备。
SFDP查询是第二个最权威的信息来源。任何设置为-1的参数值将从SFDP响应中根据SFDP部分进行填充(如果可用)。
参数的最后一个来源是默认配置文件。它包含一组回退参数,当无法匹配特定设备配置时使用,或者当设备文件从默认文件按值继承,并且该参数未由SFDP填充时使用。
通过将libflash设备ID设置为-1,配置文件描述了默认的参数集。
通过将其余参数设置为-1,该值将从SFDP或默认配置文件中继承。
默认配置不应将剩余参数的值设置为-1,因为它没有任何可以继承的值。默认配置描述了当SFDP或设备配置中缺少信息时使用的回退参数。
目前可以从SFDP填充的值可以在SFDP部分找到。
Libflash设备ID
10, /* 1. libflash设备ID */
此值由libflash在调用函数fl_getFlashType时返回,以便应用程序可以识别连接的闪存设备。
如果此值设置为-1,则配置文件描述了默认的参数集。
页面大小和页面数量
256, /* 2. 页面大小 */
512, /* 3. 页面数量 */
这些值指定每个页面的字节数以及所有可用扇区中的总页面数。在M25P10-A数据手册中,可以从第1节的以下段落中找到这些值:
存储器被组织成4个扇区,每个扇区包含128个页面。每个页面宽度为256字节。因此,整个存储器可以看作是由512个页面或131,072字节组成。
地址大小
3, /* 4. 地址大小 */
该值指定用于表示地址的字节数。下表重现了提供此信息的M25P10-A数据手册的部分内容。在该表中,所有需要地址的指令都占用三个字节。
指令 | 描述 | 单字节指令 | 地址 | 虚拟 | 数据 | |
|---|---|---|---|---|---|---|
代码 | 字节 | 字节 | 字节 | |||
WREN | 写使能 | 0000 0110 | 06h | 0 | 0 | 0 |
WRDI | 写禁止 | 0000 0100 | 04h | 0 | 0 | 0 |
RDID | 读取标识 | 1001 1111 | 9Fh | 0 | 0 | 1 到 3 |
RDSR | 读取状态寄存器 | 0000 0101 | 05h | 0 | 0 | 1 到无穷大 |
WRSR | 写状态寄存器 | 0000 0001 | 01h | 0 | 0 | 1 |
READ | 读取数据字节 | 0000 0011 | 03h | 3 | 0 | 1 到无穷大 |
FAST_READ | 以更高速度读取数据字节 | 0000 1011 | 0Bh | 3 | 1 | 1 到无穷大 |
PP | 页编程 | 0000 0010 | 02h | 3 | 0 | 1 到 256 |
SE | 扇区擦除 | 1101 1000 | D8h | 3 | 0 | 0 |
BE | 整体擦除 | 1100 0111 | C7h | 0 | 0 | 0 |
DP | 深度掉电 | 1011 1001 | B9h | 0 | 0 | 0 |
RES | 解除深度掉电,并读取电子签名 | 1010 1011 | ABh | 0 | 3 | 1 到无穷大 |
解除深度掉电 | 0 | 0 | 0 | |||
时钟频率
4, /* 5. 时钟分频器 */
此值用于确定与SPI设备进行接口的时钟速率。对于值n,使用的SPI时钟速率为100/2*n MHz。libflash支持最大12.5MHz。
下表重现了提供此信息的M25P10-A数据手册的部分内容。交流特性表显示,配置文件中使用的所有指令(如本文档所述)都可以以高达25MHz的速度运行。这比libflash支持的速度更快,因此将分频系数设为4以生成12.5MHz的时钟。
| 符号 | 备选 | 参数 | 最小值 | 典型值 | 最大值 | 单位 |
|---|---|---|---|---|---|---|
| fC | fC | 以下指令的时钟频率:FAST_READ、PP、SE、BE、DP、RES、WREN、WRDI、RDSR、WRSR | 无关紧要 | 25 | MHz | |
| fCLH | 读取指令的时钟频率 | 无关紧要 | 20 | MHz | ||
| tCH | tCLH | 时钟高电平时间 | 18 | ns | ||
| tCL | tCLL | 时钟低电平时间 | 18 | ns |
通常情况下,如果SPI设备支持libflash使用的不同命令的不同时钟速率,则必须指定最低值。
读取设备ID
0x9f, /* 6. RDID 命令 */
0, /* 7. RDID 虚拟字节数 */
3, /* 8. RDID 数据大小(以字节为单位) */
0x202011, /* 9. RDID 制造商ID */
..
0x000000 /* 24. RDID 制造商ID位掩码 */
大多数闪存设备都有一个硬件标识符,可用于识别设备。当应用程序支持 一个或多个闪存设备时,libflash使用此标识符来确定连接的设备类型。读取设备ID的顺序通常是发出RDID(读取ID)命令,等待零个或多个虚拟字节,然后读取一个或多个字节的数据。
M25P10-A数据手册的表4复制了提供此信息的M25P10-A数据手册的部分内容。RDID指令的行显示命令值为0x9f,没有虚拟字节,以及一个到三个数据字节。如M25P10-A数据手册的表5和M25P10-A数据手册的图9所示,读取的数据量取决于是否仅需要制造商ID(第一个字节),还是同时需要制造商ID和设备ID(第二个和第三个字节)。为了唯一标识设备,需要这三个字节,因此将制造商ID指定为三字节值0x202011。
ID位掩码允许使用单个配置来支持一系列相似的闪存设备。libflash将首先尝试使用最专业的配置(设置了最少位数)进行连接。
ID位掩码和设备ID字段是特殊的,因为它们不能设置为-1以触发继承 - 该值被视为设置为0xffffffff,在位掩码的情况下,忽略设备ID的所有位。
制造商标识 | 设备标识 | |
存储类型 | 存储容量 | |
20h | 20h | 11h |

一般来说,如果有多个RDID指令可供选择,则应优先选择符合JEDEC标准的指令。否则,应选择返回最长ID的指令。
扇区擦除
0xD8, /* 10. 扇区擦除命令 */
0, /* 11. 擦除整个扇区 */
大多数闪存设备都提供了擦除一个或部分扇区的指令。
M25P10-A 数据手册的表4重现了提供此信息的M25P10-A数据手册的部分内容。指令SE的行显示命令值为0xd8。在M25P10-A数据手册中,可以从第6.9节的第一段找到擦除的数据量:
扇区擦除(SE)指令将所选扇区内的所有位设置为“1”(FFh)。
在这个例子中,SE指令擦除了整个扇区,因此SE数据值设置为0。如果擦除的字节数小于一个完整扇区,应将该值设置为擦除的字节数。
写使能/禁止
0x06, /* 12. 写使能命令 */
0x04, /* 13. 写禁止命令 */
大多数闪存设备都提供了启用和禁用对存储器的写操作的指令。M25P10-A 数据手册的表4重现了提供此信息的M25P10-A数据手册的部分内容。指令WREN的行显示命令值为0x06,指令WRDI的行显示命令值为0x04。
存储器保护
PROT_TYPE_SR, /* 14. 保护类型 */
{{0x0c,0x0},{0,0}}, /* 15. SR保护和取消保护命令 */
某些闪存设备在启用写操作时提供额外的扇区保护功能。对于支持此功能的设备,libflash尝试通过保护闪存映像来防止应用程序意外破坏。protection类型的支持值包括:
-
PROT_TYPE_NONE设备不提供保护
-
PROT_TYPE_SR设备通过写入状态寄存器提供保护
-
PROT_TYPE_SECS设备提供保护单个扇区的指令
保护详细信息在以下形式的构造中指定:
{{a,b},{c,d}}
如果设备不提供保护,则所有值都应设置为0。如果设备提供SR保护,则a和b应设置为写入SR以保护和取消保护设备的值,c和d设置为0。否则,c和d应设置为写入保护和取消保护设备的指令的值,a和b设置为0。
如果使用SR保护,可以将a和b的第30位设置为启用读-修改-写访问状态寄存器的方法。这样可以防止清除不相关的状态位。在这种情况下,重新解释b并且必须包含要清除的位的位掩码 - 通常与a中设置的相同值。
M25P10-A 数据手册的表2和M25P10-A 数据手册的表6重现了提供此信息的M25P10-A数据手册的部分内容。第一个表显示状态寄存器的BP0和BP1应设置为1以保护所有扇区,并且都设置为0以禁用保护。第二个表显示这些位是SR的第2位和第3位。
状态寄存器内容 | 存储内容 | ||
|---|---|---|---|
BP1 bit | BP0 bit | 受保护区域 | 非受保护区域 |
0 | 0 | 无 | 所有扇区(四个扇区:0、1、2和3) |
0 | 1 | 上四分之一(扇区3) | 下四分之三(三个扇区:0至2) |
1 | 0 | 上半部分(两个扇区:2和3) | 下半部分(扇区0和1) |
1 | 1 | 所有扇区(四个扇区:0、1、2和3) | 无 |
编程命令
0x02, /* 16. 编程命令 */
设备可以按页或少量字节进行编程。如果支持页编程,则应使用它,因为它可以最小化通过SPI接口传输的数据量。
M25P10-A 数据手册的表4重现了提供此信息的M25P10-A数据手册的部分内容。在表中,提供了一个页编程指令,其值为0x02。
如果不支持页编程,则该值是三个独立值的连接。必须将位0..7设置为0。位8..15应包含编程命令。位16..23应包含每个命令的字节数。libflash库要求第一个编程命令接受三字节地址,但后续的编程命令使用自动地址增加(AAI)。
没有PP命令的设备示例是ESMT F25L004A。F25L004A 数据手册的表7重现了提供此信息的F25L004A数据手册的部分内容。在时序图中,AAI命令的值为0xad,后跟三字节地址和两个字节的数据。
| 符号 | 参数 | 最小值 | 单位 |
|---|---|---|---|
| TPU-READ | VDD 读取操作的最小时间 | 10 | us |
| TPU-WRITE | VDD 写入操作的最小时间 | 10 | us |
规范文件中的相应条目是:
0x00|(0xad<<8)|(2<<16), /* 没有PP命令,使用AAI编程2个字节 */
读取数据
0x0b, /* 17. 读取命令 */
1, /* 18. 虚拟字节数 */
从设备读取数据的序列通常是发出一个读取命令,等待零个或多个虚拟字节,然后读取一个或多个字节的数据。
对于libquadflash,命令位0..7表示QUAD_READ命令,通常为0xeb。位8..15可以用于设置读取或FAST_READ命令,但默认为FAST_READ的0x0b。
M25P10-A 数据手册的表4重现了提供此信息的M25P10-A数据手册的部分内容。有两个可用于读取数据的命令:READ和FAST_READ。指令FAST_READ的行显示命令值为0x0b,后跟一个虚拟字节。
扇区信息
SECTOR_LAYOUT_REGULAR, /* 19. 扇区布局 */
{32768,{0,{0}}}, /* 20. 扇区大小 */
第一个值指定了所有扇区是否具有相同的大小。支持的取值有:
-
SECTOR_LAYOUT_REGULAR所有扇区具有相同的大小
-
SECTOR_LAYOUT_IRREGULAR扇区具有不同的大小
在 M25P10-A 数据手册中,可以从第5节的以下段落中找到这些信息:
存储器的组织结构如下:
- 131,072 字节(每个字节8位)
- 4 个扇区(256 K位,每个扇区32768字节)
- 512 个页(每页256字节)
扇区大小是作为一个构造的一部分进行指定的:{a, {b, {c}}}。对于规则的扇区大小,大小在a中指定。b和c的值应为0。
对于不规则的扇区大小,扇区的数量在b中指定。每个扇区中的页数的以2为底的对数在c中指定。a的值应为0。一个具有不规则扇区的设备的例子是AMIC A25L80P。A25L80P 数据手册的表2重现了提供扇区信息的数据手册的部分内容。
| 扇区 | 扇区大小(Kb) | 地址范围 | |
|---|---|---|---|
| 15 | 64 | F0000h | FFFFFh |
| 14 | 64 | E0000h | EFFFFh |
| 13 | 64 | D0000h | DFFFFh |
| 12 | 64 | C0000h | CFFFFh |
| 11 | 64 | B0000h | BFFFFh |
| 10 | 64 | A0000h | AFFFFh |
| 9 | 64 | 90000h | 9FFFFh |
| 8 | 64 | 80000h | 8FFFFh |
| 7 | 64 | 70000h | 7FFFFh |
| 6 | 64 | 60000h | 6FFFFh |
| 5 | 64 | 50000h | 5FFFFh |
| 4 | 64 | 40000h | 4FFFFh |
| 3 | 64 | 30000h | 3FFFFh |
| 2 | 64 | 20000h | 2FFFFh |
| 1 | 64 | 10000h | 1FFFFh |
| 0-4 | 32 | 08000h | 0FFFFh |
| 0-3 | 16 | 04000h | 07FFFh |
| 0-2 | 8 | 02000h | 03FFFh |
| 0-1 | 4 | 01000h | 01FFFh |
| 0-0 | 4 | 00000h | 00FFFh |
规范文件中对应的条目是:
SECTOR_LAYOUT_IRREGULAR,
{0,{20,{4,4,5,6,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8}}},
状态寄存器位
0x05, /* 21. RDSR 命令 */
0x01, /* 22. WRSR 命令 */
0x01, /* 23. WIP 位掩码 */
大多数闪存设备提供读取和写入状态寄存器的指令,包括一个写入中标志位掩码。
M25P10-A 数据手册的表4重现并记录了 RDSR 和 WRSR 命令的 M25P10-A 数据手册的部分内容。M25P10-A 数据手册的表6中的图示显示了 WIP 位在状态寄存器的位位置,导致了一个位掩码为 0x01。
QSPI使能位
0, /* 25. 对于libquadflash: QE位的位置, 对于libflash: 保留 */
对于四线串行接口设备,提供了一个额外的字段来编码四线串行接口使能位的位置。该字段是保留字段,在使用 libflash 进行 SPI 设备时没有效果。
该字段的位0..1描述了设置该位所使用的 方法:
| 值 | 方法 | 描述 | 读-修改-写 |
|---|---|---|---|
| 0 | 传统的 libquadflash 行为 | 如果制造商 ID 是 ISSI 或 MACRONIX,则设置寄存器 0 中的第6位;否则设置寄存器 1 中的第1位 | 否 |
| 1 | 位位置覆盖 | 使用位8..15中存储的位设置位,在位0..7中存储的寄存器中使用 WRSR 命令 | 否 |
| 2 | SFDP 要求 | 根据 JEDEC 的四线串行接口使能要求 (QER) 值,在位24..26中存储的值设置该位 | 是 |
| 3 | 无 QE 位 | 不尝试设置 QE 位 | N/A |
不建议覆盖此字段,因为默认行为会尝试使用方法2进行 SFDP 查询以获取一个值。该值可以保持为-1,以从 SFDP 查询中继承。该字段用于不支持 SFDP 查询的设备。
请注意,如果应用程序 XE 文件支持 SFDP,则 XFLASH 将使用 QE 位位置覆盖填充该字段(如果有)。这将把应用程序 XE 文件与特定的闪存设备耦合在一起,这可能是不希望的。建议删除 XN 文件中的 QE 位位置,以便支持 SFDP 的系统。
如果某个方法支持读-修改-写,则在设置 QE 位时将保留状态寄存器的其他位。
SFDP
libquadflash 实现了对 JEDEC JESD216 串行闪存可发现参数 (SFDP) 的基本级别支持。这将在运行时自动使用附加的闪存设备获取的值来填充闪存配置结构,减少了手动指定设备的某些属性的需求。
目前支持的 SFDP 参数和映射包括:
- 四线串行接口使能要求:25 (quadEnable)。
- 闪存存储密度:3 (numPages)。
- 页大小:2 (pageSize)。
要使用此功能,必须将设备配置文件中的相关字段(如果有)设置为-1,以从 SFDP 查询中继承该值。任何其他值都将覆盖查询结果。
如何选择闪存设备
在为 xCORE 设备选择闪存设备时,建议遵循以下准则:
- 如果需要访问数据分区,请选择具有细粒度擦除粒度的设备,这将最小化出厂和升级映像之间的间隙,并且还将尽量减少 libflash 写入数据时需要缓冲的数据量。
- 尽可能选择支持扇区保护的设备,以确保引导加载程序和出厂映像在部署后不会意外损坏。
- 选择适合应用程序的闪存速度等级。即使在低速下,启动时间也很短。