基于Linux下的Nand flash驱动开发(一)

1.Nand Flash背景描述

1.1.背景描述

Nand-flash存储器是flash存储器的一种,其内部采用非线性宏单元模式,为固态大容量内存的实现提供了廉价有效的解决方案。Nand-flash存储器具有容量较大,改写速度快等优点,适用于大量数据的存储,因而在业界得到了越来越广泛的应用,如嵌入式产品中包括数码相机、MP3随身听记忆卡、体积小巧的U盘等。

2.Nand Flash相关分析

2.1.相关分析

NOR和NAND是市场上两种主要的非易失闪存技术。Intel于1988年首先开发出NOR flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面。紧接着,1989年,东芝公司发表了NAND flash结构,强调降低每比特的成本,更高的性能,并且像磁盘一样可以通过接口轻松升级。但是经过了十多年之后,仍然有相当多的硬件工程师分不清NOR和NAND闪存。
“NAND存储器”经常可以与“NOR存储器”相互换使用。许多业内人士也搞不清楚NAND闪存技术相对于NOR技术的优越之处,因为大多数情况下闪存只是用来存储少量的代码并且需要多次擦写,这时NOR闪存更适合一些。而NAND则是高数据存储密度的理想解决方案。
NOR的特点是芯片内执行(XIP, eXecute In Place),这样应用程序可以直接在flash 闪存内运行,不必再把代码读到系统RAM中。NOR的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除 速度大大影响了它的性能。
NAND结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也很快。应用NAND的困难在于flash的管理需要特殊的系统接口。

3.Nand Flash性能比较

3.1.性能比较

1).NAND器件flash闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编程。任何flash器件的写入操作只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。NAND器件执行擦除 操作是十分简单的,而NOR则要求在进行擦除前 先要将目标块内所有的位都写为0。
2).由于擦除NOR器件时是以64~128KB的块进行的,执行一个写入/擦除操作的时间为5s ,与此相反,擦除是以8~32KB的块进 行的,执行相同的操作最多只需要4ms。
3).执行擦除时块尺寸的不同进一步拉大了NOR和NAND之间的性能差距,统计表明,对于给定的一套写入操作(尤其是更新小文件时), 更多的擦除操作必须在基于NOR的单元中进行。这样,当选择存储解决方案时,设计师必 须权衡以下的各项因素。
● NOR的读速度比NAND稍快一些。
● NAND的写入速度比NOR快很多。
● NAND的擦除速度远比NOR快。
● NAND的擦除单元更小,相应的擦除电路更加简单。
● NAND的实际应用方式要比NOR复杂的多。
● NOR可以直接使用,并在上面直接运行代码,而NAND需要I/O接口,因此使用时需要驱动。

3.2.接口差别

1).NOR flash带有SRAM接口,有足够的地址引脚来寻址,可以很容易地存取其内部的每 一个字节。
2).NAND器件使用复杂的I/O口来串行地存取数据,各个产品或厂商的方法可能各不相同 。8个引脚用来传送控制、地址和数据信息。
3).NAND读和写操作采用512字节的块,这一点有点像硬盘管理此类操作,很自然地,基于NAND的存储器就可以取代硬盘或其他块设备。NOR的特点是芯片内执行(XIP, eXecute In Place),这样应用程序可以直接在flash闪存内运行,不必再把代码读到系统RAM中。
4).NOR的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大影响了它的性能。
5).NAND结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也很快。应用NAND的困难在于flash的管理需要特殊的系统接口。

4.Nand Flash硬件描述

4.1.硬件描述

当前以GD5F1GQ4XFXXG为例子,具体硬件描述如下。
在这里插入图片描述

Pin管脚描述:
在这里插入图片描述

5.Nand Flash物理结构

5.1.物理结构分析

在这里插入图片描述

这里解释一下,一个设备等于1Gbit,且等于128Mbyte,每个设备有1024个块,每个块有64Kbyte大小,每个块有64个页(page),每个页(page)有2K+64byte或2K+128byte。注释:这里的页有2K+64byte或2K+128byte是指是否开了ECC。如果开了就是2K+64byte,否则就是2K+128byte。
在这里插入图片描述

注意:
1.当内部ECC启用时,用户可以编程整个128字节空闲区域的前64字节,但是最后64个字节的整个空闲区域不能编程,其中用户可以读取整个128字节的空闲区域。
2.当内部ECC关闭时,用户可以读取和编程整个128字节的空闲区域。

6.Nand Flash内存映射

6.1内存映射逻辑

在这里插入图片描述

注意:

  1. CA:列地址。12位地址能够从0到4095字节寻址;但是,只有字节0通过2175是有效的。每个页面的2176到4095字节是“出界”,设备中不存在,而且无法解决。
  2. RA:行地址。RA<5:0>选择一个区块内的页面,RA<16:6>选择一个区块

7.Nand Flash命令字

7.1.命令字描述

在这里插入图片描述

注意:
这里描述了对应的寄存器操作命令和字节数。

8.Nand Flash命令字操作

8.1.写操作

8.1.1.写使能(06H)

Write Enable (WREN)命令用于设置Write Enable Latch (WEL)位。写使能锁存(WEL)位
必须在以下修改内存数组内容的操作之前设置:
•页面程序
•OTP程序/OTP保护
•块擦除
使用复位命令可以清除WEL位

在这里插入图片描述

注释:写使能,发送06H命令字,大小为1byte(字节)的命令字。

8.1.2.写失能(04H)

Write Disable命令用于重置Write Enable Latch (WEL)位。WEL位也通过以下方式复位
条件:
•页面程序
•OTP程序/OTP保护
•块擦除
在这里插入图片描述

注释:写失能,发送04H命令字,大小为1byte(字节)的命令字。

8.2.功能操作

GET FEATURES (0FH)和SET FEATURES (1FH)命令用于监控设备状态和更改设备的行为。这些命令使用一个1字节的特性地址来确定要读取或修改哪个特性。OTP和块锁定等特性可以通过设置特定的特性位来启用或禁用(如下表所示)。状态寄存器大部分是读的,除了WEL,它是WRITE ENABLE (06H)命令的可写位。当一个特性被设置后,它将一直处于活动状态,直到设备的电源循环或该特性被写入。除非另有一旦设备被设置,即使发出RESET (FFH)命令,它仍然保持设置状态。
在这里插入图片描述

8.2.1.Get Features (0FH)

在这里插入图片描述

8.2.2.Set Features (1FH)

在这里插入图片描述

8.3.读操作

8.3.1.读页

PAGE READ (13H)命令将数据从NAND闪存阵列转移到缓存寄存器。命令
顺序如下:
•13H (PAGE READ to cache)
•0FH (GET FEATURES命令读取状态)
•03H或0BH (Read from cache)/3BH (Read from cache x2)/6BH (Read from cache x4)/BBH (Read from cache dual/EBH (Read from cache quad IO)
PAGE READ命令需要一个24位的地址。块/页地址注册后,设备启动从主阵列转移到缓存寄存器,并且在tRD时间忙碌。在此期间,GET特性(0FH)可以发出命令来监视状态。接下来的页面读取操作,是随机数据读取(03H/0BH/3BH/6BH/BBH/EBH)命令从缓存中读取数据。输出数据开始在命令中指定的初始地址处,一旦到达2176字节段的结束边界,输出将自动包围开始边界,直到cs#被拉高以终止此操作。请参考波形来查看整个READ操作。

8.3.2.Page Read to Cache(13H)

在这里插入图片描述

8.3.3.Read From Cache (03H or 0BH)

在这里插入图片描述

8.3.4.Read From Cache x4 (6BH)

特性(B0[0])的Quad Enable bit (QE)必须设置为启用read from cache x4
在这里插入图片描述

8.3.5.Read From Cache Dual IO (BBH)

从Cache中读取双I/O命令(BBH)类似于从Cache中读取x2命令(3BH),但是使用
能够输入4个虚拟位,然后是一个12位的列地址作为起始字节地址和一个虚拟字节
通过SIO0和SIO1,每个位在SCLK上升边缘被锁存,然后缓存内容被移出2位
每个时钟周期从SIO0和SIO1。第一个地址字节可以在任何位置。地址自动增加
在每个字节的数据移出直到边界换行位之后,移到下一个更高的地址。
在这里插入图片描述

8.3.6.Read From Cache Quad IO (EBH)

Read from Cache Quad IO命令类似于Read from Cache x4命令,但具有输入功能4个虚拟位,后面跟着一个12位的列地址作为起始字节地址,一个虚拟字节由SIO0, SIO1, SIO3,SIO4,每个位在SCLK上升边缘期间被锁存,然后缓存内容每个时钟被移出4位从SIO0, SIO1, SIO2, SIO3循环。寻址的第一个字节可以位于任何位置。地址是自动的在每个字节的数据移出后,递增到下一个更高的地址,直到边界封装位。这里使必须设置特性(B0[0])的bit (QE)来启用read from cache quad IO命令。

在这里插入图片描述

8.3.7.Read ID (9FH)

READ ID命令用于识别NAND Flash设备。
•地址为00H~01H时,READ ID命令输出制造商ID和设备ID。

在这里插入图片描述

设备ID列表:

在这里插入图片描述

8.4.编程操作

8.4.1.页编程

页程序的操作序列程序1字节到2176字节的数据在一页。页面程序顺序如下:
•02H (PROGRAM LOAD)/32H (PROGRAM LOAD x4)
•06h (write enable)
•10h(程序执行)
•0FH (GET FEATURE命令读取状态)
首先,发出一个PROGRAM LOAD (02H/32H)命令。PROGRAM LOAD包含一个8位的操作代码,然后是4虚拟位和一个12位的列地址,然后要编程的数据字节。数据字节被加载到缓存中
长度为2176字节的寄存器。如果加载了超过2176个字节,那么这些额外的字节将被缓存忽略登记。当cs#从LOW到HIGH时,命令序列结束。图10-1显示了PROGRAM LOAD
操作。其次,在执行PROGRAM EXECUTE操作之前,必须有一个WRITE ENABLE (06H)命令
被发布。与任何改变内存内容的命令一样,必须执行WRITE ENABLE以便
设置WEL钻头。如果不发出此命令,则忽略程序序列的其余部分。

注意:

  1. 当程序加载(02h),程序随机加载(84h)时,缓存寄存器的内容不重置命令和RESET (FFh)命令。

  2. 当程序执行(10h)命令在程序加载(02h)命令之后发出时,SPI-NAND控制器Program Load (02h)命令没有加载数据的地址将0xFF数据输出到NAND。

  3. 当程序加载随机数据(84h)命令之后刚刚发出程序执行(10h)命令时,SPI-NAND控制器输出缓存寄存器的内容到NAND。

  4. 寻址应该在块中按顺序进行。

8.4.2.Program Load (PL) (02H)

在这里插入图片描述

注意:当内部ECC关闭数据字节是2176,当内部ECC启用数据字节是2112。

8.4.3.Program Load x4 (PL x4) (32H)

程序加载x4命令(32H)类似于程序加载命令(02H),但具有输入数据字节4引脚:SIO0, SIO1, SIO2和SIO3。命令序列如下所示。Quad使能位(QE)必须设置的功能(B0[0])启用程序加载x4命令。
在这里插入图片描述

注意:当内部ECC关闭数据字节是2176,当内部ECC启用数据字节是2112。

8.4.5.Program Execute (PE) (10H)

加载数据后,必须发出一个PROGRAM EXECUTE (10H)命令来启动从缓存寄存器到主数组。程序EXECUTE由一个8位的操作代码和一个24位的地址组成。后页面/块地址被注册,存储设备开始从缓存寄存器到主阵列的传输,然后正在为tPROG时间忙碌。如图所示。在这段繁忙时间内,状态寄存器可以轮询到监视操作的状态(请参阅状态寄存器)。当操作成功完成后,下一个系列的数据可以用PROGRAM LOAD命令加载。

在这里插入图片描述

8.4.6.Program Load Random Data (84H)

这个命令由一个8位的Op代码、4个虚拟位和一个12位的列地址组成。加载新数据由12位提供的列地址。如果随机数据不是顺序的,则另一个PROGRAM LOAD随机数据(84H)命令必须使用新的列地址,如图所示。这个命令是仅在内部数据移动序列中可用。
在这里插入图片描述

注意:当内部ECC关闭数据字节是2176,当内部ECC启用数据字节是2112。

8.4.7.Program Load Random Data x4 (C4H/34H)

程序加载随机数据x4命令(C4H/34H)类似于程序加载随机数据命令(84H)但是可以通过四个引脚输入数据字节:SIO0、SIO1、SIO2和SIO3。命令序列如下所示在下面。程序加载随机数据x4命令必须设置特性(B0[0])的Quad使能位(QE)为使能。如图所示。这两个命令只在内部数据移动序列中可用。
在这里插入图片描述

注意:当内部ECC关闭数据字节是2176,当内部ECC启用数据字节是2112。

8.4.8.Program Load Random Data Quad IO (72H)

程序加载随机数据四次IO命令(72H)类似于程序加载随机数据x4命令(C4H),但有能力输入4个虚拟位,12位列地址由四个引脚:SIO0, SIO1, SIO2,和SIO3。命令序列如下所示。特性(B0[0])的Quad使能位(QE)必须设置为使能程序加载随机数据x4命令。有关详细信息,请参见图。此命令仅在内部数据时可用移动序列。
在这里插入图片描述

注意:当内部ECC关闭数据字节是2176,当内部ECC启用数据字节是2112。

8.5.擦除操作

8.5.1.Block Erase (D8H)

在这里插入图片描述

BLOCK ERASE (D8H)命令用于块级擦除。每个区块组织为64页,每页2176字节(2048 + 128字节)。每个块是136kbytes。块擦除命令(D8H)操作一次一个区块。BLOCK ERASE操作的命令顺序如下:
•06H (WRITE ENBALE命令)
•D8H (BLOCK ERASE command)
•0FH (GET FEATURES命令读取状态寄存器)
在执行BLOCK ERASE操作之前,必须发出WRITE ENABLE (06H)命令。与任何命令更改内存内容时,必须执行WRITE ENABLE命令以设置WEL一些。如果不发出WRITE ENABLE命令,则忽略erase序列的其余部分。写启用命令之后必须有一个块擦除(D8H)命令。该命令需要24位的地址。行后地址注册,控制逻辑自动控制定时和擦除校验操作。设备忙在块擦除操作期间的时间。GET FEATURES (0FH)命令可以用来监控状态操作。当块擦除操作正在进行时,用户可以发出普通的读取缓存命令(03H/0BH/3BH/6BH/BBH/EBH)读取缓存中的数据。

8.6.复位操作

8.6.1.Soft Reset (FFH)

在这里插入图片描述

RESET (FFH)命令停止所有操作。例如,在一个程序或擦除或读取操作中,复位命令用来使设备进入等待状态。在缓存程序或读取缓存期间,复位也可以停止先前的操作和挂起的操作。reset命令发送后300ns可以读取状态。

9.Nand Flash块保护功能

9.1.块的加锁与解锁

块锁特性提供了保护整个设备或块范围免受程序和擦除操作。设备上电后处于“锁定”状态,即特征位BP0、bp1、BP2分别为1、INV、INV、INV、INV。CMP和BRWD设置为0。要解锁所有的块或一组块,必须发出SET FEATURES命令改变保护特征位的状态。当BRWD设置和WP#设置为LOW时,没有可写保护特性可以设置位。同样,当向锁定块发出PROGRAM/ERASE命令时,状态位OIP保持为0。当一个对锁定块发出ERASE命令,返回ERASE失败04H。当一个PROGRAM命令被发出时对于锁定的块,返回程序失败08h。
在这里插入图片描述

当WP#不是LOW时,用户可以根据需要发出波纹命令来改变保护状态。
•Issue SET FEATURES寄存器写入(1FH)
•发出特征位地址(A0h)和特征位组合作为表

10.Nand Flash操作时间

10.1.操作时间描述

在这里插入图片描述

暂时介绍Nand Flash到这里,后续会更新!!!

后续更新:基于Linux下的Nand flash驱动开发(二)

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的SPI NAND Flash驱动代码的示例,基于Linux内核的MTD框架: ``` #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/spi/spi.h> #define SPI_NAND_CMD_READ 0x03 #define SPI_NAND_CMD_READID 0x9F #define SPI_NAND_CMD_RESET 0xFF #define SPI_NAND_PAGE_SIZE 2048 #define SPI_NAND_BLOCK_SIZE (64 * 1024) #define SPI_NAND_CHIP_SIZE (1024 * 1024 * 8) struct spi_nand_chip { struct mtd_info mtd; struct spi_device *spi; u8 *buf; }; static int spi_nand_read_buf(struct spi_nand_chip *chip, u32 addr, u8 *buf, u32 len) { u8 cmd[4]; int ret; cmd[0] = SPI_NAND_CMD_READ; cmd[1] = addr >> 16; cmd[2] = addr >> 8; cmd[3] = addr; ret = spi_write_then_read(chip->spi, cmd, sizeof(cmd), buf, len); if (ret < 0) { dev_err(&chip->spi->dev, "SPI NAND read error: %d\n", ret); return ret; } return 0; } static int spi_nand_read_id(struct spi_nand_chip *chip) { u8 cmd = SPI_NAND_CMD_READID; u8 id[5]; int ret; ret = spi_write_then_read(chip->spi, &cmd, sizeof(cmd), id, sizeof(id)); if (ret < 0) { dev_err(&chip->spi->dev, "SPI NAND read ID error: %d\n", ret); return ret; } dev_info(&chip->spi->dev, "SPI NAND ID: %02x %02x %02x %02x %02x\n", id[0], id[1], id[2], id[3], id[4]); return 0; } static int spi_nand_probe(struct spi_device *spi) { struct spi_nand_chip *chip; struct mtd_info *mtd; int ret; chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; chip->buf = devm_kmalloc(&spi->dev, SPI_NAND_PAGE_SIZE, GFP_KERNEL); if (!chip->buf) return -ENOMEM; mtd = &chip->mtd; mtd->name = "spi-nand"; mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; mtd->writesize = SPI_NAND_PAGE_SIZE; mtd->erasesize = SPI_NAND_BLOCK_SIZE; mtd->size = SPI_NAND_CHIP_SIZE; mtd->_erase = nand_erase; mtd->_read = nand_read; ret = spi_setup(spi); if (ret) return ret; chip->spi = spi; ret = spi_nand_read_id(chip); if (ret) return ret; return mtd_device_register(mtd, NULL, 0); } static int spi_nand_remove(struct spi_device *spi) { struct mtd_info *mtd = spi_get_drvdata(spi); mtd_device_unregister(m

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值