本篇除了对 flash 闪存进行简单介绍外,另给读者推荐一种我本人也在用的小容量闪存。

自带坏块管理的 SD NAND Flash(贴片式 TF 卡),尺寸小巧,简单易用,兼容性强,稳定可靠,标准 SDIO 接口,兼容 SPI,兼容拔插式 TF 卡/SD 卡,可替代普通 TF 卡/SD 卡,尺寸 6.2x8mm 毫米,内置平均读写算法,读取速度 23.5MB/S 写入速度 12.3MB/S,标准的 SD 2.0 协议使得用户可以直接移植标准驱动代码,省去了驱动代码编程环节。

该 SD NAND Flash 产品由“深圳市雷龙发展有限公司”提供,获取更多学习资料可移步“雷龙发展”

下面我也将以该公司下的“二代 CSNP32GCR01-AOW”为例展开介绍

一、“FLASH 闪存”是什么?

1.简介

FLASH 闪存是属于内存器件的一种,“Flash”。闪存则是一种非易失性( Non-Volatile )内存,在没有电流供应的条件下也能够长久地保持数据,其存储特性相当于硬盘,这项特性正是闪存得以成为各类便携型数字设备的存储介质的基础。

各类 DDR 、 SDRAM 或者 RDRAM 都属于挥发性内存,只要停止电流供应内存中的数据便无法保持,因此每次电脑开机都需要把数据重新载入内存。

闪存则是一种非易失性( Non-Volatile )内存,在没有电流供应的条件下也能够长久地保持数据,其存储特性相当于硬盘,这项特性正是闪存得以成为各类便携型数字设备的存储介质的基础。

2.分类

NOR 和 NAND 是市场上两种主要的非易失闪存技术。

在 1984 年,东芝公司的发明人舛冈富士雄首先提出了快速闪存存储器(此处简称闪存)的概念。与传统电脑内存不同,闪存的特点是 NVM,其记录速度也非常快。

Intel 是世界上第一个生产闪存并将其投放市场的公司。1988 年,公司推出了一款 256K bit 闪存芯片。它如同鞋盒一样大小,并被内嵌于一个录音机里。後来,Intel 发明的这类闪存被统称为 NOR 闪存。它结合 EPROM 和 EEPROM 两项技术,并拥有一个 SRAM 接口。

第二种闪存称为 NAND 闪存。它由日立公司于 1989 年研制,并被认为是 NOR 闪存的理想替代者。NAND 闪存的写周期比 NOR 闪存短 90%,它的保存与删除处理的速度也相对较快。NAND 的存储单元只有 NOR 的一半,在更小的存储空间中 NAND 获得了更好的性能。鉴于 NAND 出色的表现,它常常被应用于诸如 CompactFlash、SmartMedia、 SD、 MMC、 xD、 and PC cards、USB sticks 等存储卡上。

NAND 闪存的存储单元采用串行结构,存储单元的读写是以页和块为单位来进行(一页包含若干字节,若干页则组成储存块, NAND 的存储块大小为 8 到 32KB ),这种结构最大的优点在于容量可以做得很大,超过 512MB 容量的 NAND 产品相当普遍, NAND 闪存的成本较低,有利于大规模普及。

3.特点

性能

flash 闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编程。任何 flash 器件的写入操作只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。NAND 器件执行擦除操作是十分简单的,而 NOR 则要求在进行擦除前先要将目标块内所有的位都写为 1。

由于擦除 NOR 器件时是以 64 ~ 128KB 的块进行的,执行一个写入/擦除操作的时间为 5s,与此相反,擦除 NAND 器件是以 8 ~ 32KB 的块进行的,执行相同的操作最多只需要 4ms。

执行擦除时块尺寸的不同进一步拉大了 NOR 和 NADN 之间的性能差距,统计表明,对于给定的一套写入操作(尤其是更新小文件时),更多的擦除操作必须在基于 NOR 的单元中进行。这样,当选择存储解决方案时,设计师必须权衡以下的各项因素。

● NOR 的读速度比 NAND 稍快一些。

● NAND 的写入速度比 NOR 快很多。

● NAND 的 4ms 擦除速度远比 NOR 的 5s 快。

● 大多数写入操作需要先进行擦除操作。

● NAND 的擦除单元更小,相应的擦除电路更少。

可靠性

采用 flash 介质时一个需要重点考虑的问题是可靠性。对于需要扩展 MTBF 的系统来说,Flash 是非常合适的存储方案。可以从寿命(耐用性)、位交换和坏块处理三个方面来比较 NOR 和 NAND 的可靠性。

耐用性

在 NAND 闪存中每个块的最大擦写次数是一百万次,而 NOR 的擦写次数是十万次。NAND 存储器除了具有 10 比 1 的块擦除周期优势,典型的 NAND 块尺寸要比 NOR 器件小 8 倍,每个 NAND 存储器块在给定的时间内的删除次数要少一些。

易于使用

可以非常直接地使用基于 NOR 的闪存,可以像其他存储器那样连接,并可以在上面直接运行代码。

由于需要 I/O 接口,NAND 要复杂得多。各种 NAND 器件的存取方法因厂家而异。

在使用 NAND 器件时,必须先写入驱动程序,才能继续执行其他操作。向 NAND 器件写入信息需要相当的技巧,因为设计师绝不能向坏块写入,这就意味着在 NAND 器件上自始至终都必须进行虚拟映射。

其他作用

驱动还用于对 DiskOnChip 产品进行仿真和 NAND 闪存的管理,包括纠错、坏块处理和损耗平衡。

4.虚拟化

FLASH 闪存是一种内存技术,与 RAM 不同,在断电时它仍旧可以保留所存储的信息。尽管 FLASH 闪存在执行读写操作时并不像 RAM 那样快,但性能远远高于典型的硬盘。更为重要的是,FLASH 闪存访问数据时几乎不存在任何时间延迟。FLASH 闪存技术非常适合随机 I/O,而虚拟服务器环境中恰恰存在大量的随机 I/O。

对 FLASH 闪存主要的关注点之一是其执行写操作的方式。FLASH 闪存可以执行的写操作次数有限,这意味着 FLASH 闪存厂商需要开发复杂的控制器技术,对写入 FLASH 闪存模块的方式进行管理,确保每个 FLASH 闪存单元接收相同的写请求。

目前有三种类型的 FLASH 闪存,耐久性各不相同。单阶存储单元(SLC)FLASH 闪存在每个单元写一位数据,耐久性最好。多阶存储单元(MLC)FLASH 闪存在每个单元写多位数据,耐久性排名第二。三阶存储单元(TLC)在每个单元写三位数据,耐久性最差。每个单元写入的数据位越多意味着每个单元的容量越高,每 GB 的成本越低,同样意味着平均寿命更短。

SLC 是数据中心标准,但控制器技术的不断优化使得 MLC 被大多数用例所接受。尤其是在采用了某种方式的数据保护,比如镜像或者 RAID 或者使用了 FLASH 闪存层时。

二、SD NAND Flash

这里我以贴片式 TF 卡“CSNP32GCR01-AOW”型号为例介绍

“Flash闪存”基础 及 “SD NAND Flash”产品的测试_服务器

1.概述

CSNP32GCR01-AOW 是基于 NAND 闪存和 SD 控制器的 32Gb 密度嵌入式存储。该产品与原始 NAND 相比,它有许多优点,包括嵌入式坏块管理和更强的嵌入式 ECC。即使在异常断电的情况下,它仍然可以安全地保存数据。

2.特点

接口:标准 SD 规范 2.0 版,带有 1-I/O 和 4-I/O。

电源:Vcc=2.7V-3.6V

默认模式:可变时钟频率 0-25 MHz,最高 12.5 MB/秒接口速度(使用 4 条并行数据线)

高速模式:可变时钟频率 0-50 MHz,最高 25 MB/秒接口速度(使用 4 条并行数据线)

工作温度:-25°C 至+85°C

储存温度:-40°C 至+85°C

备用电流:<250uA

开关功能命令支持高速、电子商务和未来功能

内存字段错误的纠正

内容保护机制-符合 SDMI 标准的最高安全性。

SD NAND 的密码保护(CMD42-锁定和解锁)

使用机械开关的写保护功能

内置写保护功能(永久和临时)

特定于应用程序的命令

3.引脚分配

“Flash闪存”基础 及 “SD NAND Flash”产品的测试_存储单元_02

4.数据传输模式

“Flash闪存”基础 及 “SD NAND Flash”产品的测试_存储单元_03

5.SD NAND 寄存器

SDNAND 接口中定义了六个寄存器:OCR、CID、CSD、RCA、DSR 和 SCR。这些信息只能通过

相应的命令。OCR、CID、CSD 和 SCR 寄存器携带 SDNAND/内容特定信息,而 RCA、DSR 寄存器是存储实际配置参数的配置寄存器(这里选取俩个寄存器进行展示)。

CID register

“Flash闪存”基础 及 “SD NAND Flash”产品的测试_寄存器_04

SCR register

“Flash闪存”基础 及 “SD NAND Flash”产品的测试_运维_05

6.通电图

“Flash闪存”基础 及 “SD NAND Flash”产品的测试_服务器_06

通电时间

“Flash闪存”基础 及 “SD NAND Flash”产品的测试_服务器_07

7.参考设计

“Flash闪存”基础 及 “SD NAND Flash”产品的测试_闪存_08

“Flash闪存”基础 及 “SD NAND Flash”产品的测试_存储单元_09

Tips: RDAT 和 RCMD(10K~100 kΩ)是上拉电阻器,当 SDNAND 处于 a 状态时,保护 CMD 和 DAT 线路不受总线浮动的影响;在高阻抗模式,即使主机仅在 SD 模式下使用 SDNAND 作为 1 位模式,主机也应通过 RDAT 上拉所有 DAT0-3 线。它是建议 VCC 上有 2.2uF 电容。RCLK 参考 0~120Ω。

三、STM32 测试例程

1. 初始化

SD_Error SD_Init(void)
{
 uint32_t i = 0;
 /*!< Initialize SD_SPI */
 GPIO_Configuration();
 /*!< SD chip select high */
 SD_CS_HIGH();
 /*!< Send dummy byte 0xFF, 10 times with CS high */
 /*!< Rise CS and MOSI for 80 clocks cycles */
 for (i = 0; i <= 9; i++)
 {
  /*!< Send dummy byte 0xFF */
  SD_WriteByte(SD_DUMMY_BYTE);
 }
	//获取卡的类型,最多尝试10次
	i=0;
	do
	{
		/*------------Put SD in SPI mode--------------*/
		/*!< SD initialized and set to SPI mode properly */
		SD_GoIdleState();
		/*Get card type*/
		SD_GetCardType();
	}while(SD_Type == SD_TYPE_NOT_SD && i++ >10);
	//不支持的卡
	if(SD_Type == SD_TYPE_NOT_SD)
		return SD_RESPONSE_FAILURE;
  return SD_GetCardInfo(&SDCardInfo);
}

2.但数据块测试

void SD_SingleBlockTest(void)
{
 /*------------------- Block Read/Write --------------------------*/
 /* Fill the buffer to send */
 Fill_Buffer(Buffer_Block_Tx, BLOCK_SIZE, 0x320F);
 if (Status == SD_RESPONSE_NO_ERROR)
 {
  /* Write block of 512 bytes on address 0 */
  Status = SD_WriteBlock(Buffer_Block_Tx, 0x00, BLOCK_SIZE);
  /* Check if the Transfer is finished */
 }
 if (Status == SD_RESPONSE_NO_ERROR)
 {
  /* Read block of 512 bytes from address 0 */
  Status = SD_ReadBlock(Buffer_Block_Rx, 0x00, BLOCK_SIZE);
 }
 /* Check the correctness of written data */
 if (Status == SD_RESPONSE_NO_ERROR)
 {
  TransferStatus1 = Buffercmp(Buffer_Block_Tx, Buffer_Block_Rx, BLOCK_SIZE);
 }
 if(TransferStatus1 == PASSED)
 {
  LED2_ON;
  printf("Single block 测试成功!\n");
 }
 else
 {
		LED1_ON;
  printf("Single block 测试失败,请确保SD卡正确接入开发板,或换一张SD卡测试!\n");
 }
}

3.多数据块测试

void SD_MultiBlockTest(void)
{
 /*--------------- Multiple Block Read/Write ---------------------*/
 /* Fill the buffer to send */
 Fill_Buffer(Buffer_MultiBlock_Tx, MULTI_BUFFER_SIZE, 0x0);
 if (Status == SD_RESPONSE_NO_ERROR)
 {
  /* Write multiple block of many bytes on address 0 */
  Status = SD_WriteMultiBlocks(Buffer_MultiBlock_Tx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);
  /* Check if the Transfer is finished */
 }
 if (Status == SD_RESPONSE_NO_ERROR)
 {
  /* Read block of many bytes from address 0 */
  Status = SD_ReadMultiBlocks(Buffer_MultiBlock_Rx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);
  /* Check if the Transfer is finished */
 }
 /* Check the correctness of written data */
 if (Status == SD_RESPONSE_NO_ERROR)
 {
  TransferStatus2 = Buffercmp(Buffer_MultiBlock_Tx, Buffer_MultiBlock_Rx, MULTI_BUFFER_SIZE);
 }
 if(TransferStatus2 == PASSED)
 {
		LED2_ON;
  printf("Multi block 测试成功!");
 }
 else
 {
		LED1_ON;
  printf("Multi block 测试失败,请确保SD卡正确接入开发板,或换一张SD卡测试!");
 }
}

4.状态缓冲

TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint32_t BufferLength)
{
 while (BufferLength--)
 {
  if (*pBuffer1 != *pBuffer2)
  {
   return FAILED;
  }
  pBuffer1++;
  pBuffer2++;
 }
 return PASSED;
}
void Fill_Buffer(uint8_t *pBuffer, uint32_t BufferLength, uint32_t Offset)
{
 uint16_t index = 0;
 /* Put in global buffer same values */

 for (index = 0; index < BufferLength; index++)
 {
  pBuffer[index] = index + Offset;
 }
}