第 3 章 - Azure RTOS LevelX NAND 支持

NAND 闪存通常用于大数据存储,大数据存储是文件系统的典型特征。 NAND 内存由块组成。 每个 NAND 块中都有一系列页。 NAND 块是可擦除的,这意味着 NAND 块中的所有页会被擦除(设置为全部)。 每个 NAND 块页都有一组备用字节,Azure RTOS LevelX 将其用于簿记、错误块管理和错误检测。 NAND 块页有多种大小可供选择。 最常见的页大小为:

Page Size 备用字节
256 8
512 16
2048 64

NAND 内存与 NOR 内存的区别在于没有直接访问,也就是说,NAND 内存不能像 NOR 内存那样直接从处理器读取。 NAND 内存只能在擦除后写入有限的次数。 这也与 NOR 内存不同,只要写入请求清除设置位,NOR 内存就可以无限次写入。 最后,与每个页相关联的备用字节对于 NAND 闪存来说是唯一的。 典型的备用字节配置如下表中所示。

备用字节 字节数 配置
8 字节 0-2: ECC 字节
字节 3、4、6、7: LevelX 元数据
字节 5: 错误的块标志
16 字节 0-3、6-7: ECC 字节
字节 8-11: LevelX 元数据
字节 12-15: 未使用
字节 5: 错误的块标志
64 字节 0: 错误的块标志
字节 2-5: LevelX 元数据
字节 6-39: 未使用
字节 40-63: ECC 字节

LevelX 利用每个 NAND 页的 4 个备用字节来跟踪每个页面中存储的数据。 这 4 个字节用于实现 LevelX 专有格式的 32 位无符号整数。 32 位字段的上 4 位 (位 31 到 28 位) 用于指示存储在页面中的数据类型。 数据类型可以是用户扇区数据和元数据。 如果数据类型将其指示为用户扇区数据,则此字段的位 28-0 将存储逻辑扇区号。 如果数据类型将其指示为元数据,则此字段的位 7-0 将存储元数据页码。 备用字节的格式如下所示。

LevelX 备用字节格式

含义
31-29 数据类型。 指定页面中存储的数据的数据类型。 它可以是 LevelX 元数据或用户扇区数据。
28-0 逻辑扇区号(如果数据类型是用户扇区数据)。
7-0 如果数据类型为元数据,则元数据页码。

LevelX 将几个 NAND 块用于元数据。 元数据块用于存储逻辑块与物理块之间的映射信息,以及用于跟踪块和页面的其他表。

NAND 错误块支持

NAND 内存也比 NOR 内存更容易出现错误块。 这在很大程度上是因为 NAND 制造商可以通过允许错误块并要求软件绕过这些错误块来提高产量。 LevelX 通过简单地映射错误块来处理 NAND 错误块管理。

LevelX 还为基础 LevelX 驱动程序提供了 256 字节汉明纠错编码 (ECC) 的 API,以用于计算新的 ECC 代码或对页面的每个 256 字节部分中的页面读取执行 1 位纠错。

NAND 驱动程序要求

LevelX 需要基础的 NAND 闪存驱动程序,该驱动程序特定于基础闪存部分和硬件实现。 在初始化期间,通过 API lx_nand_flash_openlx_nand_flash_format将驱动程序指定为 LevelX。 如果定义了 LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE ,则驱动程序服务函数将具有指向 NAND 控制块的指针作为第一个参数。 驱动程序可以访问控制块中特定于驱动程序的数据的用户扩展。 LevelX 驱动程序的原型如下所示。

INT nand_driver_initialize(LX_NAND_FLASH *instance);

实例参数指定 LevelX NAND 控制块。 驱动程序初始化函数负责为关联的 LevelX 实例设置所有其他的驱动程序级服务。 以下列表显示了每个 LevelX NAND 实例所需的服务。

  • 读取页面
  • 写入页面
  • 复制页面
  • 块擦除
  • 验证擦除的块
  • 验证擦除的页
  • 获取块状态
  • 设置块状态
  • 系统错误处理程序

驱动程序初始化

这些服务是通过在驱动程序初始化函数内的 LX_NAND_FLASH 实例中设置函数指针来设置的。 驱动程序初始化函数还指定块总数、每个块的页数、每页字节数、备用数据偏移量和长度以及总备用字节长度。 每页中存储了两个备用数据:备用数据 1 和备用数据 2。 备用数据 1 用于存储如上所述的数据类型,并且必须至少为 4 个字节且受 ECC 保护。 备用数据 2 是可选的,可用于指示元数据块的开始。 在返回 LX_SUCCESS 之前,驱动程序初始化函数可能还执行其他特定于设备和/或实现的初始化任务。

驱动程序读取页

LevelX NAND 驱动程序“读取页面”服务负责读取 NAND 闪存的特定块中的一个或多个页面。 所有错误检查和纠正逻辑都由驱动程序服务负责。 如果成功,LevelX NAND 驱动程序将返回 LX_SUCCESS。 如果未成功,LevelX NAND 驱动程序将返回 LX_ERROR。 下面提供了 LevelX NAND 驱动程序“读取页”服务的原型。

INT nand_driver_read_pages(
    LX_NAND_FLASH *nand_flash,
    ULONG block,
    ULONG page,
    UCHAR* main_buffer,
    UCHAR* spare_buffer,
    ULONG pages);

其中 ,块页面 标识要读取和 main_buffer 的第一个页面, spare_buffer 指定页面内容和备用数据的放置位置。 页面指定要读取的页数。 提供了 nand_flash 参数,以便驱动程序在需要时访问 NAND 控制块。

驱动程序写入页

LevelX NAND 驱动程序“写入页”服务负责将一个或多个页面写入 NAND 闪存的指定块。 所有错误检查和 ECC 计算都由驱动程序服务负责。 如果成功,LevelX NAND 驱动程序将返回 LX_SUCCESS。 如果未成功,LevelX NAND 驱动程序将返回 LX_ERROR。 LevelX NAND 驱动程序“写入页”服务的原型如下所示。

INT nand_driver_write_pages(
    LX_NAND_FLASH *nand_flash,
    ULONG block, 
    ULONG page,
    UCHAR* main_buffer,
    UCHAR* spare_buffer,
    ULONG pages);

其中 ,块 标识要写入和 main_buffer 的第一个页面, spare_buffer 指定页面内容和备用数据的源。 指定要写入的页数。 提供了 nand_flash 参数,以便驱动程序在需要时访问 NAND 控制块。

注意

LevelX 在写入闪存页时依赖驱动程序进行低级错误检测,这通常涉及读回页并与写入缓冲区进行比较,以确保写入成功。

驱动程序复制页

LevelX NAND 驱动程序“复制页”服务负责将一个或多个页面从 NAND 闪存的一个块复制到 NAND 闪存的另一个块。 所有错误检查和 ECC 计算都由驱动程序服务负责。 如果成功,LevelX NAND 驱动程序将返回 LX_SUCCESS。 如果未成功,LevelX NAND 驱动程序将返回 LX_ERROR。 LevelX NAND 驱动程序“复制页”服务的原型如下所示。

INT nand_driver_copy_pages(
    LX_NAND_FLASH *nand_flash,
    ULONG source_block,  
    ULONG source_page,
    ULONG destination_block,
    ULONG destination_page,
    ULONG pages,
    UCHAR *data_buffer);   

其中 source_blocksource_page 标识要复制和 destination_block 的第一个页面, destination_page 指定第一个目标块和页面。 页面指定要复制的页数。 如果驱动程序需要在写入目标页之前读取源页,则提供参数 data_buffer ,以便驱动程序存储一个页面和用于复制操作的备用数据。

驱动程序块擦除

LevelX NAND 驱动程序“块擦除”服务负责擦除 NAND 闪存的指定块。 如果成功,LevelX NAND 驱动程序将返回 LX_SUCCESS。 如果未成功,LevelX NAND 驱动程序将返回 LX_ERROR。 LevelX NAND 驱动程序“块擦除”服务的原型如下所示。

INT nand_driver_block_erase(
    LX_NAND_FLASH *nand_flash,
    ULONG block,  
    ULONG erase_count);

其中块标识要清除的块。 出于诊断目的提供了参数 erase_count。 例如,当擦除计数超过特定阈值时,驱动程序可能需要警告应用程序软件的另一部分。 提供了 nand_flash 参数,以便驱动程序在需要时访问 NAND 控制块。

注意

LevelX 在删除块时依赖驱动程序进行低级错误检测,这通常涉及确保块的所有页都是一整页。

验证擦除的驱动程序块

LevelX NAND 驱动程序“验证擦除的块”服务负责验证 NAND 闪存的指定块是否被擦除。 如果已擦除,LevelX NAND 驱动程序将返回 LX_SUCCESS。 如果未擦除该块,LevelX NAND 驱动程序将返回 LX_ERROR。 LevelX NAND 驱动程序“验证块擦除”服务的原型如下所示:

INT nand_driver_block_erased_verify(
    LX_NAND_FLASH *nand_flash,
    ULONG block);

其中块指定要验证是否被擦除的块。 提供了 nand_flash 参数,以便驱动程序在需要时访问 NAND 控制块。

注意

LevelX 依赖驱动程序检查所有页面以及每页的所有字节(包括备用字节和数据字节),以确保将其擦除(包含所有字节)。

验证擦除的驱动程序页

LevelX NAND 驱动程序“验证擦除的页”服务负责验证 NAND 闪存的指定块的指定页是否被擦除。 如果已擦除,LevelX NAND 驱动程序将返回 LX_SUCCESS。 如果未擦除该页,LevelX NAND 驱动程序将返回 LX_ERROR。 LevelX NAND 驱动程序“验证页擦除”服务的原型如下所示:

INT nand_driver_page_erased_verify(
    LX_NAND_FLASH *nand_flash,
    ULONG block,  
    ULONG page);

其中块指定是哪个块,页指定要验证是否已擦除的页 。 提供了 nand_flash 参数,以便驱动程序在需要时访问 NAND 控制块。

注意

LevelX 依赖驱动程序检查指定页面的所有字节(包括备用字节和数据字节),以确保将其擦除(包含所有字节)。

获取驱动程序块状态

LevelX NAND 驱动程序“获取块状态”服务负责检索 NAND 闪存的指定块的错误块标志。 如果成功,LevelX NAND 驱动程序将返回 LX_SUCCESS。 如果未成功,LevelX NAND 驱动程序将返回 LX_ERROR。 LevelX NAND 驱动程序“获取块状态”服务的原型如下所示。

INT nand_driver_block_status_get(
    LX_NAND_FLASH *nand_flash,
    ULONG block,  
    UCHAR *bad_block_byte);

其中块指定是哪个块,bad_block_byte 指定错误块标志的目标 。 提供了 nand_flash 参数,以便驱动程序在需要时访问 NAND 控制块。

设置驱动程序块状态

LevelX NAND 驱动程序“设置块状态”服务负责设置 NAND 闪存的指定块的错误块标志。 如果成功,LevelX NAND 驱动程序将返回 LX_SUCCESS。 如果未成功,LevelX NAND 驱动程序将返回 LX_ERROR。 LevelX NAND 驱动程序“设置块状态”服务的原型如下所示:

INT nand_driver_block_status_set(
    LX_NAND_FLASH *nand_flash,
    ULONG block,
    UCHAR bad_block_byte);

其中块指定是哪个块,bad_block_byte 指定错误块标志的值 。 提供了 nand_flash 参数,以便驱动程序在需要时访问 NAND 控制块。

驱动程序系统错误

LevelX NAND 驱动程序“系统错误处理程序”服务负责设置 LevelX 检测到的处理系统错误。 此例程中的处理依赖于应用程序。 如果成功,LevelX NAND 驱动程序将返回 LX_SUCCESS。 如果未成功,LevelX NAND 驱动程序将返回 LX_ERROR。 LevelX NAND 驱动程序“系统错误”服务的原型如下所示:

INT nand_driver_system_error(
    LX_NAND_FLASH *nand_flash,
    UINT error_code,  
    ULONG block, 
    ULONG page);

其中块指定是哪个块,页指定发生 error_code 表示的错误的特定页 。 提供了 nand_flash 参数,以便驱动程序在需要时访问 NAND 控制块。

NAND 模拟驱动程序

LevelX 提供模拟的 NAND 闪存驱动程序,该驱动程序只使用 RAM 来模拟 NAND 闪存部件的操作。 默认情况下,NAND 模拟驱动程序提供 8 个 NAND 闪存块,每个块 16 页,每页 2048 字节。

模拟的 NAND 闪存驱动程序初始化函数为 lx_nand_flash_simulator_initialize,在 lx_nand_flash_simulator.c 中定义。 这个驱动程序还为编写特定的 NAND 闪存驱动程序提供了一个很好的模板。

NAND FileX 集成

如前文所述,LevelX 不依赖于 FileX 进行操作。 应用程序软件可以直接调用所有 LevelX API,以将原始数据存储/检索到 LevelX 提供的逻辑扇区。 但是,LevelX 也支持 FileX。

文件 fx_nand_flash_simulated_driver.c 包含用于 NAND 闪存模拟的示例 FileX 驱动程序。 该驱动程序有趣的一点是,它将通常由 FileX 使用的 512 字节逻辑扇区合并为使用 2048 字节页面对 LevelX 模拟器的单个逻辑扇区读/写请求。 这样可以更高效地使用 NAND 闪存。 LevelX 的 NAND 闪存 FileX 驱动程序为编写自定义 FileX 驱动程序提供了一个很好的起点。

注意

FileX NAND 闪存格式应该是小于 NAND 闪存提供的扇区的一个完整块大小。 这将有助于确保在损耗均衡处理期间获得最佳性能。 在 LevelX 损耗均衡算法中提高写入性能的其他技巧包含以下内容。

  1. 确保所有写入大小都恰好是一个或多个群集,并且在确切的群集边界上启动。
  2. 通过 API 的 FileX fx_file_allocate 类执行大文件写入操作之前,请先预分配群集
  3. 确保已启用 FileX 驱动程序以接收释放扇区信息,并通过调用 lx_nor_flash_sector_release 在驱动程序中处理对驱动程序发出的释放扇区的请求